| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | package core | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"database/sql" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 	"log" | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	"log/slog" | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2024-07-24 01:43:57 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | 	"syscall" | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/fatih/color" | 
					
						
							|  |  |  | 	"github.com/pocketbase/dbx" | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/cron" | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/filesystem" | 
					
						
							|  |  |  | 	"github.com/pocketbase/pocketbase/tools/hook" | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/logger" | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/mailer" | 
					
						
							| 
									
										
										
										
											2023-01-12 21:20:51 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/routine" | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/store" | 
					
						
							|  |  |  | 	"github.com/pocketbase/pocketbase/tools/subscriptions" | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	"github.com/pocketbase/pocketbase/tools/types" | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-16 00:10:31 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2024-10-06 02:59:46 +08:00
										 |  |  | 	DefaultDataMaxOpenConns int           = 120 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	DefaultDataMaxIdleConns int           = 15 | 
					
						
							|  |  |  | 	DefaultAuxMaxOpenConns  int           = 20 | 
					
						
							|  |  |  | 	DefaultAuxMaxIdleConns  int           = 3 | 
					
						
							|  |  |  | 	DefaultQueryTimeout     time.Duration = 30 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	LocalStorageDirName       string = "storage" | 
					
						
							|  |  |  | 	LocalBackupsDirName       string = "backups" | 
					
						
							|  |  |  | 	LocalTempDirName          string = ".pb_temp_to_delete" // temp pb_data sub directory that will be deleted on each app.Bootstrap()
 | 
					
						
							|  |  |  | 	LocalAutocertCacheDirName string = ".autocert_cache" | 
					
						
							| 
									
										
										
										
											2022-12-16 00:10:31 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // FilesManager defines an interface with common methods that files manager models should implement.
 | 
					
						
							|  |  |  | type FilesManager interface { | 
					
						
							|  |  |  | 	// BaseFilesPath returns the storage dir path used by the interface instance.
 | 
					
						
							|  |  |  | 	BaseFilesPath() string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DBConnectFunc defines a database connection initialization function.
 | 
					
						
							|  |  |  | type DBConnectFunc func(dbPath string) (*dbx.DB, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // BaseAppConfig defines a BaseApp configuration option
 | 
					
						
							|  |  |  | type BaseAppConfig struct { | 
					
						
							|  |  |  | 	DBConnect        DBConnectFunc | 
					
						
							|  |  |  | 	DataDir          string | 
					
						
							|  |  |  | 	EncryptionEnv    string | 
					
						
							|  |  |  | 	QueryTimeout     time.Duration | 
					
						
							|  |  |  | 	DataMaxOpenConns int | 
					
						
							|  |  |  | 	DataMaxIdleConns int | 
					
						
							|  |  |  | 	AuxMaxOpenConns  int | 
					
						
							|  |  |  | 	AuxMaxIdleConns  int | 
					
						
							|  |  |  | 	IsDev            bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ensures that the BaseApp implements the App interface.
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | var _ App = (*BaseApp)(nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // BaseApp implements core.App and defines the base PocketBase app structure.
 | 
					
						
							|  |  |  | type BaseApp struct { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	config              *BaseAppConfig | 
					
						
							|  |  |  | 	txInfo              *txAppInfo | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	store               *store.Store[any] | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	cron                *cron.Cron | 
					
						
							|  |  |  | 	settings            *Settings | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	subscriptionsBroker *subscriptions.Broker | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	logger              *slog.Logger | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	concurrentDB        dbx.Builder | 
					
						
							|  |  |  | 	nonconcurrentDB     dbx.Builder | 
					
						
							|  |  |  | 	auxConcurrentDB     dbx.Builder | 
					
						
							|  |  |  | 	auxNonconcurrentDB  dbx.Builder | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-26 20:42:45 +08:00
										 |  |  | 	// app event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onBootstrap     *hook.Hook[*BootstrapEvent] | 
					
						
							|  |  |  | 	onServe         *hook.Hook[*ServeEvent] | 
					
						
							|  |  |  | 	onTerminate     *hook.Hook[*TerminateEvent] | 
					
						
							|  |  |  | 	onBackupCreate  *hook.Hook[*BackupEvent] | 
					
						
							|  |  |  | 	onBackupRestore *hook.Hook[*BackupEvent] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db model hooks
 | 
					
						
							|  |  |  | 	onModelValidate           *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelCreate             *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelCreateExecute      *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelAfterCreateSuccess *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelAfterCreateError   *hook.Hook[*ModelErrorEvent] | 
					
						
							|  |  |  | 	onModelUpdate             *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelUpdateWrite        *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelAfterUpdateSuccess *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelAfterUpdateError   *hook.Hook[*ModelErrorEvent] | 
					
						
							|  |  |  | 	onModelDelete             *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelDeleteExecute      *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelAfterDeleteSuccess *hook.Hook[*ModelEvent] | 
					
						
							|  |  |  | 	onModelAfterDeleteError   *hook.Hook[*ModelErrorEvent] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db record hooks
 | 
					
						
							|  |  |  | 	onRecordEnrich             *hook.Hook[*RecordEnrichEvent] | 
					
						
							|  |  |  | 	onRecordValidate           *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordCreate             *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordCreateExecute      *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordAfterCreateSuccess *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordAfterCreateError   *hook.Hook[*RecordErrorEvent] | 
					
						
							|  |  |  | 	onRecordUpdate             *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordUpdateExecute      *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordAfterUpdateSuccess *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordAfterUpdateError   *hook.Hook[*RecordErrorEvent] | 
					
						
							|  |  |  | 	onRecordDelete             *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordDeleteExecute      *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordAfterDeleteSuccess *hook.Hook[*RecordEvent] | 
					
						
							|  |  |  | 	onRecordAfterDeleteError   *hook.Hook[*RecordErrorEvent] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db collection hooks
 | 
					
						
							|  |  |  | 	onCollectionValidate           *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionCreate             *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionCreateExecute      *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionAfterCreateSuccess *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionAfterCreateError   *hook.Hook[*CollectionErrorEvent] | 
					
						
							|  |  |  | 	onCollectionUpdate             *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionUpdateExecute      *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionAfterUpdateSuccess *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionAfterUpdateError   *hook.Hook[*CollectionErrorEvent] | 
					
						
							|  |  |  | 	onCollectionDelete             *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionDeleteExecute      *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionAfterDeleteSuccess *hook.Hook[*CollectionEvent] | 
					
						
							|  |  |  | 	onCollectionAfterDeleteError   *hook.Hook[*CollectionErrorEvent] | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// mailer event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onMailerSend                    *hook.Hook[*MailerEvent] | 
					
						
							|  |  |  | 	onMailerRecordPasswordResetSend *hook.Hook[*MailerRecordEvent] | 
					
						
							|  |  |  | 	onMailerRecordVerificationSend  *hook.Hook[*MailerRecordEvent] | 
					
						
							|  |  |  | 	onMailerRecordEmailChangeSend   *hook.Hook[*MailerRecordEvent] | 
					
						
							|  |  |  | 	onMailerRecordOTPSend           *hook.Hook[*MailerRecordEvent] | 
					
						
							|  |  |  | 	onMailerRecordAuthAlertSend     *hook.Hook[*MailerRecordEvent] | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// realtime api event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onRealtimeConnectRequest   *hook.Hook[*RealtimeConnectRequestEvent] | 
					
						
							|  |  |  | 	onRealtimeMessageSend      *hook.Hook[*RealtimeMessageEvent] | 
					
						
							|  |  |  | 	onRealtimeSubscribeRequest *hook.Hook[*RealtimeSubscribeRequestEvent] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// settings event hooks
 | 
					
						
							|  |  |  | 	onSettingsListRequest   *hook.Hook[*SettingsListRequestEvent] | 
					
						
							|  |  |  | 	onSettingsUpdateRequest *hook.Hook[*SettingsUpdateRequestEvent] | 
					
						
							|  |  |  | 	onSettingsReload        *hook.Hook[*SettingsReloadEvent] | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// file api event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onFileDownloadRequest *hook.Hook[*FileDownloadRequestEvent] | 
					
						
							|  |  |  | 	onFileTokenRequest    *hook.Hook[*FileTokenRequestEvent] | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | 	// record auth API event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onRecordAuthRequest                 *hook.Hook[*RecordAuthRequestEvent] | 
					
						
							|  |  |  | 	onRecordAuthWithPasswordRequest     *hook.Hook[*RecordAuthWithPasswordRequestEvent] | 
					
						
							|  |  |  | 	onRecordAuthWithOAuth2Request       *hook.Hook[*RecordAuthWithOAuth2RequestEvent] | 
					
						
							|  |  |  | 	onRecordAuthRefreshRequest          *hook.Hook[*RecordAuthRefreshRequestEvent] | 
					
						
							|  |  |  | 	onRecordRequestPasswordResetRequest *hook.Hook[*RecordRequestPasswordResetRequestEvent] | 
					
						
							|  |  |  | 	onRecordConfirmPasswordResetRequest *hook.Hook[*RecordConfirmPasswordResetRequestEvent] | 
					
						
							|  |  |  | 	onRecordRequestVerificationRequest  *hook.Hook[*RecordRequestVerificationRequestEvent] | 
					
						
							|  |  |  | 	onRecordConfirmVerificationRequest  *hook.Hook[*RecordConfirmVerificationRequestEvent] | 
					
						
							|  |  |  | 	onRecordRequestEmailChangeRequest   *hook.Hook[*RecordRequestEmailChangeRequestEvent] | 
					
						
							|  |  |  | 	onRecordConfirmEmailChangeRequest   *hook.Hook[*RecordConfirmEmailChangeRequestEvent] | 
					
						
							|  |  |  | 	onRecordRequestOTPRequest           *hook.Hook[*RecordCreateOTPRequestEvent] | 
					
						
							|  |  |  | 	onRecordAuthWithOTPRequest          *hook.Hook[*RecordAuthWithOTPRequestEvent] | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// record crud API event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onRecordsListRequest  *hook.Hook[*RecordsListRequestEvent] | 
					
						
							|  |  |  | 	onRecordViewRequest   *hook.Hook[*RecordRequestEvent] | 
					
						
							|  |  |  | 	onRecordCreateRequest *hook.Hook[*RecordRequestEvent] | 
					
						
							|  |  |  | 	onRecordUpdateRequest *hook.Hook[*RecordRequestEvent] | 
					
						
							|  |  |  | 	onRecordDeleteRequest *hook.Hook[*RecordRequestEvent] | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | 	// collection API event hooks
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onCollectionsListRequest   *hook.Hook[*CollectionsListRequestEvent] | 
					
						
							|  |  |  | 	onCollectionViewRequest    *hook.Hook[*CollectionRequestEvent] | 
					
						
							|  |  |  | 	onCollectionCreateRequest  *hook.Hook[*CollectionRequestEvent] | 
					
						
							|  |  |  | 	onCollectionUpdateRequest  *hook.Hook[*CollectionRequestEvent] | 
					
						
							|  |  |  | 	onCollectionDeleteRequest  *hook.Hook[*CollectionRequestEvent] | 
					
						
							|  |  |  | 	onCollectionsImportRequest *hook.Hook[*CollectionsImportRequestEvent] | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	onBatchRequest *hook.Hook[*BatchRequestEvent] | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // NewBaseApp creates and returns a new BaseApp instance
 | 
					
						
							|  |  |  | // configured with the provided arguments.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2022-10-18 01:17:44 +08:00
										 |  |  | // To initialize the app, you need to call `app.Bootstrap()`.
 | 
					
						
							| 
									
										
										
										
											2023-06-08 22:59:08 +08:00
										 |  |  | func NewBaseApp(config BaseAppConfig) *BaseApp { | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 	app := &BaseApp{ | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		settings:            newDefaultSettings(), | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 		store:               store.New[any](nil), | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		cron:                cron.New(), | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 		subscriptionsBroker: subscriptions.NewBroker(), | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		config:              &config, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	// apply config defaults
 | 
					
						
							|  |  |  | 	if app.config.DBConnect == nil { | 
					
						
							| 
									
										
										
										
											2024-10-30 04:46:56 +08:00
										 |  |  | 		app.config.DBConnect = DefaultDBConnect | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if app.config.DataMaxOpenConns <= 0 { | 
					
						
							|  |  |  | 		app.config.DataMaxOpenConns = DefaultDataMaxOpenConns | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if app.config.DataMaxIdleConns <= 0 { | 
					
						
							|  |  |  | 		app.config.DataMaxIdleConns = DefaultDataMaxIdleConns | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if app.config.AuxMaxOpenConns <= 0 { | 
					
						
							|  |  |  | 		app.config.AuxMaxOpenConns = DefaultAuxMaxOpenConns | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if app.config.AuxMaxIdleConns <= 0 { | 
					
						
							|  |  |  | 		app.config.AuxMaxIdleConns = DefaultAuxMaxIdleConns | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if app.config.QueryTimeout <= 0 { | 
					
						
							|  |  |  | 		app.config.QueryTimeout = DefaultQueryTimeout | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	app.initHooks() | 
					
						
							|  |  |  | 	app.registerBaseHooks() | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return app | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // initHooks initializes all app hook handlers.
 | 
					
						
							|  |  |  | func (app *BaseApp) initHooks() { | 
					
						
							|  |  |  | 	// app event hooks
 | 
					
						
							|  |  |  | 	app.onBootstrap = &hook.Hook[*BootstrapEvent]{} | 
					
						
							|  |  |  | 	app.onServe = &hook.Hook[*ServeEvent]{} | 
					
						
							|  |  |  | 	app.onTerminate = &hook.Hook[*TerminateEvent]{} | 
					
						
							|  |  |  | 	app.onBackupCreate = &hook.Hook[*BackupEvent]{} | 
					
						
							|  |  |  | 	app.onBackupRestore = &hook.Hook[*BackupEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db model hooks
 | 
					
						
							|  |  |  | 	app.onModelValidate = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelCreate = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelCreateExecute = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelAfterCreateSuccess = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelAfterCreateError = &hook.Hook[*ModelErrorEvent]{} | 
					
						
							|  |  |  | 	app.onModelUpdate = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelUpdateWrite = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelAfterUpdateSuccess = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelAfterUpdateError = &hook.Hook[*ModelErrorEvent]{} | 
					
						
							|  |  |  | 	app.onModelDelete = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelDeleteExecute = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelAfterDeleteSuccess = &hook.Hook[*ModelEvent]{} | 
					
						
							|  |  |  | 	app.onModelAfterDeleteError = &hook.Hook[*ModelErrorEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db record hooks
 | 
					
						
							|  |  |  | 	app.onRecordEnrich = &hook.Hook[*RecordEnrichEvent]{} | 
					
						
							|  |  |  | 	app.onRecordValidate = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordCreate = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordCreateExecute = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAfterCreateSuccess = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAfterCreateError = &hook.Hook[*RecordErrorEvent]{} | 
					
						
							|  |  |  | 	app.onRecordUpdate = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordUpdateExecute = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAfterUpdateSuccess = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAfterUpdateError = &hook.Hook[*RecordErrorEvent]{} | 
					
						
							|  |  |  | 	app.onRecordDelete = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordDeleteExecute = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAfterDeleteSuccess = &hook.Hook[*RecordEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAfterDeleteError = &hook.Hook[*RecordErrorEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db collection hooks
 | 
					
						
							|  |  |  | 	app.onCollectionValidate = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionCreate = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionCreateExecute = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionAfterCreateSuccess = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionAfterCreateError = &hook.Hook[*CollectionErrorEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionUpdate = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionUpdateExecute = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionAfterUpdateSuccess = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionAfterUpdateError = &hook.Hook[*CollectionErrorEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionDelete = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionAfterDeleteSuccess = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionDeleteExecute = &hook.Hook[*CollectionEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionAfterDeleteError = &hook.Hook[*CollectionErrorEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// mailer event hooks
 | 
					
						
							|  |  |  | 	app.onMailerSend = &hook.Hook[*MailerEvent]{} | 
					
						
							|  |  |  | 	app.onMailerRecordPasswordResetSend = &hook.Hook[*MailerRecordEvent]{} | 
					
						
							|  |  |  | 	app.onMailerRecordVerificationSend = &hook.Hook[*MailerRecordEvent]{} | 
					
						
							|  |  |  | 	app.onMailerRecordEmailChangeSend = &hook.Hook[*MailerRecordEvent]{} | 
					
						
							|  |  |  | 	app.onMailerRecordOTPSend = &hook.Hook[*MailerRecordEvent]{} | 
					
						
							|  |  |  | 	app.onMailerRecordAuthAlertSend = &hook.Hook[*MailerRecordEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// realtime API event hooks
 | 
					
						
							|  |  |  | 	app.onRealtimeConnectRequest = &hook.Hook[*RealtimeConnectRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRealtimeMessageSend = &hook.Hook[*RealtimeMessageEvent]{} | 
					
						
							|  |  |  | 	app.onRealtimeSubscribeRequest = &hook.Hook[*RealtimeSubscribeRequestEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// settings event hooks
 | 
					
						
							|  |  |  | 	app.onSettingsListRequest = &hook.Hook[*SettingsListRequestEvent]{} | 
					
						
							|  |  |  | 	app.onSettingsUpdateRequest = &hook.Hook[*SettingsUpdateRequestEvent]{} | 
					
						
							|  |  |  | 	app.onSettingsReload = &hook.Hook[*SettingsReloadEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// file API event hooks
 | 
					
						
							|  |  |  | 	app.onFileDownloadRequest = &hook.Hook[*FileDownloadRequestEvent]{} | 
					
						
							|  |  |  | 	app.onFileTokenRequest = &hook.Hook[*FileTokenRequestEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// record auth API event hooks
 | 
					
						
							|  |  |  | 	app.onRecordAuthRequest = &hook.Hook[*RecordAuthRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAuthWithPasswordRequest = &hook.Hook[*RecordAuthWithPasswordRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAuthWithOAuth2Request = &hook.Hook[*RecordAuthWithOAuth2RequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAuthRefreshRequest = &hook.Hook[*RecordAuthRefreshRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordRequestPasswordResetRequest = &hook.Hook[*RecordRequestPasswordResetRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordConfirmPasswordResetRequest = &hook.Hook[*RecordConfirmPasswordResetRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordRequestVerificationRequest = &hook.Hook[*RecordRequestVerificationRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordConfirmVerificationRequest = &hook.Hook[*RecordConfirmVerificationRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordRequestEmailChangeRequest = &hook.Hook[*RecordRequestEmailChangeRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordConfirmEmailChangeRequest = &hook.Hook[*RecordConfirmEmailChangeRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordRequestOTPRequest = &hook.Hook[*RecordCreateOTPRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordAuthWithOTPRequest = &hook.Hook[*RecordAuthWithOTPRequestEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// record crud API event hooks
 | 
					
						
							|  |  |  | 	app.onRecordsListRequest = &hook.Hook[*RecordsListRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordViewRequest = &hook.Hook[*RecordRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordCreateRequest = &hook.Hook[*RecordRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordUpdateRequest = &hook.Hook[*RecordRequestEvent]{} | 
					
						
							|  |  |  | 	app.onRecordDeleteRequest = &hook.Hook[*RecordRequestEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// collection API event hooks
 | 
					
						
							|  |  |  | 	app.onCollectionsListRequest = &hook.Hook[*CollectionsListRequestEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionViewRequest = &hook.Hook[*CollectionRequestEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionCreateRequest = &hook.Hook[*CollectionRequestEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionUpdateRequest = &hook.Hook[*CollectionRequestEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionDeleteRequest = &hook.Hook[*CollectionRequestEvent]{} | 
					
						
							|  |  |  | 	app.onCollectionsImportRequest = &hook.Hook[*CollectionsImportRequestEvent]{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	app.onBatchRequest = &hook.Hook[*BatchRequestEvent]{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // UnsafeWithoutHooks returns a shallow copy of the current app WITHOUT any registered hooks.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NB! Note that using the returned app instance may cause data integrity errors
 | 
					
						
							|  |  |  | // since the Record validations and data normalizations (including files uploads)
 | 
					
						
							|  |  |  | // rely on the app hooks to work.
 | 
					
						
							|  |  |  | func (app *BaseApp) UnsafeWithoutHooks() App { | 
					
						
							|  |  |  | 	clone := *app | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// reset all hook handlers
 | 
					
						
							|  |  |  | 	clone.initHooks() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &clone | 
					
						
							| 
									
										
										
										
											2022-12-16 05:20:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | // Logger returns the default app logger.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If the application is not bootstrapped yet, fallbacks to slog.Default().
 | 
					
						
							|  |  |  | func (app *BaseApp) Logger() *slog.Logger { | 
					
						
							|  |  |  | 	if app.logger == nil { | 
					
						
							|  |  |  | 		return slog.Default() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return app.logger | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // IsTransactional checks if the current app instance is part of a transaction.
 | 
					
						
							|  |  |  | func (app *BaseApp) IsTransactional() bool { | 
					
						
							|  |  |  | 	return app.txInfo != nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // IsBootstrapped checks if the application was initialized
 | 
					
						
							|  |  |  | // (aka. whether Bootstrap() was called).
 | 
					
						
							|  |  |  | func (app *BaseApp) IsBootstrapped() bool { | 
					
						
							|  |  |  | 	return app.concurrentDB != nil && app.auxConcurrentDB != nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // Bootstrap initializes the application
 | 
					
						
							| 
									
										
										
										
											2022-12-16 05:20:23 +08:00
										 |  |  | // (aka. create data dir, open db connections, load settings, etc.).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // It will call ResetBootstrapState() if the application was already bootstrapped.
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | func (app *BaseApp) Bootstrap() error { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	event := &BootstrapEvent{} | 
					
						
							|  |  |  | 	event.App = app | 
					
						
							| 
									
										
										
										
											2022-11-26 20:42:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-07 03:51:39 +08:00
										 |  |  | 	err := app.OnBootstrap().Trigger(event, func(e *BootstrapEvent) error { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		// clear resources of previous core state (if any)
 | 
					
						
							|  |  |  | 		if err := app.ResetBootstrapState(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		// ensure that data dir exist
 | 
					
						
							|  |  |  | 		if err := os.MkdirAll(app.DataDir(), os.ModePerm); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if err := app.initDataDB(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if err := app.initAuxDB(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if err := app.initLogger(); err != nil { | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if err := app.RunSystemMigrations(); err != nil { | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if err := app.ReloadCachedCollections(); err != nil { | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if err := app.ReloadSettings(); err != nil { | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		// try to cleanup the pb_data temp directory (if any)
 | 
					
						
							|  |  |  | 		_ = os.RemoveAll(filepath.Join(app.DataDir(), LocalTempDirName)) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-10-07 03:51:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// add a more user friendly message in case users forgot to call
 | 
					
						
							|  |  |  | 	// e.Next() as part of their bootstrap hook
 | 
					
						
							|  |  |  | 	if err == nil && !app.IsBootstrapped() { | 
					
						
							|  |  |  | 		app.Logger().Warn("OnBootstrap hook didn't fail but the app is still not bootstrapped - maybe missing e.Next()?") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | type closer interface { | 
					
						
							|  |  |  | 	Close() error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ResetBootstrapState releases the initialized core app resources
 | 
					
						
							|  |  |  | // (closing db connections, stopping cron ticker, etc.).
 | 
					
						
							|  |  |  | func (app *BaseApp) ResetBootstrapState() error { | 
					
						
							|  |  |  | 	app.Cron().Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var errs []error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dbs := []*dbx.Builder{ | 
					
						
							|  |  |  | 		&app.concurrentDB, | 
					
						
							|  |  |  | 		&app.nonconcurrentDB, | 
					
						
							|  |  |  | 		&app.auxConcurrentDB, | 
					
						
							|  |  |  | 		&app.auxNonconcurrentDB, | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	for _, db := range dbs { | 
					
						
							|  |  |  | 		if db == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if v, ok := (*db).(closer); ok { | 
					
						
							|  |  |  | 			if err := v.Close(); err != nil { | 
					
						
							|  |  |  | 				errs = append(errs, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		*db = nil | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	if len(errs) > 0 { | 
					
						
							|  |  |  | 		return errors.Join(errs...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // DB returns the default app data db instance (pb_data/data.db).
 | 
					
						
							|  |  |  | func (app *BaseApp) DB() dbx.Builder { | 
					
						
							|  |  |  | 	return app.concurrentDB | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // NonconcurrentDB returns the nonconcurrent app data db instance (pb_data/data.db).
 | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // The returned db instance is limited only to a single open connection,
 | 
					
						
							|  |  |  | // meaning that it can process only 1 db operation at a time (other operations will be queued up).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This method is used mainly internally and in the tests to execute write
 | 
					
						
							|  |  |  | // (save/delete) db operations as it helps with minimizing the SQLITE_BUSY errors.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // For the majority of cases you would want to use the regular DB() method
 | 
					
						
							|  |  |  | // since it allows concurrent db read operations.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // In a transaction the ConcurrentDB() and NonconcurrentDB() refer to the same *dbx.TX instance.
 | 
					
						
							|  |  |  | func (app *BaseApp) NonconcurrentDB() dbx.Builder { | 
					
						
							|  |  |  | 	return app.nonconcurrentDB | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-06 21:41:05 +08:00
										 |  |  | // AuxDB returns the default app auxiliary db instance (pb_data/auxiliary.db).
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) AuxDB() dbx.Builder { | 
					
						
							|  |  |  | 	return app.auxConcurrentDB | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-06 21:41:05 +08:00
										 |  |  | // AuxNonconcurrentDB returns the nonconcurrent app auxiliary db instance (pb_data/auxiliary.db).
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // The returned db instance is limited only to a single open connection,
 | 
					
						
							|  |  |  | // meaning that it can process only 1 db operation at a time (other operations will be queued up).
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This method is used mainly internally and in the tests to execute write
 | 
					
						
							|  |  |  | // (save/delete) db operations as it helps with minimizing the SQLITE_BUSY errors.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // For the majority of cases you would want to use the regular DB() method
 | 
					
						
							|  |  |  | // since it allows concurrent db read operations.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // In a transaction the AuxNonconcurrentDB() and AuxNonconcurrentDB() refer to the same *dbx.TX instance.
 | 
					
						
							|  |  |  | func (app *BaseApp) AuxNonconcurrentDB() dbx.Builder { | 
					
						
							|  |  |  | 	return app.auxNonconcurrentDB | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DataDir returns the app data directory path.
 | 
					
						
							|  |  |  | func (app *BaseApp) DataDir() string { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return app.config.DataDir | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // EncryptionEnv returns the name of the app secret env key
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // (currently used primarily for optional settings encryption but this may change in the future).
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | func (app *BaseApp) EncryptionEnv() string { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return app.config.EncryptionEnv | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | // IsDev returns whether the app is in dev mode.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // When enabled logs, executed sql statements, etc. are printed to the stderr.
 | 
					
						
							|  |  |  | func (app *BaseApp) IsDev() bool { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return app.config.IsDev | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // Settings returns the loaded app settings.
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) Settings() *Settings { | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	return app.settings | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // Store returns the app runtime store.
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | func (app *BaseApp) Store() *store.Store[any] { | 
					
						
							|  |  |  | 	return app.store | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // Cron returns the app cron instance.
 | 
					
						
							|  |  |  | func (app *BaseApp) Cron() *cron.Cron { | 
					
						
							|  |  |  | 	return app.cron | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // SubscriptionsBroker returns the app realtime subscriptions broker instance.
 | 
					
						
							|  |  |  | func (app *BaseApp) SubscriptionsBroker() *subscriptions.Broker { | 
					
						
							|  |  |  | 	return app.subscriptionsBroker | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewMailClient creates and returns a new SMTP or Sendmail client
 | 
					
						
							|  |  |  | // based on the current app settings.
 | 
					
						
							|  |  |  | func (app *BaseApp) NewMailClient() mailer.Mailer { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	var client mailer.Mailer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// init mailer client
 | 
					
						
							|  |  |  | 	if app.Settings().SMTP.Enabled { | 
					
						
							|  |  |  | 		client = &mailer.SMTPClient{ | 
					
						
							|  |  |  | 			Host:       app.Settings().SMTP.Host, | 
					
						
							|  |  |  | 			Port:       app.Settings().SMTP.Port, | 
					
						
							|  |  |  | 			Username:   app.Settings().SMTP.Username, | 
					
						
							|  |  |  | 			Password:   app.Settings().SMTP.Password, | 
					
						
							|  |  |  | 			TLS:        app.Settings().SMTP.TLS, | 
					
						
							|  |  |  | 			AuthMethod: app.Settings().SMTP.AuthMethod, | 
					
						
							|  |  |  | 			LocalName:  app.Settings().SMTP.LocalName, | 
					
						
							| 
									
										
										
										
											2022-12-13 17:45:59 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		client = &mailer.Sendmail{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// register the app level hook
 | 
					
						
							|  |  |  | 	if h, ok := client.(mailer.SendInterceptor); ok { | 
					
						
							|  |  |  | 		h.OnSend().Bind(&hook.Handler[*mailer.SendEvent]{ | 
					
						
							|  |  |  | 			Id: "__pbMailerOnSend__", | 
					
						
							|  |  |  | 			Func: func(e *mailer.SendEvent) error { | 
					
						
							|  |  |  | 				appEvent := new(MailerEvent) | 
					
						
							|  |  |  | 				appEvent.App = app | 
					
						
							|  |  |  | 				appEvent.Mailer = client | 
					
						
							|  |  |  | 				appEvent.Message = e.Message | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return app.OnMailerSend().Trigger(appEvent, func(ae *MailerEvent) error { | 
					
						
							|  |  |  | 					e.Message = ae.Message | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// print the mail in the console to assist with the debugging
 | 
					
						
							|  |  |  | 					if app.IsDev() { | 
					
						
							|  |  |  | 						logDate := new(strings.Builder) | 
					
						
							|  |  |  | 						log.New(logDate, "", log.LstdFlags).Print() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						mailLog := new(strings.Builder) | 
					
						
							|  |  |  | 						mailLog.WriteString(strings.TrimSpace(logDate.String())) | 
					
						
							|  |  |  | 						mailLog.WriteString(" Mail sent\n") | 
					
						
							|  |  |  | 						fmt.Fprintf(mailLog, "├─ From: %v\n", ae.Message.From) | 
					
						
							|  |  |  | 						fmt.Fprintf(mailLog, "├─ To: %v\n", ae.Message.To) | 
					
						
							|  |  |  | 						fmt.Fprintf(mailLog, "├─ Cc: %v\n", ae.Message.Cc) | 
					
						
							|  |  |  | 						fmt.Fprintf(mailLog, "├─ Bcc: %v\n", ae.Message.Bcc) | 
					
						
							|  |  |  | 						fmt.Fprintf(mailLog, "├─ Subject: %v\n", ae.Message.Subject) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if len(ae.Message.Attachments) > 0 { | 
					
						
							|  |  |  | 							attachmentKeys := make([]string, 0, len(ae.Message.Attachments)) | 
					
						
							|  |  |  | 							for k := range ae.Message.Attachments { | 
					
						
							|  |  |  | 								attachmentKeys = append(attachmentKeys, k) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							fmt.Fprintf(mailLog, "├─ Attachments: %v\n", attachmentKeys) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						const indentation = "        " | 
					
						
							|  |  |  | 						if ae.Message.Text != "" { | 
					
						
							|  |  |  | 							textParts := strings.Split(strings.TrimSpace(ae.Message.Text), "\n") | 
					
						
							|  |  |  | 							textIndented := indentation + strings.Join(textParts, "\n"+indentation) | 
					
						
							|  |  |  | 							fmt.Fprintf(mailLog, "└─ Text:\n%s", textIndented) | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							htmlParts := strings.Split(strings.TrimSpace(ae.Message.HTML), "\n") | 
					
						
							|  |  |  | 							htmlIndented := indentation + strings.Join(htmlParts, "\n"+indentation) | 
					
						
							|  |  |  | 							fmt.Fprintf(mailLog, "└─ HTML:\n%s", htmlIndented) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						color.HiBlack("%s", mailLog.String()) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// send the email with the new mailer in case it was replaced
 | 
					
						
							|  |  |  | 					if client != ae.Mailer { | 
					
						
							|  |  |  | 						return ae.Mailer.Send(e.Message) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					return e.Next() | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return client | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewFilesystem creates a new local or S3 filesystem instance
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // for managing regular app files (ex. record uploads)
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // based on the current app settings.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2023-06-14 18:14:30 +08:00
										 |  |  | // NB! Make sure to call Close() on the returned result
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // after you are done working with it.
 | 
					
						
							|  |  |  | func (app *BaseApp) NewFilesystem() (*filesystem.System, error) { | 
					
						
							| 
									
										
										
										
											2023-02-19 01:33:42 +08:00
										 |  |  | 	if app.settings != nil && app.settings.S3.Enabled { | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 		return filesystem.NewS3( | 
					
						
							|  |  |  | 			app.settings.S3.Bucket, | 
					
						
							|  |  |  | 			app.settings.S3.Region, | 
					
						
							|  |  |  | 			app.settings.S3.Endpoint, | 
					
						
							|  |  |  | 			app.settings.S3.AccessKey, | 
					
						
							|  |  |  | 			app.settings.S3.Secret, | 
					
						
							| 
									
										
										
										
											2022-07-19 15:45:38 +08:00
										 |  |  | 			app.settings.S3.ForcePathStyle, | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// fallback to local filesystem
 | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | 	return filesystem.NewLocal(filepath.Join(app.DataDir(), LocalStorageDirName)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewFilesystem creates a new local or S3 filesystem instance
 | 
					
						
							|  |  |  | // for managing app backups based on the current app settings.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2023-06-14 18:14:30 +08:00
										 |  |  | // NB! Make sure to call Close() on the returned result
 | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | // after you are done working with it.
 | 
					
						
							|  |  |  | func (app *BaseApp) NewBackupsFilesystem() (*filesystem.System, error) { | 
					
						
							|  |  |  | 	if app.settings != nil && app.settings.Backups.S3.Enabled { | 
					
						
							|  |  |  | 		return filesystem.NewS3( | 
					
						
							|  |  |  | 			app.settings.Backups.S3.Bucket, | 
					
						
							|  |  |  | 			app.settings.Backups.S3.Region, | 
					
						
							|  |  |  | 			app.settings.Backups.S3.Endpoint, | 
					
						
							|  |  |  | 			app.settings.Backups.S3.AccessKey, | 
					
						
							|  |  |  | 			app.settings.Backups.S3.Secret, | 
					
						
							|  |  |  | 			app.settings.Backups.S3.ForcePathStyle, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// fallback to local filesystem
 | 
					
						
							|  |  |  | 	return filesystem.NewLocal(filepath.Join(app.DataDir(), LocalBackupsDirName)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Restart restarts (aka. replaces) the current running application process.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NB! It relies on execve which is supported only on UNIX based systems.
 | 
					
						
							|  |  |  | func (app *BaseApp) Restart() error { | 
					
						
							|  |  |  | 	if runtime.GOOS == "windows" { | 
					
						
							|  |  |  | 		return errors.New("restart is not supported on windows") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	execPath, err := os.Executable() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	event := &TerminateEvent{} | 
					
						
							|  |  |  | 	event.App = app | 
					
						
							|  |  |  | 	event.IsRestart = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return app.OnTerminate().Trigger(event, func(e *TerminateEvent) error { | 
					
						
							|  |  |  | 		_ = e.App.ResetBootstrapState() | 
					
						
							| 
									
										
										
										
											2023-12-10 01:43:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 03:16:48 +08:00
										 |  |  | 		// attempt to restart the bootstrap process in case execve returns an error for some reason
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		defer func() { | 
					
						
							|  |  |  | 			if err := e.App.Bootstrap(); err != nil { | 
					
						
							|  |  |  | 				app.Logger().Error("Failed to rebootstrap the application after failed app.Restart()", "error", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2023-12-08 21:45:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 03:16:48 +08:00
										 |  |  | 		return syscall.Exec(execPath, os.Args, os.Environ()) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // RunSystemMigrations applies all new migrations registered in the [core.SystemMigrations] list.
 | 
					
						
							|  |  |  | func (app *BaseApp) RunSystemMigrations() error { | 
					
						
							|  |  |  | 	_, err := NewMigrationsRunner(app, SystemMigrations).Up() | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-03 21:01:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // RunAppMigrations applies all new migrations registered in the [core.AppMigrations] list.
 | 
					
						
							|  |  |  | func (app *BaseApp) RunAppMigrations() error { | 
					
						
							|  |  |  | 	_, err := NewMigrationsRunner(app, AppMigrations).Up() | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // RunAllMigrations applies all system and app migrations
 | 
					
						
							|  |  |  | // (aka. from both [core.SystemMigrations] and [core.AppMigrations]).
 | 
					
						
							|  |  |  | func (app *BaseApp) RunAllMigrations() error { | 
					
						
							|  |  |  | 	list := MigrationsList{} | 
					
						
							|  |  |  | 	list.Copy(SystemMigrations) | 
					
						
							|  |  |  | 	list.Copy(AppMigrations) | 
					
						
							|  |  |  | 	_, err := NewMigrationsRunner(app, list).Up() | 
					
						
							|  |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2022-11-26 20:42:45 +08:00
										 |  |  | // App event hooks
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnBootstrap() *hook.Hook[*BootstrapEvent] { | 
					
						
							|  |  |  | 	return app.onBootstrap | 
					
						
							| 
									
										
										
										
											2022-11-26 20:42:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnServe() *hook.Hook[*ServeEvent] { | 
					
						
							|  |  |  | 	return app.onServe | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnTerminate() *hook.Hook[*TerminateEvent] { | 
					
						
							|  |  |  | 	return app.onTerminate | 
					
						
							| 
									
										
										
										
											2022-12-02 22:36:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnBackupCreate() *hook.Hook[*BackupEvent] { | 
					
						
							|  |  |  | 	return app.onBackupCreate | 
					
						
							| 
									
										
										
										
											2022-12-02 22:36:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnBackupRestore() *hook.Hook[*BackupEvent] { | 
					
						
							|  |  |  | 	return app.onBackupRestore | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // ---------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelCreate(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelCreate, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelCreateExecute(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelCreateExecute, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelAfterCreateSuccess(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelAfterCreateSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelAfterCreateError(tags ...string) *hook.TaggedHook[*ModelErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelAfterCreateError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelUpdate(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelUpdate, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelUpdateExecute(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelUpdateWrite, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelAfterUpdateSuccess(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelAfterUpdateSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelAfterUpdateError(tags ...string) *hook.TaggedHook[*ModelErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelAfterUpdateError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelValidate(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelValidate, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelDelete(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelDelete, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelDeleteExecute(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelDeleteExecute, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelAfterDeleteSuccess(tags ...string) *hook.TaggedHook[*ModelEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelAfterDeleteSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnModelAfterDeleteError(tags ...string) *hook.TaggedHook[*ModelErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onModelAfterDeleteError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordEnrich(tags ...string) *hook.TaggedHook[*RecordEnrichEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordEnrich, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordValidate(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordValidate, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordCreate(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordCreate, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-02 20:25:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordCreateExecute(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordCreateExecute, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-02 20:25:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAfterCreateSuccess(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAfterCreateSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-02 20:25:36 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAfterCreateError(tags ...string) *hook.TaggedHook[*RecordErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAfterCreateError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordUpdate(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordUpdate, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordUpdateExecute(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordUpdateExecute, tags...) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAfterUpdateSuccess(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAfterUpdateSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAfterUpdateError(tags ...string) *hook.TaggedHook[*RecordErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAfterUpdateError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordDelete(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordDelete, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordDeleteExecute(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordDeleteExecute, tags...) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAfterDeleteSuccess(tags ...string) *hook.TaggedHook[*RecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAfterDeleteSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAfterDeleteError(tags ...string) *hook.TaggedHook[*RecordErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAfterDeleteError, tags...) | 
					
						
							| 
									
										
										
										
											2023-04-05 01:33:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionValidate(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionValidate, tags...) | 
					
						
							| 
									
										
										
										
											2023-04-05 01:33:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionCreate(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionCreate, tags...) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionCreateExecute(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionCreateExecute, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionAfterCreateSuccess(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionAfterCreateSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionAfterCreateError(tags ...string) *hook.TaggedHook[*CollectionErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionAfterCreateError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionUpdate(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionUpdate, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionUpdateExecute(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionUpdateExecute, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionAfterUpdateSuccess(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionAfterUpdateSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionAfterUpdateError(tags ...string) *hook.TaggedHook[*CollectionErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionAfterUpdateError, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionDelete(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionDelete, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionDeleteExecute(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionDeleteExecute, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionAfterDeleteSuccess(tags ...string) *hook.TaggedHook[*CollectionEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionAfterDeleteSuccess, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionAfterDeleteError(tags ...string) *hook.TaggedHook[*CollectionErrorEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onCollectionAfterDeleteError, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Mailer event hooks
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (app *BaseApp) OnMailerSend() *hook.Hook[*MailerEvent] { | 
					
						
							|  |  |  | 	return app.onMailerSend | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnMailerRecordPasswordResetSend(tags ...string) *hook.TaggedHook[*MailerRecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onMailerRecordPasswordResetSend, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnMailerRecordVerificationSend(tags ...string) *hook.TaggedHook[*MailerRecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onMailerRecordVerificationSend, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnMailerRecordEmailChangeSend(tags ...string) *hook.TaggedHook[*MailerRecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onMailerRecordEmailChangeSend, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnMailerRecordOTPSend(tags ...string) *hook.TaggedHook[*MailerRecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onMailerRecordOTPSend, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnMailerRecordAuthAlertSend(tags ...string) *hook.TaggedHook[*MailerRecordEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onMailerRecordAuthAlertSend, tags...) | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // Realtime API event hooks
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRealtimeConnectRequest() *hook.Hook[*RealtimeConnectRequestEvent] { | 
					
						
							|  |  |  | 	return app.onRealtimeConnectRequest | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRealtimeMessageSend() *hook.Hook[*RealtimeMessageEvent] { | 
					
						
							|  |  |  | 	return app.onRealtimeMessageSend | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRealtimeSubscribeRequest() *hook.Hook[*RealtimeSubscribeRequestEvent] { | 
					
						
							|  |  |  | 	return app.onRealtimeSubscribeRequest | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Settings API event hooks
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnSettingsListRequest() *hook.Hook[*SettingsListRequestEvent] { | 
					
						
							|  |  |  | 	return app.onSettingsListRequest | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnSettingsUpdateRequest() *hook.Hook[*SettingsUpdateRequestEvent] { | 
					
						
							|  |  |  | 	return app.onSettingsUpdateRequest | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnSettingsReload() *hook.Hook[*SettingsReloadEvent] { | 
					
						
							|  |  |  | 	return app.onSettingsReload | 
					
						
							| 
									
										
										
										
											2023-01-15 23:00:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | // File API event hooks
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnFileDownloadRequest(tags ...string) *hook.TaggedHook[*FileDownloadRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onFileDownloadRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-24 13:37:22 +08:00
										 |  |  | func (app *BaseApp) OnFileTokenRequest(tags ...string) *hook.TaggedHook[*FileTokenRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onFileTokenRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Record auth API event hooks
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (app *BaseApp) OnRecordAuthRequest(tags ...string) *hook.TaggedHook[*RecordAuthRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAuthRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAuthWithPasswordRequest(tags ...string) *hook.TaggedHook[*RecordAuthWithPasswordRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAuthWithPasswordRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAuthWithOAuth2Request(tags ...string) *hook.TaggedHook[*RecordAuthWithOAuth2RequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAuthWithOAuth2Request, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAuthRefreshRequest(tags ...string) *hook.TaggedHook[*RecordAuthRefreshRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAuthRefreshRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordRequestPasswordResetRequest(tags ...string) *hook.TaggedHook[*RecordRequestPasswordResetRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordRequestPasswordResetRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordConfirmPasswordResetRequest(tags ...string) *hook.TaggedHook[*RecordConfirmPasswordResetRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordConfirmPasswordResetRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordRequestVerificationRequest(tags ...string) *hook.TaggedHook[*RecordRequestVerificationRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordRequestVerificationRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordConfirmVerificationRequest(tags ...string) *hook.TaggedHook[*RecordConfirmVerificationRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordConfirmVerificationRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordRequestEmailChangeRequest(tags ...string) *hook.TaggedHook[*RecordRequestEmailChangeRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordRequestEmailChangeRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordConfirmEmailChangeRequest(tags ...string) *hook.TaggedHook[*RecordConfirmEmailChangeRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordConfirmEmailChangeRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordRequestOTPRequest(tags ...string) *hook.TaggedHook[*RecordCreateOTPRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordRequestOTPRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordAuthWithOTPRequest(tags ...string) *hook.TaggedHook[*RecordAuthWithOTPRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordAuthWithOTPRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2022-12-03 20:50:02 +08:00
										 |  |  | // Record CRUD API event hooks
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordsListRequest(tags ...string) *hook.TaggedHook[*RecordsListRequestEvent] { | 
					
						
							| 
									
										
										
										
											2023-01-28 04:19:08 +08:00
										 |  |  | 	return hook.NewTaggedHook(app.onRecordsListRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordViewRequest(tags ...string) *hook.TaggedHook[*RecordRequestEvent] { | 
					
						
							| 
									
										
										
										
											2023-01-28 04:19:08 +08:00
										 |  |  | 	return hook.NewTaggedHook(app.onRecordViewRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordCreateRequest(tags ...string) *hook.TaggedHook[*RecordRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordCreateRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordUpdateRequest(tags ...string) *hook.TaggedHook[*RecordRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordUpdateRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnRecordDeleteRequest(tags ...string) *hook.TaggedHook[*RecordRequestEvent] { | 
					
						
							|  |  |  | 	return hook.NewTaggedHook(app.onRecordDeleteRequest, tags...) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Collection API event hooks
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionsListRequest() *hook.Hook[*CollectionsListRequestEvent] { | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	return app.onCollectionsListRequest | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionViewRequest() *hook.Hook[*CollectionRequestEvent] { | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	return app.onCollectionViewRequest | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionCreateRequest() *hook.Hook[*CollectionRequestEvent] { | 
					
						
							|  |  |  | 	return app.onCollectionCreateRequest | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionUpdateRequest() *hook.Hook[*CollectionRequestEvent] { | 
					
						
							|  |  |  | 	return app.onCollectionUpdateRequest | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionDeleteRequest() *hook.Hook[*CollectionRequestEvent] { | 
					
						
							|  |  |  | 	return app.onCollectionDeleteRequest | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnCollectionsImportRequest() *hook.Hook[*CollectionsImportRequestEvent] { | 
					
						
							|  |  |  | 	return app.onCollectionsImportRequest | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) OnBatchRequest() *hook.Hook[*BatchRequestEvent] { | 
					
						
							|  |  |  | 	return app.onBatchRequest | 
					
						
							| 
									
										
										
										
											2022-08-08 01:58:21 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Helpers
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (app *BaseApp) initDataDB() error { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	dbPath := filepath.Join(app.DataDir(), "data.db") | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	concurrentDB, err := app.config.DBConnect(dbPath) | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	concurrentDB.DB().SetMaxOpenConns(app.config.DataMaxOpenConns) | 
					
						
							|  |  |  | 	concurrentDB.DB().SetMaxIdleConns(app.config.DataMaxIdleConns) | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	concurrentDB.DB().SetConnMaxIdleTime(3 * time.Minute) | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	nonconcurrentDB, err := app.config.DBConnect(dbPath) | 
					
						
							| 
									
										
										
										
											2022-12-15 22:42:35 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-12-16 19:07:58 +08:00
										 |  |  | 	nonconcurrentDB.DB().SetMaxOpenConns(1) | 
					
						
							|  |  |  | 	nonconcurrentDB.DB().SetMaxIdleConns(1) | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	nonconcurrentDB.DB().SetConnMaxIdleTime(3 * time.Minute) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 	if app.IsDev() { | 
					
						
							|  |  |  | 		nonconcurrentDB.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), normalizeSQLLog(sql)) | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		nonconcurrentDB.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), normalizeSQLLog(sql)) | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		concurrentDB.QueryLogFunc = nonconcurrentDB.QueryLogFunc | 
					
						
							|  |  |  | 		concurrentDB.ExecLogFunc = nonconcurrentDB.ExecLogFunc | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	app.concurrentDB = concurrentDB | 
					
						
							|  |  |  | 	app.nonconcurrentDB = nonconcurrentDB | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | var sqlLogReplacements = map[string]string{ | 
					
						
							|  |  |  | 	"{{":    "`", | 
					
						
							|  |  |  | 	"}}":    "`", | 
					
						
							|  |  |  | 	"[[":    "`", | 
					
						
							|  |  |  | 	"]]":    "`", | 
					
						
							|  |  |  | 	"<nil>": "NULL", | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | var sqlLogPrefixedTableIdentifierPattern = regexp.MustCompile(`\[\[(.+)\.(.+)\]\]`) | 
					
						
							|  |  |  | var sqlLogPrefixedColumnIdentifierPattern = regexp.MustCompile(`\{\{(.+)\.(.+)\}\}`) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | // normalizeSQLLog replaces common query builder charactes with their plain SQL version for easier debugging.
 | 
					
						
							|  |  |  | // The query is still not suitable for execution and should be used only for log and debug purposes
 | 
					
						
							|  |  |  | // (the normalization is done here to avoid breaking changes in dbx).
 | 
					
						
							|  |  |  | func normalizeSQLLog(sql string) string { | 
					
						
							|  |  |  | 	sql = sqlLogPrefixedTableIdentifierPattern.ReplaceAllString(sql, "`$1`.`$2`") | 
					
						
							| 
									
										
										
										
											2023-04-05 01:33:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	sql = sqlLogPrefixedColumnIdentifierPattern.ReplaceAllString(sql, "`$1`.`$2`") | 
					
						
							| 
									
										
										
										
											2023-04-05 01:33:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	for old, new := range sqlLogReplacements { | 
					
						
							|  |  |  | 		sql = strings.ReplaceAll(sql, old, new) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return sql | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) initAuxDB() error { | 
					
						
							| 
									
										
										
										
											2024-10-06 21:41:05 +08:00
										 |  |  | 	// note: renamed to "auxiliary" because "aux" is a reserved Windows filename
 | 
					
						
							|  |  |  | 	// (see https://github.com/pocketbase/pocketbase/issues/5607)
 | 
					
						
							|  |  |  | 	dbPath := filepath.Join(app.DataDir(), "auxiliary.db") | 
					
						
							| 
									
										
										
										
											2023-04-05 01:33:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	concurrentDB, err := app.config.DBConnect(dbPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	concurrentDB.DB().SetMaxOpenConns(app.config.AuxMaxOpenConns) | 
					
						
							|  |  |  | 	concurrentDB.DB().SetMaxIdleConns(app.config.AuxMaxIdleConns) | 
					
						
							|  |  |  | 	concurrentDB.DB().SetConnMaxIdleTime(3 * time.Minute) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	nonconcurrentDB, err := app.config.DBConnect(dbPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	nonconcurrentDB.DB().SetMaxOpenConns(1) | 
					
						
							|  |  |  | 	nonconcurrentDB.DB().SetMaxIdleConns(1) | 
					
						
							|  |  |  | 	nonconcurrentDB.DB().SetConnMaxIdleTime(3 * time.Minute) | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	app.auxConcurrentDB = concurrentDB | 
					
						
							|  |  |  | 	app.auxNonconcurrentDB = nonconcurrentDB | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2022-07-07 05:19:05 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func (app *BaseApp) registerBaseHooks() { | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 	deletePrefix := func(prefix string) error { | 
					
						
							|  |  |  | 		fs, err := app.NewFilesystem() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer fs.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		failed := fs.DeletePrefix(prefix) | 
					
						
							|  |  |  | 		if len(failed) > 0 { | 
					
						
							| 
									
										
										
										
											2023-01-12 21:20:51 +08:00
										 |  |  | 			return errors.New("failed to delete the files at " + prefix) | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-12 21:20:51 +08:00
										 |  |  | 	// try to delete the storage files from deleted Collection, Records, etc. model
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	app.OnModelAfterDeleteSuccess().Bind(&hook.Handler[*ModelEvent]{ | 
					
						
							|  |  |  | 		Id: "__pbFilesManagerDelete__", | 
					
						
							|  |  |  | 		Func: func(e *ModelEvent) error { | 
					
						
							|  |  |  | 			if m, ok := e.Model.(FilesManager); ok && m.BaseFilesPath() != "" { | 
					
						
							|  |  |  | 				// ensure that there is a trailing slash so that the list iterator could start walking from the prefix dir
 | 
					
						
							|  |  |  | 				// (https://github.com/pocketbase/pocketbase/discussions/5246#discussioncomment-10128955)
 | 
					
						
							|  |  |  | 				prefix := strings.TrimRight(m.BaseFilesPath(), "/") + "/" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// run in the background for "optimistic" delete to avoid
 | 
					
						
							|  |  |  | 				// blocking the delete transaction
 | 
					
						
							|  |  |  | 				routine.FireAndForget(func() { | 
					
						
							|  |  |  | 					if err := deletePrefix(prefix); err != nil { | 
					
						
							|  |  |  | 						app.Logger().Error( | 
					
						
							|  |  |  | 							"Failed to delete storage prefix (non critical error; usually could happen because of S3 api limits)", | 
					
						
							|  |  |  | 							slog.String("prefix", prefix), | 
					
						
							|  |  |  | 							slog.String("error", err.Error()), | 
					
						
							|  |  |  | 						) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			return e.Next() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Priority: -99, | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	app.OnServe().Bind(&hook.Handler[*ServeEvent]{ | 
					
						
							|  |  |  | 		Id: "__pbCronStart__", | 
					
						
							|  |  |  | 		Func: func(e *ServeEvent) error { | 
					
						
							|  |  |  | 			app.Cron().Start() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return e.Next() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Priority: 999, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-04-25 15:05:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-17 20:26:42 +08:00
										 |  |  | 	app.Cron().Add("__pbDBOptimize__", "0 0 * * *", func() { | 
					
						
							|  |  |  | 		_, execErr := app.NonconcurrentDB().NewQuery("PRAGMA wal_checkpoint(TRUNCATE)").Execute() | 
					
						
							|  |  |  | 		if execErr != nil { | 
					
						
							|  |  |  | 			app.Logger().Warn("Failed to run periodic PRAGMA wal_checkpoint for the main DB", slog.String("error", execErr.Error())) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_, execErr = app.AuxNonconcurrentDB().NewQuery("PRAGMA wal_checkpoint(TRUNCATE)").Execute() | 
					
						
							|  |  |  | 		if execErr != nil { | 
					
						
							|  |  |  | 			app.Logger().Warn("Failed to run periodic PRAGMA wal_checkpoint for the auxiliary DB", slog.String("error", execErr.Error())) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_, execErr = app.DB().NewQuery("PRAGMA optimize").Execute() | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		if execErr != nil { | 
					
						
							|  |  |  | 			app.Logger().Warn("Failed to run periodic PRAGMA optimize", slog.String("error", execErr.Error())) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	app.registerSettingsHooks() | 
					
						
							|  |  |  | 	app.registerAutobackupHooks() | 
					
						
							|  |  |  | 	app.registerCollectionHooks() | 
					
						
							|  |  |  | 	app.registerRecordHooks() | 
					
						
							|  |  |  | 	app.registerSuperuserHooks() | 
					
						
							|  |  |  | 	app.registerExternalAuthHooks() | 
					
						
							|  |  |  | 	app.registerMFAHooks() | 
					
						
							|  |  |  | 	app.registerOTPHooks() | 
					
						
							|  |  |  | 	app.registerAuthOriginHooks() | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 22:39:35 +08:00
										 |  |  | // getLoggerMinLevel returns the logger min level based on the
 | 
					
						
							|  |  |  | // app configurations (dev mode, settings, etc.).
 | 
					
						
							| 
									
										
										
										
											2024-02-27 00:28:10 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2024-02-26 22:39:35 +08:00
										 |  |  | // If not in dev mode - returns the level from the app settings.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If the app is in dev mode it returns -9999 level allowing to print
 | 
					
						
							|  |  |  | // practically all logs to the terminal.
 | 
					
						
							|  |  |  | // In this case DB logs are still filtered but the checks for the min level are done
 | 
					
						
							|  |  |  | // in the BatchOptions.BeforeAddFunc instead of the slog.Handler.Enabled() method.
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | func getLoggerMinLevel(app App) slog.Level { | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 	var minLevel slog.Level | 
					
						
							| 
									
										
										
										
											2024-02-26 22:39:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 	if app.IsDev() { | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		minLevel = -99999 | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 	} else if app.Settings() != nil { | 
					
						
							|  |  |  | 		minLevel = slog.Level(app.Settings().Logs.MinLevel) | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 22:39:35 +08:00
										 |  |  | 	return minLevel | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (app *BaseApp) initLogger() error { | 
					
						
							|  |  |  | 	duration := 3 * time.Second | 
					
						
							|  |  |  | 	ticker := time.NewTicker(duration) | 
					
						
							|  |  |  | 	done := make(chan bool) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	handler := logger.NewBatchHandler(logger.BatchOptions{ | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 		Level:     getLoggerMinLevel(app), | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 		BatchSize: 200, | 
					
						
							|  |  |  | 		BeforeAddFunc: func(ctx context.Context, log *logger.Log) bool { | 
					
						
							| 
									
										
										
										
											2023-12-16 21:41:12 +08:00
										 |  |  | 			if app.IsDev() { | 
					
						
							|  |  |  | 				printLog(log) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// manually check the log level and skip if necessary
 | 
					
						
							|  |  |  | 				if log.Level < slog.Level(app.Settings().Logs.MinLevel) { | 
					
						
							|  |  |  | 					return false | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 			ticker.Reset(duration) | 
					
						
							| 
									
										
										
										
											2023-12-10 18:30:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return app.Settings().Logs.MaxDays > 0 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		WriteFunc: func(ctx context.Context, logs []*logger.Log) error { | 
					
						
							| 
									
										
										
										
											2023-12-10 18:30:55 +08:00
										 |  |  | 			if !app.IsBootstrapped() || app.Settings().Logs.MaxDays == 0 { | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// write the accumulated logs
 | 
					
						
							|  |  |  | 			// (note: based on several local tests there is no significant performance difference between small number of separate write queries vs 1 big INSERT)
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			app.AuxRunInTransaction(func(txApp App) error { | 
					
						
							|  |  |  | 				model := &Log{} | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 				for _, l := range logs { | 
					
						
							|  |  |  | 					model.MarkAsNew() | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 					model.Id = GenerateDefaultRandomId() | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 					model.Level = int(l.Level) | 
					
						
							|  |  |  | 					model.Message = l.Message | 
					
						
							|  |  |  | 					model.Data = l.Data | 
					
						
							|  |  |  | 					model.Created, _ = types.ParseDateTime(l.Time) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 					if err := txApp.AuxSave(model); err != nil { | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 						log.Println("Failed to write log", model, err) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2023-12-10 18:13:37 +08:00
										 |  |  | 		ctx := context.Background() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 		for { | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case <-done: | 
					
						
							| 
									
										
										
										
											2024-03-21 05:47:19 +08:00
										 |  |  | 				return | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 			case <-ticker.C: | 
					
						
							|  |  |  | 				handler.WriteAll(ctx) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	app.logger = slog.New(handler) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 	// write all remaining logs before ticker.Stop to avoid races with ResetBootstrap user calls
 | 
					
						
							|  |  |  | 	app.OnTerminate().Bind(&hook.Handler[*TerminateEvent]{ | 
					
						
							|  |  |  | 		Id: "__pbAppLoggerOnTerminate__", | 
					
						
							|  |  |  | 		Func: func(e *TerminateEvent) error { | 
					
						
							|  |  |  | 			handler.WriteAll(context.Background()) | 
					
						
							| 
									
										
										
										
											2024-03-21 05:47:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			ticker.Stop() | 
					
						
							| 
									
										
										
										
											2024-03-21 05:47:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			done <- true | 
					
						
							| 
									
										
										
										
											2024-03-21 05:47:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-30 00:23:19 +08:00
										 |  |  | 			return e.Next() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Priority: -999, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// reload log handler level (if initialized)
 | 
					
						
							|  |  |  | 	app.OnSettingsReload().Bind(&hook.Handler[*SettingsReloadEvent]{ | 
					
						
							|  |  |  | 		Id: "__pbAppLoggerOnSettingsReload__", | 
					
						
							|  |  |  | 		Func: func(e *SettingsReloadEvent) error { | 
					
						
							|  |  |  | 			err := e.Next() | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if e.App.Logger() != nil { | 
					
						
							|  |  |  | 				if h, ok := e.App.Logger().Handler().(*logger.BatchHandler); ok { | 
					
						
							|  |  |  | 					h.SetLevel(getLoggerMinLevel(e.App)) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// try to clear old logs not matching the new settings
 | 
					
						
							|  |  |  | 			createdBefore := types.NowDateTime().AddDate(0, 0, -1*e.App.Settings().Logs.MaxDays) | 
					
						
							|  |  |  | 			expr := dbx.NewExp("[[created]] <= {:date} OR [[level]] < {:level}", dbx.Params{ | 
					
						
							|  |  |  | 				"date":  createdBefore.String(), | 
					
						
							|  |  |  | 				"level": e.App.Settings().Logs.MinLevel, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			_, err = e.App.AuxNonconcurrentDB().Delete((&Log{}).TableName(), expr).Execute() | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				e.App.Logger().Debug("Failed to cleanup old logs", "error", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// no logs are allowed -> try to reclaim preserved disk space after the previous delete operation
 | 
					
						
							|  |  |  | 			if e.App.Settings().Logs.MaxDays == 0 { | 
					
						
							|  |  |  | 				err = e.App.AuxVacuum() | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					e.App.Logger().Debug("Failed to VACUUM aux database", "error", err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Priority: -999, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// cleanup old logs
 | 
					
						
							|  |  |  | 	app.Cron().Add("__pbLogsCleanup__", "0 */6 * * *", func() { | 
					
						
							|  |  |  | 		deleteErr := app.DeleteOldLogs(time.Now().AddDate(0, 0, -1*app.Settings().Logs.MaxDays)) | 
					
						
							|  |  |  | 		if deleteErr != nil { | 
					
						
							|  |  |  | 			app.Logger().Warn("Failed to delete old logs", "error", deleteErr) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-05-09 02:52:40 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2022-07-18 17:04:27 +08:00
										 |  |  | } |