code.gitea.io/gitea@v1.22.3/models/user/user.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // Copyright 2019 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package user
     6  
     7  import (
     8  	"context"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"net/url"
    12  	"path/filepath"
    13  	"regexp"
    14  	"strings"
    15  	"time"
    16  	"unicode"
    17  
    18  	_ "image/jpeg" // Needed for jpeg support
    19  
    20  	"code.gitea.io/gitea/models/auth"
    21  	"code.gitea.io/gitea/models/db"
    22  	"code.gitea.io/gitea/modules/auth/openid"
    23  	"code.gitea.io/gitea/modules/auth/password/hash"
    24  	"code.gitea.io/gitea/modules/base"
    25  	"code.gitea.io/gitea/modules/container"
    26  	"code.gitea.io/gitea/modules/git"
    27  	"code.gitea.io/gitea/modules/log"
    28  	"code.gitea.io/gitea/modules/optional"
    29  	"code.gitea.io/gitea/modules/setting"
    30  	"code.gitea.io/gitea/modules/structs"
    31  	"code.gitea.io/gitea/modules/timeutil"
    32  	"code.gitea.io/gitea/modules/util"
    33  	"code.gitea.io/gitea/modules/validation"
    34  
    35  	"golang.org/x/text/runes"
    36  	"golang.org/x/text/transform"
    37  	"golang.org/x/text/unicode/norm"
    38  	"xorm.io/builder"
    39  )
    40  
    41  // UserType defines the user type
    42  type UserType int //revive:disable-line:exported
    43  
    44  const (
    45  	// UserTypeIndividual defines an individual user
    46  	UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
    47  
    48  	// UserTypeOrganization defines an organization
    49  	UserTypeOrganization
    50  
    51  	// UserTypeUserReserved reserves a (non-existing) user, i.e. to prevent a spam user from re-registering after being deleted, or to reserve the name until the user is actually created later on
    52  	UserTypeUserReserved
    53  
    54  	// UserTypeOrganizationReserved reserves a (non-existing) organization, to be used in combination with UserTypeUserReserved
    55  	UserTypeOrganizationReserved
    56  
    57  	// UserTypeBot defines a bot user
    58  	UserTypeBot
    59  
    60  	// UserTypeRemoteUser defines a remote user for federated users
    61  	UserTypeRemoteUser
    62  )
    63  
    64  const (
    65  	// EmailNotificationsEnabled indicates that the user would like to receive all email notifications except your own
    66  	EmailNotificationsEnabled = "enabled"
    67  	// EmailNotificationsOnMention indicates that the user would like to be notified via email when mentioned.
    68  	EmailNotificationsOnMention = "onmention"
    69  	// EmailNotificationsDisabled indicates that the user would not like to be notified via email.
    70  	EmailNotificationsDisabled = "disabled"
    71  	// EmailNotificationsAndYourOwn indicates that the user would like to receive all email notifications and your own
    72  	EmailNotificationsAndYourOwn = "andyourown"
    73  )
    74  
    75  // User represents the object of individual and member of organization.
    76  type User struct {
    77  	ID        int64  `xorm:"pk autoincr"`
    78  	LowerName string `xorm:"UNIQUE NOT NULL"`
    79  	Name      string `xorm:"UNIQUE NOT NULL"`
    80  	FullName  string
    81  	// Email is the primary email address (to be used for communication)
    82  	Email                        string `xorm:"NOT NULL"`
    83  	KeepEmailPrivate             bool
    84  	EmailNotificationsPreference string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'enabled'"`
    85  	Passwd                       string `xorm:"NOT NULL"`
    86  	PasswdHashAlgo               string `xorm:"NOT NULL DEFAULT 'argon2'"`
    87  
    88  	// MustChangePassword is an attribute that determines if a user
    89  	// is to change their password after registration.
    90  	MustChangePassword bool `xorm:"NOT NULL DEFAULT false"`
    91  
    92  	LoginType   auth.Type
    93  	LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
    94  	LoginName   string
    95  	Type        UserType
    96  	Location    string
    97  	Website     string
    98  	Rands       string `xorm:"VARCHAR(32)"`
    99  	Salt        string `xorm:"VARCHAR(32)"`
   100  	Language    string `xorm:"VARCHAR(5)"`
   101  	Description string
   102  
   103  	CreatedUnix   timeutil.TimeStamp `xorm:"INDEX created"`
   104  	UpdatedUnix   timeutil.TimeStamp `xorm:"INDEX updated"`
   105  	LastLoginUnix timeutil.TimeStamp `xorm:"INDEX"`
   106  
   107  	// Remember visibility choice for convenience, true for private
   108  	LastRepoVisibility bool
   109  	// Maximum repository creation limit, -1 means use global default
   110  	MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
   111  
   112  	// IsActive true: primary email is activated, user can access Web UI and Git SSH.
   113  	// false: an inactive user can only log in Web UI for account operations (ex: activate the account by email), no other access.
   114  	IsActive bool `xorm:"INDEX"`
   115  	// the user is a Gitea admin, who can access all repositories and the admin pages.
   116  	IsAdmin bool
   117  	// true: the user is only allowed to see organizations/repositories that they has explicit rights to.
   118  	// (ex: in private Gitea instances user won't be allowed to see even organizations/repositories that are set as public)
   119  	IsRestricted bool `xorm:"NOT NULL DEFAULT false"`
   120  
   121  	AllowGitHook            bool
   122  	AllowImportLocal        bool // Allow migrate repository by local path
   123  	AllowCreateOrganization bool `xorm:"DEFAULT true"`
   124  
   125  	// true: the user is not allowed to log in Web UI. Git/SSH access could still be allowed (please refer to Git/SSH access related code/documents)
   126  	ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"`
   127  
   128  	// Avatar
   129  	Avatar          string `xorm:"VARCHAR(2048) NOT NULL"`
   130  	AvatarEmail     string `xorm:"NOT NULL"`
   131  	UseCustomAvatar bool
   132  
   133  	// Counters
   134  	NumFollowers int
   135  	NumFollowing int `xorm:"NOT NULL DEFAULT 0"`
   136  	NumStars     int
   137  	NumRepos     int
   138  
   139  	// For organization
   140  	NumTeams                  int
   141  	NumMembers                int
   142  	Visibility                structs.VisibleType `xorm:"NOT NULL DEFAULT 0"`
   143  	RepoAdminChangeTeamAccess bool                `xorm:"NOT NULL DEFAULT false"`
   144  
   145  	// Preferences
   146  	DiffViewStyle       string `xorm:"NOT NULL DEFAULT ''"`
   147  	Theme               string `xorm:"NOT NULL DEFAULT ''"`
   148  	KeepActivityPrivate bool   `xorm:"NOT NULL DEFAULT false"`
   149  }
   150  
   151  func init() {
   152  	db.RegisterModel(new(User))
   153  }
   154  
   155  // SearchOrganizationsOptions options to filter organizations
   156  type SearchOrganizationsOptions struct {
   157  	db.ListOptions
   158  	All bool
   159  }
   160  
   161  func (u *User) LogString() string {
   162  	if u == nil {
   163  		return "<User nil>"
   164  	}
   165  	return fmt.Sprintf("<User %d:%s>", u.ID, u.Name)
   166  }
   167  
   168  // BeforeUpdate is invoked from XORM before updating this object.
   169  func (u *User) BeforeUpdate() {
   170  	if u.MaxRepoCreation < -1 {
   171  		u.MaxRepoCreation = -1
   172  	}
   173  
   174  	// Organization does not need email
   175  	u.Email = strings.ToLower(u.Email)
   176  	if !u.IsOrganization() {
   177  		if len(u.AvatarEmail) == 0 {
   178  			u.AvatarEmail = u.Email
   179  		}
   180  	}
   181  
   182  	u.LowerName = strings.ToLower(u.Name)
   183  	u.Location = base.TruncateString(u.Location, 255)
   184  	u.Website = base.TruncateString(u.Website, 255)
   185  	u.Description = base.TruncateString(u.Description, 255)
   186  }
   187  
   188  // AfterLoad is invoked from XORM after filling all the fields of this object.
   189  func (u *User) AfterLoad() {
   190  	if u.Theme == "" {
   191  		u.Theme = setting.UI.DefaultTheme
   192  	}
   193  }
   194  
   195  // SetLastLogin set time to last login
   196  func (u *User) SetLastLogin() {
   197  	u.LastLoginUnix = timeutil.TimeStampNow()
   198  }
   199  
   200  // GetPlaceholderEmail returns an noreply email
   201  func (u *User) GetPlaceholderEmail() string {
   202  	return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
   203  }
   204  
   205  // GetEmail returns an noreply email, if the user has set to keep his
   206  // email address private, otherwise the primary email address.
   207  func (u *User) GetEmail() string {
   208  	if u.KeepEmailPrivate {
   209  		return u.GetPlaceholderEmail()
   210  	}
   211  	return u.Email
   212  }
   213  
   214  // GetAllUsers returns a slice of all individual users found in DB.
   215  func GetAllUsers(ctx context.Context) ([]*User, error) {
   216  	users := make([]*User, 0)
   217  	return users, db.GetEngine(ctx).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users)
   218  }
   219  
   220  // IsLocal returns true if user login type is LoginPlain.
   221  func (u *User) IsLocal() bool {
   222  	return u.LoginType <= auth.Plain
   223  }
   224  
   225  // IsOAuth2 returns true if user login type is LoginOAuth2.
   226  func (u *User) IsOAuth2() bool {
   227  	return u.LoginType == auth.OAuth2
   228  }
   229  
   230  // MaxCreationLimit returns the number of repositories a user is allowed to create
   231  func (u *User) MaxCreationLimit() int {
   232  	if u.MaxRepoCreation <= -1 {
   233  		return setting.Repository.MaxCreationLimit
   234  	}
   235  	return u.MaxRepoCreation
   236  }
   237  
   238  // CanCreateRepo returns if user login can create a repository
   239  // NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
   240  func (u *User) CanCreateRepo() bool {
   241  	if u.IsAdmin {
   242  		return true
   243  	}
   244  	if u.MaxRepoCreation <= -1 {
   245  		if setting.Repository.MaxCreationLimit <= -1 {
   246  			return true
   247  		}
   248  		return u.NumRepos < setting.Repository.MaxCreationLimit
   249  	}
   250  	return u.NumRepos < u.MaxRepoCreation
   251  }
   252  
   253  // CanCreateOrganization returns true if user can create organisation.
   254  func (u *User) CanCreateOrganization() bool {
   255  	return u.IsAdmin || (u.AllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation)
   256  }
   257  
   258  // CanEditGitHook returns true if user can edit Git hooks.
   259  func (u *User) CanEditGitHook() bool {
   260  	return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
   261  }
   262  
   263  // CanForkRepo returns if user login can fork a repository
   264  // It checks especially that the user can create repos, and potentially more
   265  func (u *User) CanForkRepo() bool {
   266  	if setting.Repository.AllowForkWithoutMaximumLimit {
   267  		return true
   268  	}
   269  	return u.CanCreateRepo()
   270  }
   271  
   272  // CanImportLocal returns true if user can migrate repository by local path.
   273  func (u *User) CanImportLocal() bool {
   274  	if !setting.ImportLocalPaths || u == nil {
   275  		return false
   276  	}
   277  	return u.IsAdmin || u.AllowImportLocal
   278  }
   279  
   280  // DashboardLink returns the user dashboard page link.
   281  func (u *User) DashboardLink() string {
   282  	if u.IsOrganization() {
   283  		return u.OrganisationLink() + "/dashboard"
   284  	}
   285  	return setting.AppSubURL + "/"
   286  }
   287  
   288  // HomeLink returns the user or organization home page link.
   289  func (u *User) HomeLink() string {
   290  	return setting.AppSubURL + "/" + url.PathEscape(u.Name)
   291  }
   292  
   293  // HTMLURL returns the user or organization's full link.
   294  func (u *User) HTMLURL() string {
   295  	return setting.AppURL + url.PathEscape(u.Name)
   296  }
   297  
   298  // OrganisationLink returns the organization sub page link.
   299  func (u *User) OrganisationLink() string {
   300  	return setting.AppSubURL + "/org/" + url.PathEscape(u.Name)
   301  }
   302  
   303  // GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
   304  func (u *User) GenerateEmailActivateCode(email string) string {
   305  	code := base.CreateTimeLimitCode(
   306  		fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
   307  		setting.Service.ActiveCodeLives, time.Now(), nil)
   308  
   309  	// Add tail hex username
   310  	code += hex.EncodeToString([]byte(u.LowerName))
   311  	return code
   312  }
   313  
   314  // GetUserFollowers returns range of user's followers.
   315  func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
   316  	sess := db.GetEngine(ctx).
   317  		Select("`user`.*").
   318  		Join("LEFT", "follow", "`user`.id=follow.user_id").
   319  		Where("follow.follow_id=?", u.ID).
   320  		And("`user`.type=?", UserTypeIndividual).
   321  		And(isUserVisibleToViewerCond(viewer))
   322  
   323  	if listOptions.Page != 0 {
   324  		sess = db.SetSessionPagination(sess, &listOptions)
   325  
   326  		users := make([]*User, 0, listOptions.PageSize)
   327  		count, err := sess.FindAndCount(&users)
   328  		return users, count, err
   329  	}
   330  
   331  	users := make([]*User, 0, 8)
   332  	count, err := sess.FindAndCount(&users)
   333  	return users, count, err
   334  }
   335  
   336  // GetUserFollowing returns range of user's following.
   337  func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
   338  	sess := db.GetEngine(ctx).
   339  		Select("`user`.*").
   340  		Join("LEFT", "follow", "`user`.id=follow.follow_id").
   341  		Where("follow.user_id=?", u.ID).
   342  		And("`user`.type IN (?, ?)", UserTypeIndividual, UserTypeOrganization).
   343  		And(isUserVisibleToViewerCond(viewer))
   344  
   345  	if listOptions.Page != 0 {
   346  		sess = db.SetSessionPagination(sess, &listOptions)
   347  
   348  		users := make([]*User, 0, listOptions.PageSize)
   349  		count, err := sess.FindAndCount(&users)
   350  		return users, count, err
   351  	}
   352  
   353  	users := make([]*User, 0, 8)
   354  	count, err := sess.FindAndCount(&users)
   355  	return users, count, err
   356  }
   357  
   358  // NewGitSig generates and returns the signature of given user.
   359  func (u *User) NewGitSig() *git.Signature {
   360  	return &git.Signature{
   361  		Name:  u.GitName(),
   362  		Email: u.GetEmail(),
   363  		When:  time.Now(),
   364  	}
   365  }
   366  
   367  // SetPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO
   368  // change passwd, salt and passwd_hash_algo fields
   369  func (u *User) SetPassword(passwd string) (err error) {
   370  	if u.Salt, err = GetUserSalt(); err != nil {
   371  		return err
   372  	}
   373  	if u.Passwd, err = hash.Parse(setting.PasswordHashAlgo).Hash(passwd, u.Salt); err != nil {
   374  		return err
   375  	}
   376  	u.PasswdHashAlgo = setting.PasswordHashAlgo
   377  
   378  	return nil
   379  }
   380  
   381  // ValidatePassword checks if the given password matches the one belonging to the user.
   382  func (u *User) ValidatePassword(passwd string) bool {
   383  	return hash.Parse(u.PasswdHashAlgo).VerifyPassword(passwd, u.Passwd, u.Salt)
   384  }
   385  
   386  // IsPasswordSet checks if the password is set or left empty
   387  func (u *User) IsPasswordSet() bool {
   388  	return len(u.Passwd) != 0
   389  }
   390  
   391  // IsOrganization returns true if user is actually a organization.
   392  func (u *User) IsOrganization() bool {
   393  	return u.Type == UserTypeOrganization
   394  }
   395  
   396  // IsIndividual returns true if user is actually a individual user.
   397  func (u *User) IsIndividual() bool {
   398  	return u.Type == UserTypeIndividual
   399  }
   400  
   401  func (u *User) IsUser() bool {
   402  	return u.Type == UserTypeIndividual || u.Type == UserTypeBot
   403  }
   404  
   405  // IsBot returns whether or not the user is of type bot
   406  func (u *User) IsBot() bool {
   407  	return u.Type == UserTypeBot
   408  }
   409  
   410  // DisplayName returns full name if it's not empty,
   411  // returns username otherwise.
   412  func (u *User) DisplayName() string {
   413  	trimmed := strings.TrimSpace(u.FullName)
   414  	if len(trimmed) > 0 {
   415  		return trimmed
   416  	}
   417  	return u.Name
   418  }
   419  
   420  // GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set,
   421  // returns username otherwise.
   422  func (u *User) GetDisplayName() string {
   423  	if setting.UI.DefaultShowFullName {
   424  		trimmed := strings.TrimSpace(u.FullName)
   425  		if len(trimmed) > 0 {
   426  			return trimmed
   427  		}
   428  	}
   429  	return u.Name
   430  }
   431  
   432  // GetCompleteName returns the full name and username in the form of
   433  // "Full Name (username)" if full name is not empty, otherwise it returns
   434  // "username".
   435  func (u *User) GetCompleteName() string {
   436  	trimmedFullName := strings.TrimSpace(u.FullName)
   437  	if len(trimmedFullName) > 0 {
   438  		return fmt.Sprintf("%s (%s)", trimmedFullName, u.Name)
   439  	}
   440  	return u.Name
   441  }
   442  
   443  func gitSafeName(name string) string {
   444  	return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name))
   445  }
   446  
   447  // GitName returns a git safe name
   448  func (u *User) GitName() string {
   449  	gitName := gitSafeName(u.FullName)
   450  	if len(gitName) > 0 {
   451  		return gitName
   452  	}
   453  	// Although u.Name should be safe if created in our system
   454  	// LDAP users may have bad names
   455  	gitName = gitSafeName(u.Name)
   456  	if len(gitName) > 0 {
   457  		return gitName
   458  	}
   459  	// Totally pathological name so it's got to be:
   460  	return fmt.Sprintf("user-%d", u.ID)
   461  }
   462  
   463  // ShortName ellipses username to length
   464  func (u *User) ShortName(length int) string {
   465  	if setting.UI.DefaultShowFullName && len(u.FullName) > 0 {
   466  		return base.EllipsisString(u.FullName, length)
   467  	}
   468  	return base.EllipsisString(u.Name, length)
   469  }
   470  
   471  // IsMailable checks if a user is eligible
   472  // to receive emails.
   473  func (u *User) IsMailable() bool {
   474  	return u.IsActive
   475  }
   476  
   477  // IsUserExist checks if given user name exist,
   478  // the user name should be noncased unique.
   479  // If uid is presented, then check will rule out that one,
   480  // it is used when update a user name in settings page.
   481  func IsUserExist(ctx context.Context, uid int64, name string) (bool, error) {
   482  	if len(name) == 0 {
   483  		return false, nil
   484  	}
   485  	return db.GetEngine(ctx).
   486  		Where("id!=?", uid).
   487  		Get(&User{LowerName: strings.ToLower(name)})
   488  }
   489  
   490  // Note: As of the beginning of 2022, it is recommended to use at least
   491  // 64 bits of salt, but NIST is already recommending to use to 128 bits.
   492  // (16 bytes = 16 * 8 = 128 bits)
   493  const SaltByteLength = 16
   494  
   495  // GetUserSalt returns a random user salt token.
   496  func GetUserSalt() (string, error) {
   497  	rBytes, err := util.CryptoRandomBytes(SaltByteLength)
   498  	if err != nil {
   499  		return "", err
   500  	}
   501  	// Returns a 32 bytes long string.
   502  	return hex.EncodeToString(rBytes), nil
   503  }
   504  
   505  // Note: The set of characters here can safely expand without a breaking change,
   506  // but characters removed from this set can cause user account linking to break
   507  var (
   508  	customCharsReplacement = strings.NewReplacer("Æ", "AE")
   509  	removeCharsRE          = regexp.MustCompile("['`´]")
   510  	transformDiacritics    = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
   511  	replaceCharsHyphenRE   = regexp.MustCompile(`[\s~+]`)
   512  )
   513  
   514  // NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters.
   515  // It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character
   516  func NormalizeUserName(s string) (string, error) {
   517  	s, _, _ = strings.Cut(s, "@")
   518  	strDiacriticsRemoved, n, err := transform.String(transformDiacritics, customCharsReplacement.Replace(s))
   519  	if err != nil {
   520  		return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n)
   521  	}
   522  	return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
   523  }
   524  
   525  var (
   526  	reservedUsernames = []string{
   527  		".",
   528  		"..",
   529  		".well-known",
   530  		"admin",
   531  		"api",
   532  		"assets",
   533  		"attachments",
   534  		"avatar",
   535  		"avatars",
   536  		"captcha",
   537  		"commits",
   538  		"debug",
   539  		"error",
   540  		"explore",
   541  		"favicon.ico",
   542  		"ghost",
   543  		"issues",
   544  		"login",
   545  		"manifest.json",
   546  		"metrics",
   547  		"milestones",
   548  		"new",
   549  		"notifications",
   550  		"org",
   551  		"pulls",
   552  		"raw",
   553  		"repo",
   554  		"repo-avatars",
   555  		"robots.txt",
   556  		"search",
   557  		"serviceworker.js",
   558  		"ssh_info",
   559  		"swagger.v1.json",
   560  		"user",
   561  		"v2",
   562  		"gitea-actions",
   563  	}
   564  
   565  	// DON'T ADD ANY NEW STUFF, WE SOLVE THIS WITH `/user/{obj}` PATHS!
   566  	reservedUserPatterns = []string{"*.keys", "*.gpg", "*.rss", "*.atom", "*.png"}
   567  )
   568  
   569  // IsUsableUsername returns an error when a username is reserved
   570  func IsUsableUsername(name string) error {
   571  	// Validate username make sure it satisfies requirement.
   572  	if !validation.IsValidUsername(name) {
   573  		// Note: usually this error is normally caught up earlier in the UI
   574  		return db.ErrNameCharsNotAllowed{Name: name}
   575  	}
   576  	return db.IsUsableName(reservedUsernames, reservedUserPatterns, name)
   577  }
   578  
   579  // CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
   580  type CreateUserOverwriteOptions struct {
   581  	KeepEmailPrivate             optional.Option[bool]
   582  	Visibility                   *structs.VisibleType
   583  	AllowCreateOrganization      optional.Option[bool]
   584  	EmailNotificationsPreference *string
   585  	MaxRepoCreation              *int
   586  	Theme                        *string
   587  	IsRestricted                 optional.Option[bool]
   588  	IsActive                     optional.Option[bool]
   589  }
   590  
   591  // CreateUser creates record of a new user.
   592  func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
   593  	return createUser(ctx, u, false, overwriteDefault...)
   594  }
   595  
   596  // AdminCreateUser is used by admins to manually create users
   597  func AdminCreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
   598  	return createUser(ctx, u, true, overwriteDefault...)
   599  }
   600  
   601  // createUser creates record of a new user.
   602  func createUser(ctx context.Context, u *User, createdByAdmin bool, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
   603  	if err = IsUsableUsername(u.Name); err != nil {
   604  		return err
   605  	}
   606  
   607  	// set system defaults
   608  	u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
   609  	u.Visibility = setting.Service.DefaultUserVisibilityMode
   610  	u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation
   611  	u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
   612  	u.MaxRepoCreation = -1
   613  	u.Theme = setting.UI.DefaultTheme
   614  	u.IsRestricted = setting.Service.DefaultUserIsRestricted
   615  	u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm)
   616  
   617  	// Ensure consistency of the dates.
   618  	if u.UpdatedUnix < u.CreatedUnix {
   619  		u.UpdatedUnix = u.CreatedUnix
   620  	}
   621  
   622  	// overwrite defaults if set
   623  	if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
   624  		overwrite := overwriteDefault[0]
   625  		if overwrite.KeepEmailPrivate.Has() {
   626  			u.KeepEmailPrivate = overwrite.KeepEmailPrivate.Value()
   627  		}
   628  		if overwrite.Visibility != nil {
   629  			u.Visibility = *overwrite.Visibility
   630  		}
   631  		if overwrite.AllowCreateOrganization.Has() {
   632  			u.AllowCreateOrganization = overwrite.AllowCreateOrganization.Value()
   633  		}
   634  		if overwrite.EmailNotificationsPreference != nil {
   635  			u.EmailNotificationsPreference = *overwrite.EmailNotificationsPreference
   636  		}
   637  		if overwrite.MaxRepoCreation != nil {
   638  			u.MaxRepoCreation = *overwrite.MaxRepoCreation
   639  		}
   640  		if overwrite.Theme != nil {
   641  			u.Theme = *overwrite.Theme
   642  		}
   643  		if overwrite.IsRestricted.Has() {
   644  			u.IsRestricted = overwrite.IsRestricted.Value()
   645  		}
   646  		if overwrite.IsActive.Has() {
   647  			u.IsActive = overwrite.IsActive.Value()
   648  		}
   649  	}
   650  
   651  	// validate data
   652  	if err := ValidateUser(u); err != nil {
   653  		return err
   654  	}
   655  
   656  	if createdByAdmin {
   657  		if err := ValidateEmailForAdmin(u.Email); err != nil {
   658  			return err
   659  		}
   660  	} else {
   661  		if err := ValidateEmail(u.Email); err != nil {
   662  			return err
   663  		}
   664  	}
   665  
   666  	ctx, committer, err := db.TxContext(ctx)
   667  	if err != nil {
   668  		return err
   669  	}
   670  	defer committer.Close()
   671  
   672  	isExist, err := IsUserExist(ctx, 0, u.Name)
   673  	if err != nil {
   674  		return err
   675  	} else if isExist {
   676  		return ErrUserAlreadyExist{u.Name}
   677  	}
   678  
   679  	isExist, err = IsEmailUsed(ctx, u.Email)
   680  	if err != nil {
   681  		return err
   682  	} else if isExist {
   683  		return ErrEmailAlreadyUsed{
   684  			Email: u.Email,
   685  		}
   686  	}
   687  
   688  	// prepare for database
   689  
   690  	u.LowerName = strings.ToLower(u.Name)
   691  	u.AvatarEmail = u.Email
   692  	if u.Rands, err = GetUserSalt(); err != nil {
   693  		return err
   694  	}
   695  	if u.Passwd != "" {
   696  		if err = u.SetPassword(u.Passwd); err != nil {
   697  			return err
   698  		}
   699  	} else {
   700  		u.Salt = ""
   701  		u.PasswdHashAlgo = ""
   702  	}
   703  
   704  	// save changes to database
   705  
   706  	if err = DeleteUserRedirect(ctx, u.Name); err != nil {
   707  		return err
   708  	}
   709  
   710  	if u.CreatedUnix == 0 {
   711  		// Caller expects auto-time for creation & update timestamps.
   712  		err = db.Insert(ctx, u)
   713  	} else {
   714  		// Caller sets the timestamps themselves. They are responsible for ensuring
   715  		// both `CreatedUnix` and `UpdatedUnix` are set appropriately.
   716  		_, err = db.GetEngine(ctx).NoAutoTime().Insert(u)
   717  	}
   718  	if err != nil {
   719  		return err
   720  	}
   721  
   722  	// insert email address
   723  	if err := db.Insert(ctx, &EmailAddress{
   724  		UID:         u.ID,
   725  		Email:       u.Email,
   726  		LowerEmail:  strings.ToLower(u.Email),
   727  		IsActivated: u.IsActive,
   728  		IsPrimary:   true,
   729  	}); err != nil {
   730  		return err
   731  	}
   732  
   733  	return committer.Commit()
   734  }
   735  
   736  // IsLastAdminUser check whether user is the last admin
   737  func IsLastAdminUser(ctx context.Context, user *User) bool {
   738  	if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: optional.Some(true)}) <= 1 {
   739  		return true
   740  	}
   741  	return false
   742  }
   743  
   744  // CountUserFilter represent optional filters for CountUsers
   745  type CountUserFilter struct {
   746  	LastLoginSince *int64
   747  	IsAdmin        optional.Option[bool]
   748  }
   749  
   750  // CountUsers returns number of users.
   751  func CountUsers(ctx context.Context, opts *CountUserFilter) int64 {
   752  	return countUsers(ctx, opts)
   753  }
   754  
   755  func countUsers(ctx context.Context, opts *CountUserFilter) int64 {
   756  	sess := db.GetEngine(ctx)
   757  	cond := builder.NewCond()
   758  	cond = cond.And(builder.Eq{"type": UserTypeIndividual})
   759  
   760  	if opts != nil {
   761  		if opts.LastLoginSince != nil {
   762  			cond = cond.And(builder.Gte{"last_login_unix": *opts.LastLoginSince})
   763  		}
   764  
   765  		if opts.IsAdmin.Has() {
   766  			cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.Value()})
   767  		}
   768  	}
   769  
   770  	count, err := sess.Where(cond).Count(new(User))
   771  	if err != nil {
   772  		log.Error("user.countUsers: %v", err)
   773  	}
   774  
   775  	return count
   776  }
   777  
   778  // GetVerifyUser get user by verify code
   779  func GetVerifyUser(ctx context.Context, code string) (user *User) {
   780  	if len(code) <= base.TimeLimitCodeLength {
   781  		return nil
   782  	}
   783  
   784  	// use tail hex username query user
   785  	hexStr := code[base.TimeLimitCodeLength:]
   786  	if b, err := hex.DecodeString(hexStr); err == nil {
   787  		if user, err = GetUserByName(ctx, string(b)); user != nil {
   788  			return user
   789  		}
   790  		log.Error("user.getVerifyUser: %v", err)
   791  	}
   792  
   793  	return nil
   794  }
   795  
   796  // VerifyUserActiveCode verifies active code when active account
   797  func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
   798  	if user = GetVerifyUser(ctx, code); user != nil {
   799  		// time limit code
   800  		prefix := code[:base.TimeLimitCodeLength]
   801  		data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
   802  		if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
   803  			return user
   804  		}
   805  	}
   806  	return nil
   807  }
   808  
   809  // ValidateUser check if user is valid to insert / update into database
   810  func ValidateUser(u *User, cols ...string) error {
   811  	if len(cols) == 0 || util.SliceContainsString(cols, "visibility", true) {
   812  		if !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(u.Visibility) && !u.IsOrganization() {
   813  			return fmt.Errorf("visibility Mode not allowed: %s", u.Visibility.String())
   814  		}
   815  	}
   816  
   817  	return nil
   818  }
   819  
   820  // UpdateUserCols update user according special columns
   821  func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
   822  	if err := ValidateUser(u, cols...); err != nil {
   823  		return err
   824  	}
   825  
   826  	_, err := db.GetEngine(ctx).ID(u.ID).Cols(cols...).Update(u)
   827  	return err
   828  }
   829  
   830  // GetInactiveUsers gets all inactive users
   831  func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) {
   832  	var cond builder.Cond = builder.Eq{"is_active": false}
   833  
   834  	if olderThan > 0 {
   835  		cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-olderThan).Unix()})
   836  	}
   837  
   838  	users := make([]*User, 0, 10)
   839  	return users, db.GetEngine(ctx).
   840  		Where(cond).
   841  		Find(&users)
   842  }
   843  
   844  // UserPath returns the path absolute path of user repositories.
   845  func UserPath(userName string) string { //revive:disable-line:exported
   846  	return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
   847  }
   848  
   849  // GetUserByID returns the user object by given ID if exists.
   850  func GetUserByID(ctx context.Context, id int64) (*User, error) {
   851  	u := new(User)
   852  	has, err := db.GetEngine(ctx).ID(id).Get(u)
   853  	if err != nil {
   854  		return nil, err
   855  	} else if !has {
   856  		return nil, ErrUserNotExist{UID: id}
   857  	}
   858  	return u, nil
   859  }
   860  
   861  // GetUserByIDs returns the user objects by given IDs if exists.
   862  func GetUserByIDs(ctx context.Context, ids []int64) ([]*User, error) {
   863  	users := make([]*User, 0, len(ids))
   864  	err := db.GetEngine(ctx).In("id", ids).
   865  		Table("user").
   866  		Find(&users)
   867  	return users, err
   868  }
   869  
   870  // GetPossibleUserByID returns the user if id > 0 or return system usrs if id < 0
   871  func GetPossibleUserByID(ctx context.Context, id int64) (*User, error) {
   872  	switch id {
   873  	case GhostUserID:
   874  		return NewGhostUser(), nil
   875  	case ActionsUserID:
   876  		return NewActionsUser(), nil
   877  	case 0:
   878  		return nil, ErrUserNotExist{}
   879  	default:
   880  		return GetUserByID(ctx, id)
   881  	}
   882  }
   883  
   884  // GetPossibleUserByIDs returns the users if id > 0 or return system users if id < 0
   885  func GetPossibleUserByIDs(ctx context.Context, ids []int64) ([]*User, error) {
   886  	uniqueIDs := container.SetOf(ids...)
   887  	users := make([]*User, 0, len(ids))
   888  	_ = uniqueIDs.Remove(0)
   889  	if uniqueIDs.Remove(GhostUserID) {
   890  		users = append(users, NewGhostUser())
   891  	}
   892  	if uniqueIDs.Remove(ActionsUserID) {
   893  		users = append(users, NewActionsUser())
   894  	}
   895  	res, err := GetUserByIDs(ctx, uniqueIDs.Values())
   896  	if err != nil {
   897  		return nil, err
   898  	}
   899  	users = append(users, res...)
   900  	return users, nil
   901  }
   902  
   903  // GetUserByNameCtx returns user by given name.
   904  func GetUserByName(ctx context.Context, name string) (*User, error) {
   905  	if len(name) == 0 {
   906  		return nil, ErrUserNotExist{Name: name}
   907  	}
   908  	u := &User{LowerName: strings.ToLower(name), Type: UserTypeIndividual}
   909  	has, err := db.GetEngine(ctx).Get(u)
   910  	if err != nil {
   911  		return nil, err
   912  	} else if !has {
   913  		return nil, ErrUserNotExist{Name: name}
   914  	}
   915  	return u, nil
   916  }
   917  
   918  // GetUserEmailsByNames returns a list of e-mails corresponds to names of users
   919  // that have their email notifications set to enabled or onmention.
   920  func GetUserEmailsByNames(ctx context.Context, names []string) []string {
   921  	mails := make([]string, 0, len(names))
   922  	for _, name := range names {
   923  		u, err := GetUserByName(ctx, name)
   924  		if err != nil {
   925  			continue
   926  		}
   927  		if u.IsMailable() && u.EmailNotificationsPreference != EmailNotificationsDisabled {
   928  			mails = append(mails, u.Email)
   929  		}
   930  	}
   931  	return mails
   932  }
   933  
   934  // GetMaileableUsersByIDs gets users from ids, but only if they can receive mails
   935  func GetMaileableUsersByIDs(ctx context.Context, ids []int64, isMention bool) ([]*User, error) {
   936  	if len(ids) == 0 {
   937  		return nil, nil
   938  	}
   939  	ous := make([]*User, 0, len(ids))
   940  
   941  	if isMention {
   942  		return ous, db.GetEngine(ctx).
   943  			In("id", ids).
   944  			Where("`type` = ?", UserTypeIndividual).
   945  			And("`prohibit_login` = ?", false).
   946  			And("`is_active` = ?", true).
   947  			In("`email_notifications_preference`", EmailNotificationsEnabled, EmailNotificationsOnMention, EmailNotificationsAndYourOwn).
   948  			Find(&ous)
   949  	}
   950  
   951  	return ous, db.GetEngine(ctx).
   952  		In("id", ids).
   953  		Where("`type` = ?", UserTypeIndividual).
   954  		And("`prohibit_login` = ?", false).
   955  		And("`is_active` = ?", true).
   956  		In("`email_notifications_preference`", EmailNotificationsEnabled, EmailNotificationsAndYourOwn).
   957  		Find(&ous)
   958  }
   959  
   960  // GetUserNamesByIDs returns usernames for all resolved users from a list of Ids.
   961  func GetUserNamesByIDs(ctx context.Context, ids []int64) ([]string, error) {
   962  	unames := make([]string, 0, len(ids))
   963  	err := db.GetEngine(ctx).In("id", ids).
   964  		Table("user").
   965  		Asc("name").
   966  		Cols("name").
   967  		Find(&unames)
   968  	return unames, err
   969  }
   970  
   971  // GetUserNameByID returns username for the id
   972  func GetUserNameByID(ctx context.Context, id int64) (string, error) {
   973  	var name string
   974  	has, err := db.GetEngine(ctx).Table("user").Where("id = ?", id).Cols("name").Get(&name)
   975  	if err != nil {
   976  		return "", err
   977  	}
   978  	if has {
   979  		return name, nil
   980  	}
   981  	return "", nil
   982  }
   983  
   984  // GetUserIDsByNames returns a slice of ids corresponds to names.
   985  func GetUserIDsByNames(ctx context.Context, names []string, ignoreNonExistent bool) ([]int64, error) {
   986  	ids := make([]int64, 0, len(names))
   987  	for _, name := range names {
   988  		u, err := GetUserByName(ctx, name)
   989  		if err != nil {
   990  			if ignoreNonExistent {
   991  				continue
   992  			}
   993  			return nil, err
   994  		}
   995  		ids = append(ids, u.ID)
   996  	}
   997  	return ids, nil
   998  }
   999  
  1000  // GetUsersBySource returns a list of Users for a login source
  1001  func GetUsersBySource(ctx context.Context, s *auth.Source) ([]*User, error) {
  1002  	var users []*User
  1003  	err := db.GetEngine(ctx).Where("login_type = ? AND login_source = ?", s.Type, s.ID).Find(&users)
  1004  	return users, err
  1005  }
  1006  
  1007  // UserCommit represents a commit with validation of user.
  1008  type UserCommit struct { //revive:disable-line:exported
  1009  	User *User
  1010  	*git.Commit
  1011  }
  1012  
  1013  // ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user.
  1014  func ValidateCommitWithEmail(ctx context.Context, c *git.Commit) *User {
  1015  	if c.Author == nil {
  1016  		return nil
  1017  	}
  1018  	u, err := GetUserByEmail(ctx, c.Author.Email)
  1019  	if err != nil {
  1020  		return nil
  1021  	}
  1022  	return u
  1023  }
  1024  
  1025  // ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
  1026  func ValidateCommitsWithEmails(ctx context.Context, oldCommits []*git.Commit) []*UserCommit {
  1027  	var (
  1028  		emails     = make(map[string]*User)
  1029  		newCommits = make([]*UserCommit, 0, len(oldCommits))
  1030  	)
  1031  	for _, c := range oldCommits {
  1032  		var u *User
  1033  		if c.Author != nil {
  1034  			if v, ok := emails[c.Author.Email]; !ok {
  1035  				u, _ = GetUserByEmail(ctx, c.Author.Email)
  1036  				emails[c.Author.Email] = u
  1037  			} else {
  1038  				u = v
  1039  			}
  1040  		}
  1041  
  1042  		newCommits = append(newCommits, &UserCommit{
  1043  			User:   u,
  1044  			Commit: c,
  1045  		})
  1046  	}
  1047  	return newCommits
  1048  }
  1049  
  1050  // GetUserByEmail returns the user object by given e-mail if exists.
  1051  func GetUserByEmail(ctx context.Context, email string) (*User, error) {
  1052  	if len(email) == 0 {
  1053  		return nil, ErrUserNotExist{Name: email}
  1054  	}
  1055  
  1056  	email = strings.ToLower(email)
  1057  	// Otherwise, check in alternative list for activated email addresses
  1058  	emailAddress := &EmailAddress{LowerEmail: email, IsActivated: true}
  1059  	has, err := db.GetEngine(ctx).Get(emailAddress)
  1060  	if err != nil {
  1061  		return nil, err
  1062  	}
  1063  	if has {
  1064  		return GetUserByID(ctx, emailAddress.UID)
  1065  	}
  1066  
  1067  	// Finally, if email address is the protected email address:
  1068  	if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) {
  1069  		username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress))
  1070  		user := &User{}
  1071  		has, err := db.GetEngine(ctx).Where("lower_name=?", username).Get(user)
  1072  		if err != nil {
  1073  			return nil, err
  1074  		}
  1075  		if has {
  1076  			return user, nil
  1077  		}
  1078  	}
  1079  
  1080  	return nil, ErrUserNotExist{Name: email}
  1081  }
  1082  
  1083  // GetUser checks if a user already exists
  1084  func GetUser(ctx context.Context, user *User) (bool, error) {
  1085  	return db.GetEngine(ctx).Get(user)
  1086  }
  1087  
  1088  // GetUserByOpenID returns the user object by given OpenID if exists.
  1089  func GetUserByOpenID(ctx context.Context, uri string) (*User, error) {
  1090  	if len(uri) == 0 {
  1091  		return nil, ErrUserNotExist{Name: uri}
  1092  	}
  1093  
  1094  	uri, err := openid.Normalize(uri)
  1095  	if err != nil {
  1096  		return nil, err
  1097  	}
  1098  
  1099  	log.Trace("Normalized OpenID URI: " + uri)
  1100  
  1101  	// Otherwise, check in openid table
  1102  	oid := &UserOpenID{}
  1103  	has, err := db.GetEngine(ctx).Where("uri=?", uri).Get(oid)
  1104  	if err != nil {
  1105  		return nil, err
  1106  	}
  1107  	if has {
  1108  		return GetUserByID(ctx, oid.UID)
  1109  	}
  1110  
  1111  	return nil, ErrUserNotExist{Name: uri}
  1112  }
  1113  
  1114  // GetAdminUser returns the first administrator
  1115  func GetAdminUser(ctx context.Context) (*User, error) {
  1116  	var admin User
  1117  	has, err := db.GetEngine(ctx).
  1118  		Where("is_admin=?", true).
  1119  		Asc("id"). // Reliably get the admin with the lowest ID.
  1120  		Get(&admin)
  1121  	if err != nil {
  1122  		return nil, err
  1123  	} else if !has {
  1124  		return nil, ErrUserNotExist{}
  1125  	}
  1126  
  1127  	return &admin, nil
  1128  }
  1129  
  1130  func isUserVisibleToViewerCond(viewer *User) builder.Cond {
  1131  	if viewer != nil && viewer.IsAdmin {
  1132  		return builder.NewCond()
  1133  	}
  1134  
  1135  	if viewer == nil || viewer.IsRestricted {
  1136  		return builder.Eq{
  1137  			"`user`.visibility": structs.VisibleTypePublic,
  1138  		}
  1139  	}
  1140  
  1141  	return builder.Neq{
  1142  		"`user`.visibility": structs.VisibleTypePrivate,
  1143  	}.Or(
  1144  		// viewer self
  1145  		builder.Eq{"`user`.id": viewer.ID},
  1146  		// viewer's following
  1147  		builder.In("`user`.id",
  1148  			builder.
  1149  				Select("`follow`.user_id").
  1150  				From("follow").
  1151  				Where(builder.Eq{"`follow`.follow_id": viewer.ID})),
  1152  		// viewer's org user
  1153  		builder.In("`user`.id",
  1154  			builder.
  1155  				Select("`team_user`.uid").
  1156  				From("team_user").
  1157  				Join("INNER", "`team_user` AS t2", "`team_user`.org_id = `t2`.org_id").
  1158  				Where(builder.Eq{"`t2`.uid": viewer.ID})),
  1159  		// viewer's org
  1160  		builder.In("`user`.id",
  1161  			builder.
  1162  				Select("`team_user`.org_id").
  1163  				From("team_user").
  1164  				Where(builder.Eq{"`team_user`.uid": viewer.ID})))
  1165  }
  1166  
  1167  // IsUserVisibleToViewer check if viewer is able to see user profile
  1168  func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
  1169  	if viewer != nil && (viewer.IsAdmin || viewer.ID == u.ID) {
  1170  		return true
  1171  	}
  1172  
  1173  	switch u.Visibility {
  1174  	case structs.VisibleTypePublic:
  1175  		return true
  1176  	case structs.VisibleTypeLimited:
  1177  		if viewer == nil || viewer.IsRestricted {
  1178  			return false
  1179  		}
  1180  		return true
  1181  	case structs.VisibleTypePrivate:
  1182  		if viewer == nil || viewer.IsRestricted {
  1183  			return false
  1184  		}
  1185  
  1186  		// If they follow - they see each other
  1187  		follower := IsFollowing(ctx, u.ID, viewer.ID)
  1188  		if follower {
  1189  			return true
  1190  		}
  1191  
  1192  		// Now we need to check if they in some organization together
  1193  		count, err := db.GetEngine(ctx).Table("team_user").
  1194  			Where(
  1195  				builder.And(
  1196  					builder.Eq{"uid": viewer.ID},
  1197  					builder.Or(
  1198  						builder.Eq{"org_id": u.ID},
  1199  						builder.In("org_id",
  1200  							builder.Select("org_id").
  1201  								From("team_user", "t2").
  1202  								Where(builder.Eq{"uid": u.ID}))))).
  1203  			Count()
  1204  		if err != nil {
  1205  			return false
  1206  		}
  1207  
  1208  		if count == 0 {
  1209  			// No common organization
  1210  			return false
  1211  		}
  1212  
  1213  		// they are in an organization together
  1214  		return true
  1215  	}
  1216  	return false
  1217  }
  1218  
  1219  // CountWrongUserType count OrgUser who have wrong type
  1220  func CountWrongUserType(ctx context.Context) (int64, error) {
  1221  	return db.GetEngine(ctx).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(User))
  1222  }
  1223  
  1224  // FixWrongUserType fix OrgUser who have wrong type
  1225  func FixWrongUserType(ctx context.Context) (int64, error) {
  1226  	return db.GetEngine(ctx).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&User{Type: 1})
  1227  }
  1228  
  1229  func GetOrderByName() string {
  1230  	if setting.UI.DefaultShowFullName {
  1231  		return "full_name, name"
  1232  	}
  1233  	return "name"
  1234  }
  1235  
  1236  // IsFeatureDisabledWithLoginType checks if a user feature is disabled, taking into account the login type of the
  1237  // user if applicable
  1238  func IsFeatureDisabledWithLoginType(user *User, feature string) bool {
  1239  	// NOTE: in the long run it may be better to check the ExternalLoginUser table rather than user.LoginType
  1240  	return (user != nil && user.LoginType > auth.Plain && setting.Admin.ExternalUserDisableFeatures.Contains(feature)) ||
  1241  		setting.Admin.UserDisabledFeatures.Contains(feature)
  1242  }
  1243  
  1244  // DisabledFeaturesWithLoginType returns the set of user features disabled, taking into account the login type
  1245  // of the user if applicable
  1246  func DisabledFeaturesWithLoginType(user *User) *container.Set[string] {
  1247  	// NOTE: in the long run it may be better to check the ExternalLoginUser table rather than user.LoginType
  1248  	if user != nil && user.LoginType > auth.Plain {
  1249  		return &setting.Admin.ExternalUserDisableFeatures
  1250  	}
  1251  	return &setting.Admin.UserDisabledFeatures
  1252  }