Skip to content

Latest commit

 

History

History
684 lines (620 loc) · 25.8 KB

CHANGELOG.md

File metadata and controls

684 lines (620 loc) · 25.8 KB

(WIP) v0.9.0

  • Changes to the mailer.Mailer interface (minor breaking if you are sending custom emails):

    // Old:
    app.NewMailClient().Send(from, to, subject, html, attachments?)
    
    // New:
    app.NewMailClient().Send(&mailer.Message{
      From: from,
      To: to,
      Subject: subject,
      HTML: html,
      Attachments: attachments,
      // new configurable fields
      Bcc: []string{"[email protected]", "[email protected]"},
      Cc: []string{"[email protected]", "[email protected]"},
      Headers: map[string]string{"Custom-Header": "test"},
      Text: "custom plain text version",
    })
  • Added the new *mailer.Message to the MailerRecordEvent, MailerAdminEvent event structs.

v0.8.0

⚠️ This release contains breaking changes and requires some manual migration steps!

The biggest change is the merge of the User models and the profiles collection per #376. There is no longer user type field and the users are just an "auth" collection (we now support collection types, currently only "base" and "auth"). This should simplify the users management and at the same time allow us to have unlimited multiple "auth" collections each with their own custom fields and authentication options (eg. staff, client, etc.).

