2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								package forms
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import (
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-06 13:03:34 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									"encoding/json"
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									"fmt"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									"log"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									validation "github.com/go-ozzo/ozzo-validation/v4"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									"github.com/pocketbase/pocketbase/core"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									"github.com/pocketbase/pocketbase/daos"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									"github.com/pocketbase/pocketbase/models"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								// CollectionsImport is a form model to bulk import
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-06 23:15:18 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								// (create, replace and delete) collections from a user provided list.
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								type CollectionsImport struct {
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									app core.App
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									dao *daos.Dao
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									Collections   []*models.Collection `form:"collections" json:"collections"`
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									DeleteMissing bool                 `form:"deleteMissing" json:"deleteMissing"`
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-07 20:38:21 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								// NewCollectionsImport creates a new [CollectionsImport] form with
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// initialized with from the provided [core.App] instance.
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-07 20:38:21 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								//
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// If you want to submit the form as part of a transaction,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// you can change the default Dao via [SetDao()].
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-07 20:38:21 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								func NewCollectionsImport(app core.App) *CollectionsImport {
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return &CollectionsImport{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										app: app,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										dao: app.Dao(),
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-07 20:38:21 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// SetDao replaces the default form Dao instance with the provided one.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								func (form *CollectionsImport) SetDao(dao *daos.Dao) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									form.dao = dao
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-06 23:15:18 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// Validate makes the form validatable by implementing [validation.Validatable] interface.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								func (form *CollectionsImport) Validate() error {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return validation.ValidateStruct(form,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										validation.Field(&form.Collections, validation.Required),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// Submit applies the import, aka.:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// - imports the form collections (create or replace)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// - sync the collection changes with their related records table
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// - ensures the integrity of the imported structure (aka. run validations for each collection)
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// - if [form.DeleteMissing] is set, deletes all local collections that are not found in the imports list
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								//
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// All operations are wrapped in a single transaction that are
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// rollbacked on the first encountered error.
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-08 01:58:21 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								//
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// You can optionally provide a list of InterceptorFunc to further
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// modify the form behavior before persisting it.
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								func (form *CollectionsImport) Submit(interceptors ...InterceptorFunc[[]*models.Collection]) error {
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if err := form.Validate(); err != nil {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return err
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return runInterceptors(form.Collections, func(collections []*models.Collection) error {
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return form.dao.RunInTransaction(func(txDao *daos.Dao) error {
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											importErr := txDao.ImportCollections(
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												collections,
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												form.DeleteMissing,
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 22:43:27 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												form.afterSync,
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if importErr == nil {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												return nil
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											// validation failure
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if err, ok := importErr.(validation.Errors); ok {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												return err
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-06 13:03:34 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											// generic/db failure
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if form.app.IsDebug() {
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												log.Println("Internal import failure:", importErr)
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-06 13:03:34 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return validation.Errors{"collections": validation.NewError(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												"collections_import_failure",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												"Failed to import the collections configuration.",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											)}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										})
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}, interceptors...)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-06 13:03:34 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 22:43:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								func (form *CollectionsImport) afterSync(txDao *daos.Dao, mappedNew, mappedOld map[string]*models.Collection) error {
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									// refresh the actual persisted collections list
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									refreshedCollections := []*models.Collection{}
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-12 22:43:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if err := txDao.CollectionQuery().OrderBy("updated ASC").All(&refreshedCollections); err != nil {
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return err
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									// trigger the validator for each existing collection to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									// ensure that the app is not left in a broken state
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									for _, collection := range refreshedCollections {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertModel := mappedOld[collection.GetId()]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if upsertModel == nil {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											upsertModel = collection
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 19:57:09 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										upsertModel.MarkAsNotNew()
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm := NewCollectionUpsert(form.app, upsertModel)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.SetDao(txDao)
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										// load form fields with the refreshed collection state
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.Id = collection.Id
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.Type = collection.Type
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.Name = collection.Name
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.System = collection.System
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.ListRule = collection.ListRule
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.ViewRule = collection.ViewRule
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.CreateRule = collection.CreateRule
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.UpdateRule = collection.UpdateRule
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.DeleteRule = collection.DeleteRule
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.Schema = collection.Schema
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-30 16:28:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										upsertForm.Options = collection.Options
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if err := upsertForm.Validate(); err != nil {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											// serialize the validation error(s)
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-10 18:22:27 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											serializedErr, _ := json.MarshalIndent(err, "", "  ")
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return validation.Errors{"collections": validation.NewError(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												"collections_import_validate_failure",
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-10 18:22:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												fmt.Sprintf("Data validations failed for collection %q (%s):\n%s", collection.Name, collection.Id, serializedErr),
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											)}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-09 00:16:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return nil
							 | 
						
					
						
							
								
									
										
										
										
											2022-08-05 11:00:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 |