diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /models/user/external_login_user.go | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to '')
-rw-r--r-- | models/user/external_login_user.go | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/models/user/external_login_user.go b/models/user/external_login_user.go new file mode 100644 index 0000000..965b7a5 --- /dev/null +++ b/models/user/external_login_user.go @@ -0,0 +1,184 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package user + +import ( + "context" + "fmt" + "time" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" + + "xorm.io/builder" +) + +// ErrExternalLoginUserAlreadyExist represents a "ExternalLoginUserAlreadyExist" kind of error. +type ErrExternalLoginUserAlreadyExist struct { + ExternalID string + UserID int64 + LoginSourceID int64 +} + +// IsErrExternalLoginUserAlreadyExist checks if an error is a ExternalLoginUserAlreadyExist. +func IsErrExternalLoginUserAlreadyExist(err error) bool { + _, ok := err.(ErrExternalLoginUserAlreadyExist) + return ok +} + +func (err ErrExternalLoginUserAlreadyExist) Error() string { + return fmt.Sprintf("external login user already exists [externalID: %s, userID: %d, loginSourceID: %d]", err.ExternalID, err.UserID, err.LoginSourceID) +} + +func (err ErrExternalLoginUserAlreadyExist) Unwrap() error { + return util.ErrAlreadyExist +} + +// ErrExternalLoginUserNotExist represents a "ExternalLoginUserNotExist" kind of error. +type ErrExternalLoginUserNotExist struct { + UserID int64 + LoginSourceID int64 +} + +// IsErrExternalLoginUserNotExist checks if an error is a ExternalLoginUserNotExist. +func IsErrExternalLoginUserNotExist(err error) bool { + _, ok := err.(ErrExternalLoginUserNotExist) + return ok +} + +func (err ErrExternalLoginUserNotExist) Error() string { + return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID) +} + +func (err ErrExternalLoginUserNotExist) Unwrap() error { + return util.ErrNotExist +} + +// ExternalLoginUser makes the connecting between some existing user and additional external login sources +type ExternalLoginUser struct { + ExternalID string `xorm:"pk NOT NULL"` + UserID int64 `xorm:"INDEX NOT NULL"` + LoginSourceID int64 `xorm:"pk NOT NULL"` + RawData map[string]any `xorm:"TEXT JSON"` + Provider string `xorm:"index VARCHAR(25)"` + Email string + Name string + FirstName string + LastName string + NickName string + Description string + AvatarURL string `xorm:"TEXT"` + Location string + AccessToken string `xorm:"TEXT"` + AccessTokenSecret string `xorm:"TEXT"` + RefreshToken string `xorm:"TEXT"` + ExpiresAt time.Time +} + +type ExternalUserMigrated interface { + GetExternalName() string + GetExternalID() int64 +} + +type ExternalUserRemappable interface { + GetUserID() int64 + RemapExternalUser(externalName string, externalID, userID int64) error + ExternalUserMigrated +} + +func init() { + db.RegisterModel(new(ExternalLoginUser)) +} + +// GetExternalLogin checks if a externalID in loginSourceID scope already exists +func GetExternalLogin(ctx context.Context, externalLoginUser *ExternalLoginUser) (bool, error) { + return db.GetEngine(ctx).Get(externalLoginUser) +} + +// LinkExternalToUser link the external user to the user +func LinkExternalToUser(ctx context.Context, user *User, externalLoginUser *ExternalLoginUser) error { + has, err := db.Exist[ExternalLoginUser](ctx, builder.Eq{ + "external_id": externalLoginUser.ExternalID, + "login_source_id": externalLoginUser.LoginSourceID, + }) + if err != nil { + return err + } else if has { + return ErrExternalLoginUserAlreadyExist{externalLoginUser.ExternalID, user.ID, externalLoginUser.LoginSourceID} + } + + _, err = db.GetEngine(ctx).Insert(externalLoginUser) + return err +} + +// RemoveAccountLink will remove all external login sources for the given user +func RemoveAccountLink(ctx context.Context, user *User, loginSourceID int64) (int64, error) { + deleted, err := db.GetEngine(ctx).Delete(&ExternalLoginUser{UserID: user.ID, LoginSourceID: loginSourceID}) + if err != nil { + return deleted, err + } + if deleted < 1 { + return deleted, ErrExternalLoginUserNotExist{user.ID, loginSourceID} + } + return deleted, err +} + +// RemoveAllAccountLinks will remove all external login sources for the given user +func RemoveAllAccountLinks(ctx context.Context, user *User) error { + _, err := db.GetEngine(ctx).Delete(&ExternalLoginUser{UserID: user.ID}) + return err +} + +// GetUserIDByExternalUserID get user id according to provider and userID +func GetUserIDByExternalUserID(ctx context.Context, provider, userID string) (int64, error) { + var id int64 + _, err := db.GetEngine(ctx).Table("external_login_user"). + Select("user_id"). + Where("provider=?", provider). + And("external_id=?", userID). + Get(&id) + if err != nil { + return 0, err + } + return id, nil +} + +// UpdateExternalUserByExternalID updates an external user's information +func UpdateExternalUserByExternalID(ctx context.Context, external *ExternalLoginUser) error { + has, err := db.Exist[ExternalLoginUser](ctx, builder.Eq{ + "external_id": external.ExternalID, + "login_source_id": external.LoginSourceID, + }) + if err != nil { + return err + } else if !has { + return ErrExternalLoginUserNotExist{external.UserID, external.LoginSourceID} + } + + _, err = db.GetEngine(ctx).Where("external_id=? AND login_source_id=?", external.ExternalID, external.LoginSourceID).AllCols().Update(external) + return err +} + +// FindExternalUserOptions represents an options to find external users +type FindExternalUserOptions struct { + db.ListOptions + Provider string + UserID int64 + OrderBy string +} + +func (opts FindExternalUserOptions) ToConds() builder.Cond { + cond := builder.NewCond() + if len(opts.Provider) > 0 { + cond = cond.And(builder.Eq{"provider": opts.Provider}) + } + if opts.UserID > 0 { + cond = cond.And(builder.Eq{"user_id": opts.UserID}) + } + return cond +} + +func (opts FindExternalUserOptions) ToOrders() string { + return opts.OrderBy +} |