In addition to the Users and profiles merge, this release comes with several other improvements:

  • Added indirect expand support #312.

  • The json field type now supports filtering and sorting #423.

  • The relation field now allows unlimitted maxSelect (aka. without upper limit).

  • Added support for combined email/username + password authentication (see below authWithPassword()).

  • Added support for full "manager-subordinate" users management, including a special API rule to allow directly changing system fields like email, password, etc. without requiring oldPassword or other user verification.

  • Enabled OAuth2 account linking on authorized request from the same auth collection (this is useful for example if the OAuth2 provider doesn't return an email and you want to associate it with the current logged in user).

  • Added option to toggle the record columns visibility from the table listing.

  • Added support for collection schema fields reordering.

  • Added several new OAuth2 providers (Microsoft Azure AD, Spotify, Twitch, Kakao).

  • Improved memory usage on large file uploads #835.

  • More detailed API preview docs and site documentation (the repo is located at https://github.com/pocketbase/site).

  • Other minor performance improvements (mostly related to the search apis).

Migrate from v0.7.x

Data

The merge of users and profiles comes with several required db changes. The easiest way to apply them is to use the new temporary upgrade command:

# make sure to have a copy of your pb_data in case something fails
cp -r ./pb_data ./pb_data_backup

# run the upgrade command
./pocketbase08 upgrade

# start the application as usual
./pocketbase08 serve

The upgrade command:

  • Creates a new users collection with merged fields from the _users table and the profiles collection. The new user records will have the ids from the profiles collection.
  • Changes all user type fields to relation and update the references to point to the new user ids.
  • Renames all @collection.profiles.*, @request.user.* and @request.user.profile.* filters to @collection.users.* and @request.auth.*.
  • Appends 2 to all schema field names and api filter rules that conflicts with the new system reserved ones:
    collectionId   => collectionId2
    collectionName => collectionName2
    expand         => expand2
    
    // only for the "profiles" collection fields:
    username               => username2
    email                  => email2
    emailVisibility        => emailVisibility2
    verified               => verified2
    tokenKey               => tokenKey2
    passwordHash           => passwordHash2
    lastResetSentAt        => lastResetSentAt2
    lastVerificationSentAt => lastVerificationSentAt2
    

SDKs

Please check the individual SDK package changelog and apply the necessary changes in your code:

API

You don't have to read this if you are using an official SDK.

  • The authorization schema is no longer necessary. Now it is auto detected from the JWT token payload:

    Old New
    Authorization: Admin TOKEN Authorization: TOKEN
    Authorization: User TOKEN Authorization: TOKEN
  • All datetime stings are now returned in ISO8601 format - with Z suffix and space as separator between the date and time part:

    Old New
    2022-01-02 03:04:05.678 2022-01-02 03:04:05.678Z
  • Removed the @ prefix from the system record fields for easier json parsing:

    Old New
    @collectionId collectionId
    @collectionName collectionName
    @expand expand
  • All users api handlers are moved under /api/collections/:collection/:

    Old New
    GET /api/users/auth-methods GET /api/collections/:collection/auth-methods
    POST /api/users/refresh POST /api/collections/:collection/auth-refresh
    POST /api/users/auth-via-oauth2 POST /api/collections/:collection/auth-with-oauth2
    You can now also pass optional createData object on OAuth2 sign-up.
    Also please note that now required user/profile fields are properly validated when creating new auth model on OAuth2 sign-up.
    POST /api/users/auth-via-email POST /api/collections/:collection/auth-with-password
    Handles username/email + password authentication.
    {"identity": "usernameOrEmail", "password": "123456"}
    POST /api/users/request-password-reset POST /api/collections/:collection/request-password-reset
    POST /api/users/confirm-password-reset POST /api/collections/:collection/confirm-password-reset
    POST /api/users/request-verification POST /api/collections/:collection/request-verification
    POST /api/users/confirm-verification POST /api/collections/:collection/confirm-verification
    POST /api/users/request-email-change POST /api/collections/:collection/request-email-change
    POST /api/users/confirm-email-change POST /api/collections/:collection/confirm-email-change
    GET /api/users GET /api/collections/:collection/records
    GET /api/users/:id GET /api/collections/:collection/records/:id
    POST /api/users POST /api/collections/:collection/records
    PATCH /api/users/:id PATCH /api/collections/:collection/records/:id
    DELETE /api/users/:id DELETE /api/collections/:collection/records/:id
    GET /api/users/:id/external-auths GET /api/collections/:collection/records/:id/external-auths
    DELETE /api/users/:id/external-auths/:provider DELETE /api/collections/:collection/records/:id/external-auths/:provider

    In relation to the above changes, the user property in the auth response is renamed to record.

  • The admins api was also updated for consistency with the users api changes:

    Old New
    POST /api/admins/refresh POST /api/admins/auth-refresh
    POST /api/admins/auth-via-email POST /api/admins/auth-with-password
    {"identity": "[email protected]", "password": "123456"}
    (notice that the email body field was renamed to identity)
  • To prevent confusion with the auth method responses, the following endpoints now returns 204 with empty body (previously 200 with token and auth model):

    POST /api/admins/confirm-password-reset
    POST /api/collections/:collection/confirm-password-reset
    POST /api/collections/:collection/confirm-verification
    POST /api/collections/:collection/confirm-email-change
    
  • Renamed the "user" related settings fields returned by GET /api/settings:

    Old New
    userAuthToken recordAuthToken
    userPasswordResetToken recordPasswordResetToken
    userEmailChangeToken recordEmailChangeToken
    userVerificationToken recordVerificationToken

Internals

You don't have to read this if you are not using PocketBase as framework.

  • Removed forms.New*WithConfig() factories to minimize ambiguities. If you need to pass a transaction Dao you can use the new SetDao(dao) method available to the form instances.

  • forms.RecordUpsert.LoadData(data map[string]any) now can bulk load external data from a map. To load data from a request instance, you could use forms.RecordUpsert.LoadRequest(r, optKeysPrefix = "").

  • schema.RelationOptions.MaxSelect has new type *int (you can use the new types.Pointer(123) helper to assign pointer values).

  • Renamed the constant apis.ContextUserKey ("user") to apis.ContextAuthRecordKey ("authRecord").

  • Replaced user related middlewares with their auth record alternative:

    Old New
    apis.RequireUserAuth() apis.RequireRecordAuth(optCollectionNames ...string)
    apis.RequireAdminOrUserAuth() apis.RequireAdminOrRecordAuth(optCollectionNames ...string)
    N/A RequireSameContextRecordAuth()
    (requires the auth record to be from the same context collection)
  • The following record Dao helpers now uses the collection id or name instead of *models.Collection instance to reduce the verbosity when fetching records:

    Old New
    dao.FindRecordById(collection, ...) dao.FindRecordById(collectionNameOrId, ...)
    dao.FindRecordsByIds(collection, ...) dao.FindRecordsByIds(collectionNameOrId, ...)
    dao.FindRecordsByExpr(collection, ...) dao.FindRecordsByExpr(collectionNameOrId, ...)
    dao.FindFirstRecordByData(collection, ...) dao.FindFirstRecordByData(collectionNameOrId, ...)
    dao.IsRecordValueUnique(collection, ...) dao.IsRecordValueUnique(collectionNameOrId, ...)
  • Replaced all User related Dao helpers with Record equivalents:

    Old New
    dao.UserQuery() dao.RecordQuery(collection)
    dao.FindUserById(id) dao.FindRecordById(collectionNameOrId, id)
    dao.FindUserByToken(token, baseKey) dao.FindAuthRecordByToken(token, baseKey)
    dao.FindUserByEmail(email) dao.FindAuthRecordByEmail(collectionNameOrId, email)
    N/A dao.FindAuthRecordByUsername(collectionNameOrId, username)
  • Moved the formatted ApiError struct and factories to the github.com/pocketbase/pocketbase/apis subpackage:

    Old New
    Import path
    github.com/pocketbase/pocketbase/tools/rest github.com/pocketbase/pocketbase/apis
    Fields
    rest.ApiError{} apis.ApiError{}
    rest.NewNotFoundError() apis.NewNotFoundError()
    rest.NewBadRequestError() apis.NewBadRequestError()
    rest.NewForbiddenError() apis.NewForbiddenError()
    rest.NewUnauthorizedError() apis.NewUnauthorizedError()
    rest.NewApiError() apis.NewApiError()
  • Renamed models.Record helper getters:

    Old New
    SetDataValue Set
    GetDataValue Get
    GetBoolDataValue GetBool
    GetStringDataValue GetString
    GetIntDataValue GetInt
    GetFloatDataValue GetFloat
    GetTimeDataValue GetTime
    GetDateTimeDataValue GetDateTime
    GetStringSliceDataValue GetStringSlice
  • Added new auth collection models.Record helpers:

    func (m *Record) Username() string
    func (m *Record) SetUsername(username string) error
    func (m *Record) Email() string
    func (m *Record) SetEmail(email string) error
    func (m *Record) EmailVisibility() bool
    func (m *Record) SetEmailVisibility(visible bool) error
    func (m *Record) IgnoreEmailVisibility(state bool)
    func (m *Record) Verified() bool
    func (m *Record) SetVerified(verified bool) error
    func (m *Record) TokenKey() string
    func (m *Record) SetTokenKey(key string) error
    func (m *Record) RefreshTokenKey() error
    func (m *Record) LastResetSentAt() types.DateTime
    func (m *Record) SetLastResetSentAt(dateTime types.DateTime) error
    func (m *Record) LastVerificationSentAt() types.DateTime
    func (m *Record) SetLastVerificationSentAt(dateTime types.DateTime) error
    func (m *Record) ValidatePassword(password string) bool
    func (m *Record) SetPassword(password string) error
  • Added option to return serialized custom models.Record fields data:

    func (m *Record) UnknownData() map[string]any
    func (m *Record) WithUnkownData(state bool)
  • Deleted model.User. Now the user data is stored as an auth models.Record.

    Old New
    User.Email Record.Email()
    User.TokenKey Record.TokenKey()
    User.Verified Record.Verified()
    User.SetPassword() Record.SetPassword()
    User.RefreshTokenKey() Record.RefreshTokenKey()
    etc.
  • Replaced User related event hooks with their Record alternative:

    Old New
    OnMailerBeforeUserResetPasswordSend() *hook.Hook[*MailerUserEvent] OnMailerBeforeRecordResetPasswordSend() *hook.Hook[*MailerRecordEvent]
    OnMailerAfterUserResetPasswordSend() *hook.Hook[*MailerUserEvent] OnMailerAfterRecordResetPasswordSend() *hook.Hook[*MailerRecordEvent]
    OnMailerBeforeUserVerificationSend() *hook.Hook[*MailerUserEvent] OnMailerBeforeRecordVerificationSend() *hook.Hook[*MailerRecordEvent]
    OnMailerAfterUserVerificationSend() *hook.Hook[*MailerUserEvent] OnMailerAfterRecordVerificationSend() *hook.Hook[*MailerRecordEvent]
    OnMailerBeforeUserChangeEmailSend() *hook.Hook[*MailerUserEvent] OnMailerBeforeRecordChangeEmailSend() *hook.Hook[*MailerRecordEvent]
    OnMailerAfterUserChangeEmailSend() *hook.Hook[*MailerUserEvent] OnMailerAfterRecordChangeEmailSend() *hook.Hook[*MailerRecordEvent]
    OnUsersListRequest() *hook.Hook[*UserListEvent] OnRecordsListRequest() *hook.Hook[*RecordsListEvent]
    OnUserViewRequest() *hook.Hook[*UserViewEvent] OnRecordViewRequest() *hook.Hook[*RecordViewEvent]
    OnUserBeforeCreateRequest() *hook.Hook[*UserCreateEvent] OnRecordBeforeCreateRequest() *hook.Hook[*RecordCreateEvent]
    OnUserAfterCreateRequest() *hook.Hook[*UserCreateEvent] OnRecordAfterCreateRequest() *hook.Hook[*RecordCreateEvent]
    OnUserBeforeUpdateRequest() *hook.Hook[*UserUpdateEvent] OnRecordBeforeUpdateRequest() *hook.Hook[*RecordUpdateEvent]
    OnUserAfterUpdateRequest() *hook.Hook[*UserUpdateEvent] OnRecordAfterUpdateRequest() *hook.Hook[*RecordUpdateEvent]
    OnUserBeforeDeleteRequest() *hook.Hook[*UserDeleteEvent] OnRecordBeforeDeleteRequest() *hook.Hook[*RecordDeleteEvent]
    OnUserAfterDeleteRequest() *hook.Hook[*UserDeleteEvent] OnRecordAfterDeleteRequest() *hook.Hook[*RecordDeleteEvent]
    OnUserAuthRequest() *hook.Hook[*UserAuthEvent] OnRecordAuthRequest() *hook.Hook[*RecordAuthEvent]
    OnUserListExternalAuths() *hook.Hook[*UserListExternalAuthsEvent] OnRecordListExternalAuths() *hook.Hook[*RecordListExternalAuthsEvent]
    OnUserBeforeUnlinkExternalAuthRequest() *hook.Hook[*UserUnlinkExternalAuthEvent] OnRecordBeforeUnlinkExternalAuthRequest() *hook.Hook[*RecordUnlinkExternalAuthEvent]
    OnUserAfterUnlinkExternalAuthRequest() *hook.Hook[*UserUnlinkExternalAuthEvent] OnRecordAfterUnlinkExternalAuthRequest() *hook.Hook[*RecordUnlinkExternalAuthEvent]
  • Replaced forms.UserEmailLogin{} with forms.RecordPasswordLogin{} (for both username and email depending on which is enabled for the collection).

  • Renamed user related core.Settings fields:

    Old New
    core.Settings.UserAuthToken{} core.Settings.RecordAuthToken{}
    core.Settings.UserPasswordResetToken{} core.Settings.RecordPasswordResetToken{}
    core.Settings.UserEmailChangeToken{} core.Settings.RecordEmailChangeToken{}
    core.Settings.UserVerificationToken{} core.Settings.RecordVerificationToken{}
  • Marked as "Deprecated" and will be removed in v0.9:

    core.Settings.EmailAuth{}
    core.EmailAuthConfig{}
    schema.FieldTypeUser
    schema.UserOptions{}
    
  • The second argument of apis.StaticDirectoryHandler(fileSystem, enableIndexFallback) now is used to enable/disable index.html forwarding on missing file (eg. in case of SPA).