You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

user.go 40KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "bytes"
  7. "container/list"
  8. "crypto/md5"
  9. "crypto/sha256"
  10. "crypto/subtle"
  11. "encoding/hex"
  12. "errors"
  13. "fmt"
  14. "image"
  15. // Needed for jpeg support
  16. _ "image/jpeg"
  17. "image/png"
  18. "os"
  19. "path/filepath"
  20. "strings"
  21. "time"
  22. "unicode/utf8"
  23. "github.com/Unknwon/com"
  24. "github.com/go-xorm/builder"
  25. "github.com/go-xorm/xorm"
  26. "github.com/nfnt/resize"
  27. "golang.org/x/crypto/pbkdf2"
  28. "code.gitea.io/git"
  29. api "code.gitea.io/sdk/gitea"
  30. "code.gitea.io/gitea/modules/avatar"
  31. "code.gitea.io/gitea/modules/base"
  32. "code.gitea.io/gitea/modules/log"
  33. "code.gitea.io/gitea/modules/setting"
  34. )
  35. // UserType defines the user type
  36. type UserType int
  37. const (
  38. // UserTypeIndividual defines an individual user
  39. UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
  40. // UserTypeOrganization defines an organization
  41. UserTypeOrganization
  42. )
  43. const syncExternalUsers = "sync_external_users"
  44. var (
  45. // ErrUserNotKeyOwner user does not own this key error
  46. ErrUserNotKeyOwner = errors.New("User does not own this public key")
  47. // ErrEmailNotExist e-mail does not exist error
  48. ErrEmailNotExist = errors.New("E-mail does not exist")
  49. // ErrEmailNotActivated e-mail address has not been activated error
  50. ErrEmailNotActivated = errors.New("E-mail address has not been activated")
  51. // ErrUserNameIllegal user name contains illegal characters error
  52. ErrUserNameIllegal = errors.New("User name contains illegal characters")
  53. // ErrLoginSourceNotActived login source is not actived error
  54. ErrLoginSourceNotActived = errors.New("Login source is not actived")
  55. // ErrUnsupportedLoginType login source is unknown error
  56. ErrUnsupportedLoginType = errors.New("Login source is unknown")
  57. )
  58. // User represents the object of individual and member of organization.
  59. type User struct {
  60. ID int64 `xorm:"pk autoincr"`
  61. LowerName string `xorm:"UNIQUE NOT NULL"`
  62. Name string `xorm:"UNIQUE NOT NULL"`
  63. FullName string
  64. // Email is the primary email address (to be used for communication)
  65. Email string `xorm:"NOT NULL"`
  66. KeepEmailPrivate bool
  67. Passwd string `xorm:"NOT NULL"`
  68. LoginType LoginType
  69. LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
  70. LoginName string
  71. Type UserType
  72. OwnedOrgs []*User `xorm:"-"`
  73. Orgs []*User `xorm:"-"`
  74. Repos []*Repository `xorm:"-"`
  75. Location string
  76. Website string
  77. Rands string `xorm:"VARCHAR(10)"`
  78. Salt string `xorm:"VARCHAR(10)"`
  79. Created time.Time `xorm:"-"`
  80. CreatedUnix int64 `xorm:"INDEX"`
  81. Updated time.Time `xorm:"-"`
  82. UpdatedUnix int64 `xorm:"INDEX"`
  83. LastLogin time.Time `xorm:"-"`
  84. LastLoginUnix int64 `xorm:"INDEX"`
  85. // Remember visibility choice for convenience, true for private
  86. LastRepoVisibility bool
  87. // Maximum repository creation limit, -1 means use global default
  88. MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
  89. // Permissions
  90. IsActive bool `xorm:"INDEX"` // Activate primary email
  91. IsAdmin bool
  92. AllowGitHook bool
  93. AllowImportLocal bool // Allow migrate repository by local path
  94. AllowCreateOrganization bool `xorm:"DEFAULT true"`
  95. ProhibitLogin bool
  96. // Avatar
  97. Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
  98. AvatarEmail string `xorm:"NOT NULL"`
  99. UseCustomAvatar bool
  100. // Counters
  101. NumFollowers int
  102. NumFollowing int `xorm:"NOT NULL DEFAULT 0"`
  103. NumStars int
  104. NumRepos int
  105. // For organization
  106. Description string
  107. NumTeams int
  108. NumMembers int
  109. Teams []*Team `xorm:"-"`
  110. Members []*User `xorm:"-"`
  111. // Preferences
  112. DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
  113. }
  114. // BeforeInsert is invoked from XORM before inserting an object of this type.
  115. func (u *User) BeforeInsert() {
  116. u.CreatedUnix = time.Now().Unix()
  117. u.UpdatedUnix = u.CreatedUnix
  118. }
  119. // BeforeUpdate is invoked from XORM before updating this object.
  120. func (u *User) BeforeUpdate() {
  121. if u.MaxRepoCreation < -1 {
  122. u.MaxRepoCreation = -1
  123. }
  124. u.UpdatedUnix = time.Now().Unix()
  125. }
  126. // SetLastLogin set time to last login
  127. func (u *User) SetLastLogin() {
  128. u.LastLoginUnix = time.Now().Unix()
  129. }
  130. // UpdateDiffViewStyle updates the users diff view style
  131. func (u *User) UpdateDiffViewStyle(style string) error {
  132. u.DiffViewStyle = style
  133. return UpdateUserCols(u, "diff_view_style")
  134. }
  135. // AfterSet is invoked from XORM after setting the value of a field of this object.
  136. func (u *User) AfterSet(colName string, _ xorm.Cell) {
  137. switch colName {
  138. case "created_unix":
  139. u.Created = time.Unix(u.CreatedUnix, 0).Local()
  140. case "updated_unix":
  141. u.Updated = time.Unix(u.UpdatedUnix, 0).Local()
  142. case "last_login_unix":
  143. u.LastLogin = time.Unix(u.LastLoginUnix, 0).Local()
  144. }
  145. }
  146. // getEmail returns an noreply email, if the user has set to keep his
  147. // email address private, otherwise the primary email address.
  148. func (u *User) getEmail() string {
  149. if u.KeepEmailPrivate {
  150. return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
  151. }
  152. return u.Email
  153. }
  154. // APIFormat converts a User to api.User
  155. func (u *User) APIFormat() *api.User {
  156. return &api.User{
  157. ID: u.ID,
  158. UserName: u.Name,
  159. FullName: u.FullName,
  160. Email: u.getEmail(),
  161. AvatarURL: u.AvatarLink(),
  162. }
  163. }
  164. // IsLocal returns true if user login type is LoginPlain.
  165. func (u *User) IsLocal() bool {
  166. return u.LoginType <= LoginPlain
  167. }
  168. // IsOAuth2 returns true if user login type is LoginOAuth2.
  169. func (u *User) IsOAuth2() bool {
  170. return u.LoginType == LoginOAuth2
  171. }
  172. // HasForkedRepo checks if user has already forked a repository with given ID.
  173. func (u *User) HasForkedRepo(repoID int64) bool {
  174. _, has := HasForkedRepo(u.ID, repoID)
  175. return has
  176. }
  177. // MaxCreationLimit returns the number of repositories a user is allowed to create
  178. func (u *User) MaxCreationLimit() int {
  179. if u.MaxRepoCreation <= -1 {
  180. return setting.Repository.MaxCreationLimit
  181. }
  182. return u.MaxRepoCreation
  183. }
  184. // CanCreateRepo returns if user login can create a repository
  185. func (u *User) CanCreateRepo() bool {
  186. if u.IsAdmin {
  187. return true
  188. }
  189. if u.MaxRepoCreation <= -1 {
  190. if setting.Repository.MaxCreationLimit <= -1 {
  191. return true
  192. }
  193. return u.NumRepos < setting.Repository.MaxCreationLimit
  194. }
  195. return u.NumRepos < u.MaxRepoCreation
  196. }
  197. // CanCreateOrganization returns true if user can create organisation.
  198. func (u *User) CanCreateOrganization() bool {
  199. return u.IsAdmin || (u.AllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation)
  200. }
  201. // CanEditGitHook returns true if user can edit Git hooks.
  202. func (u *User) CanEditGitHook() bool {
  203. return u.IsAdmin || u.AllowGitHook
  204. }
  205. // CanImportLocal returns true if user can migrate repository by local path.
  206. func (u *User) CanImportLocal() bool {
  207. if !setting.ImportLocalPaths {
  208. return false
  209. }
  210. return u.IsAdmin || u.AllowImportLocal
  211. }
  212. // DashboardLink returns the user dashboard page link.
  213. func (u *User) DashboardLink() string {
  214. if u.IsOrganization() {
  215. return setting.AppSubURL + "/org/" + u.Name + "/dashboard/"
  216. }
  217. return setting.AppSubURL + "/"
  218. }
  219. // HomeLink returns the user or organization home page link.
  220. func (u *User) HomeLink() string {
  221. return setting.AppSubURL + "/" + u.Name
  222. }
  223. // HTMLURL returns the user or organization's full link.
  224. func (u *User) HTMLURL() string {
  225. return setting.AppURL + u.Name
  226. }
  227. // GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
  228. func (u *User) GenerateEmailActivateCode(email string) string {
  229. code := base.CreateTimeLimitCode(
  230. com.ToStr(u.ID)+email+u.LowerName+u.Passwd+u.Rands,
  231. setting.Service.ActiveCodeLives, nil)
  232. // Add tail hex username
  233. code += hex.EncodeToString([]byte(u.LowerName))
  234. return code
  235. }
  236. // GenerateActivateCode generates an activate code based on user information.
  237. func (u *User) GenerateActivateCode() string {
  238. return u.GenerateEmailActivateCode(u.Email)
  239. }
  240. // CustomAvatarPath returns user custom avatar file path.
  241. func (u *User) CustomAvatarPath() string {
  242. return filepath.Join(setting.AvatarUploadPath, u.Avatar)
  243. }
  244. // GenerateRandomAvatar generates a random avatar for user.
  245. func (u *User) GenerateRandomAvatar() error {
  246. return u.generateRandomAvatar(x)
  247. }
  248. func (u *User) generateRandomAvatar(e Engine) error {
  249. seed := u.Email
  250. if len(seed) == 0 {
  251. seed = u.Name
  252. }
  253. img, err := avatar.RandomImage([]byte(seed))
  254. if err != nil {
  255. return fmt.Errorf("RandomImage: %v", err)
  256. }
  257. // NOTICE for random avatar, it still uses id as avatar name, but custom avatar use md5
  258. // since random image is not a user's photo, there is no security for enumable
  259. u.Avatar = fmt.Sprintf("%d", u.ID)
  260. if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil {
  261. return fmt.Errorf("MkdirAll: %v", err)
  262. }
  263. fw, err := os.Create(u.CustomAvatarPath())
  264. if err != nil {
  265. return fmt.Errorf("Create: %v", err)
  266. }
  267. defer fw.Close()
  268. if _, err := e.Id(u.ID).Cols("avatar").Update(u); err != nil {
  269. return err
  270. }
  271. if err = png.Encode(fw, img); err != nil {
  272. return fmt.Errorf("Encode: %v", err)
  273. }
  274. log.Info("New random avatar created: %d", u.ID)
  275. return nil
  276. }
  277. // RelAvatarLink returns relative avatar link to the site domain,
  278. // which includes app sub-url as prefix. However, it is possible
  279. // to return full URL if user enables Gravatar-like service.
  280. func (u *User) RelAvatarLink() string {
  281. if u.ID == -1 {
  282. return base.DefaultAvatarLink()
  283. }
  284. switch {
  285. case u.UseCustomAvatar:
  286. if !com.IsFile(u.CustomAvatarPath()) {
  287. return base.DefaultAvatarLink()
  288. }
  289. return setting.AppSubURL + "/avatars/" + u.Avatar
  290. case setting.DisableGravatar, setting.OfflineMode:
  291. if !com.IsFile(u.CustomAvatarPath()) {
  292. if err := u.GenerateRandomAvatar(); err != nil {
  293. log.Error(3, "GenerateRandomAvatar: %v", err)
  294. }
  295. }
  296. return setting.AppSubURL + "/avatars/" + u.Avatar
  297. }
  298. return base.AvatarLink(u.AvatarEmail)
  299. }
  300. // AvatarLink returns user avatar absolute link.
  301. func (u *User) AvatarLink() string {
  302. link := u.RelAvatarLink()
  303. if link[0] == '/' && link[1] != '/' {
  304. return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:]
  305. }
  306. return link
  307. }
  308. // GetFollowers returns range of user's followers.
  309. func (u *User) GetFollowers(page int) ([]*User, error) {
  310. users := make([]*User, 0, ItemsPerPage)
  311. sess := x.
  312. Limit(ItemsPerPage, (page-1)*ItemsPerPage).
  313. Where("follow.follow_id=?", u.ID)
  314. if setting.UsePostgreSQL {
  315. sess = sess.Join("LEFT", "follow", `"user".id=follow.user_id`)
  316. } else {
  317. sess = sess.Join("LEFT", "follow", "user.id=follow.user_id")
  318. }
  319. return users, sess.Find(&users)
  320. }
  321. // IsFollowing returns true if user is following followID.
  322. func (u *User) IsFollowing(followID int64) bool {
  323. return IsFollowing(u.ID, followID)
  324. }
  325. // GetFollowing returns range of user's following.
  326. func (u *User) GetFollowing(page int) ([]*User, error) {
  327. users := make([]*User, 0, ItemsPerPage)
  328. sess := x.
  329. Limit(ItemsPerPage, (page-1)*ItemsPerPage).
  330. Where("follow.user_id=?", u.ID)
  331. if setting.UsePostgreSQL {
  332. sess = sess.Join("LEFT", "follow", `"user".id=follow.follow_id`)
  333. } else {
  334. sess = sess.Join("LEFT", "follow", "user.id=follow.follow_id")
  335. }
  336. return users, sess.Find(&users)
  337. }
  338. // NewGitSig generates and returns the signature of given user.
  339. func (u *User) NewGitSig() *git.Signature {
  340. return &git.Signature{
  341. Name: u.DisplayName(),
  342. Email: u.getEmail(),
  343. When: time.Now(),
  344. }
  345. }
  346. // EncodePasswd encodes password to safe format.
  347. func (u *User) EncodePasswd() {
  348. newPasswd := pbkdf2.Key([]byte(u.Passwd), []byte(u.Salt), 10000, 50, sha256.New)
  349. u.Passwd = fmt.Sprintf("%x", newPasswd)
  350. }
  351. // ValidatePassword checks if given password matches the one belongs to the user.
  352. func (u *User) ValidatePassword(passwd string) bool {
  353. newUser := &User{Passwd: passwd, Salt: u.Salt}
  354. newUser.EncodePasswd()
  355. return subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(newUser.Passwd)) == 1
  356. }
  357. // IsPasswordSet checks if the password is set or left empty
  358. func (u *User) IsPasswordSet() bool {
  359. return !u.ValidatePassword("")
  360. }
  361. // UploadAvatar saves custom avatar for user.
  362. // FIXME: split uploads to different subdirs in case we have massive users.
  363. func (u *User) UploadAvatar(data []byte) error {
  364. img, _, err := image.Decode(bytes.NewReader(data))
  365. if err != nil {
  366. return fmt.Errorf("Decode: %v", err)
  367. }
  368. m := resize.Resize(avatar.AvatarSize, avatar.AvatarSize, img, resize.NearestNeighbor)
  369. sess := x.NewSession()
  370. defer sess.Close()
  371. if err = sess.Begin(); err != nil {
  372. return err
  373. }
  374. u.UseCustomAvatar = true
  375. u.Avatar = fmt.Sprintf("%x", md5.Sum(data))
  376. if err = updateUser(sess, u); err != nil {
  377. return fmt.Errorf("updateUser: %v", err)
  378. }
  379. if err := os.MkdirAll(setting.AvatarUploadPath, os.ModePerm); err != nil {
  380. return fmt.Errorf("Failed to create dir %s: %v", setting.AvatarUploadPath, err)
  381. }
  382. fw, err := os.Create(u.CustomAvatarPath())
  383. if err != nil {
  384. return fmt.Errorf("Create: %v", err)
  385. }
  386. defer fw.Close()
  387. if err = png.Encode(fw, m); err != nil {
  388. return fmt.Errorf("Encode: %v", err)
  389. }
  390. return sess.Commit()
  391. }
  392. // DeleteAvatar deletes the user's custom avatar.
  393. func (u *User) DeleteAvatar() error {
  394. log.Trace("DeleteAvatar[%d]: %s", u.ID, u.CustomAvatarPath())
  395. if len(u.Avatar) > 0 {
  396. if err := os.Remove(u.CustomAvatarPath()); err != nil {
  397. return fmt.Errorf("Failed to remove %s: %v", u.CustomAvatarPath(), err)
  398. }
  399. }
  400. u.UseCustomAvatar = false
  401. u.Avatar = ""
  402. if _, err := x.Id(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
  403. return fmt.Errorf("UpdateUser: %v", err)
  404. }
  405. return nil
  406. }
  407. // IsAdminOfRepo returns true if user has admin or higher access of repository.
  408. func (u *User) IsAdminOfRepo(repo *Repository) bool {
  409. has, err := HasAccess(u.ID, repo, AccessModeAdmin)
  410. if err != nil {
  411. log.Error(3, "HasAccess: %v", err)
  412. }
  413. return has
  414. }
  415. // IsWriterOfRepo returns true if user has write access to given repository.
  416. func (u *User) IsWriterOfRepo(repo *Repository) bool {
  417. has, err := HasAccess(u.ID, repo, AccessModeWrite)
  418. if err != nil {
  419. log.Error(3, "HasAccess: %v", err)
  420. }
  421. return has
  422. }
  423. // IsOrganization returns true if user is actually a organization.
  424. func (u *User) IsOrganization() bool {
  425. return u.Type == UserTypeOrganization
  426. }
  427. // IsUserOrgOwner returns true if user is in the owner team of given organization.
  428. func (u *User) IsUserOrgOwner(orgID int64) bool {
  429. return IsOrganizationOwner(orgID, u.ID)
  430. }
  431. // IsPublicMember returns true if user public his/her membership in given organization.
  432. func (u *User) IsPublicMember(orgID int64) bool {
  433. return IsPublicMembership(orgID, u.ID)
  434. }
  435. func (u *User) getOrganizationCount(e Engine) (int64, error) {
  436. return e.
  437. Where("uid=?", u.ID).
  438. Count(new(OrgUser))
  439. }
  440. // GetOrganizationCount returns count of membership of organization of user.
  441. func (u *User) GetOrganizationCount() (int64, error) {
  442. return u.getOrganizationCount(x)
  443. }
  444. // GetRepositories returns repositories that user owns, including private repositories.
  445. func (u *User) GetRepositories(page, pageSize int) (err error) {
  446. u.Repos, err = GetUserRepositories(u.ID, true, page, pageSize, "")
  447. return err
  448. }
  449. // GetRepositoryIDs returns repositories IDs where user owned
  450. func (u *User) GetRepositoryIDs() ([]int64, error) {
  451. var ids []int64
  452. return ids, x.Table("repository").Cols("id").Where("owner_id = ?", u.ID).Find(&ids)
  453. }
  454. // GetOrgRepositoryIDs returns repositories IDs where user's team owned
  455. func (u *User) GetOrgRepositoryIDs() ([]int64, error) {
  456. var ids []int64
  457. return ids, x.Table("repository").
  458. Cols("repository.id").
  459. Join("INNER", "team_user", "repository.owner_id = team_user.org_id AND team_user.uid = ?", u.ID).
  460. GroupBy("repository.id").Find(&ids)
  461. }
  462. // GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations
  463. func (u *User) GetAccessRepoIDs() ([]int64, error) {
  464. ids, err := u.GetRepositoryIDs()
  465. if err != nil {
  466. return nil, err
  467. }
  468. ids2, err := u.GetOrgRepositoryIDs()
  469. if err != nil {
  470. return nil, err
  471. }
  472. return append(ids, ids2...), nil
  473. }
  474. // GetMirrorRepositories returns mirror repositories that user owns, including private repositories.
  475. func (u *User) GetMirrorRepositories() ([]*Repository, error) {
  476. return GetUserMirrorRepositories(u.ID)
  477. }
  478. // GetOwnedOrganizations returns all organizations that user owns.
  479. func (u *User) GetOwnedOrganizations() (err error) {
  480. u.OwnedOrgs, err = GetOwnedOrgsByUserID(u.ID)
  481. return err
  482. }
  483. // GetOrganizations returns all organizations that user belongs to.
  484. func (u *User) GetOrganizations(all bool) error {
  485. ous, err := GetOrgUsersByUserID(u.ID, all)
  486. if err != nil {
  487. return err
  488. }
  489. u.Orgs = make([]*User, len(ous))
  490. for i, ou := range ous {
  491. u.Orgs[i], err = GetUserByID(ou.OrgID)
  492. if err != nil {
  493. return err
  494. }
  495. }
  496. return nil
  497. }
  498. // DisplayName returns full name if it's not empty,
  499. // returns username otherwise.
  500. func (u *User) DisplayName() string {
  501. if len(u.FullName) > 0 {
  502. return u.FullName
  503. }
  504. return u.Name
  505. }
  506. // ShortName ellipses username to length
  507. func (u *User) ShortName(length int) string {
  508. return base.EllipsisString(u.Name, length)
  509. }
  510. // IsMailable checks if a user is eligible
  511. // to receive emails.
  512. func (u *User) IsMailable() bool {
  513. return u.IsActive
  514. }
  515. // IsUserExist checks if given user name exist,
  516. // the user name should be noncased unique.
  517. // If uid is presented, then check will rule out that one,
  518. // it is used when update a user name in settings page.
  519. func IsUserExist(uid int64, name string) (bool, error) {
  520. if len(name) == 0 {
  521. return false, nil
  522. }
  523. return x.
  524. Where("id!=?", uid).
  525. Get(&User{LowerName: strings.ToLower(name)})
  526. }
  527. // GetUserSalt returns a random user salt token.
  528. func GetUserSalt() (string, error) {
  529. return base.GetRandomString(10)
  530. }
  531. // NewGhostUser creates and returns a fake user for someone has deleted his/her account.
  532. func NewGhostUser() *User {
  533. return &User{
  534. ID: -1,
  535. Name: "Ghost",
  536. LowerName: "ghost",
  537. }
  538. }
  539. var (
  540. reservedUsernames = []string{"assets", "css", "explore", "img", "js", "less", "plugins", "debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new", ".", ".."}
  541. reservedUserPatterns = []string{"*.keys"}
  542. )
  543. // isUsableName checks if name is reserved or pattern of name is not allowed
  544. // based on given reserved names and patterns.
  545. // Names are exact match, patterns can be prefix or suffix match with placeholder '*'.
  546. func isUsableName(names, patterns []string, name string) error {
  547. name = strings.TrimSpace(strings.ToLower(name))
  548. if utf8.RuneCountInString(name) == 0 {
  549. return ErrNameEmpty
  550. }
  551. for i := range names {
  552. if name == names[i] {
  553. return ErrNameReserved{name}
  554. }
  555. }
  556. for _, pat := range patterns {
  557. if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
  558. (pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
  559. return ErrNamePatternNotAllowed{pat}
  560. }
  561. }
  562. return nil
  563. }
  564. // IsUsableUsername returns an error when a username is reserved
  565. func IsUsableUsername(name string) error {
  566. return isUsableName(reservedUsernames, reservedUserPatterns, name)
  567. }
  568. // CreateUser creates record of a new user.
  569. func CreateUser(u *User) (err error) {
  570. if err = IsUsableUsername(u.Name); err != nil {
  571. return err
  572. }
  573. isExist, err := IsUserExist(0, u.Name)
  574. if err != nil {
  575. return err
  576. } else if isExist {
  577. return ErrUserAlreadyExist{u.Name}
  578. }
  579. u.Email = strings.ToLower(u.Email)
  580. has, err := x.
  581. Where("email=?", u.Email).
  582. Get(new(User))
  583. if err != nil {
  584. return err
  585. } else if has {
  586. return ErrEmailAlreadyUsed{u.Email}
  587. }
  588. isExist, err = IsEmailUsed(u.Email)
  589. if err != nil {
  590. return err
  591. } else if isExist {
  592. return ErrEmailAlreadyUsed{u.Email}
  593. }
  594. u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
  595. u.LowerName = strings.ToLower(u.Name)
  596. u.AvatarEmail = u.Email
  597. u.Avatar = base.HashEmail(u.AvatarEmail)
  598. if u.Rands, err = GetUserSalt(); err != nil {
  599. return err
  600. }
  601. if u.Salt, err = GetUserSalt(); err != nil {
  602. return err
  603. }
  604. u.EncodePasswd()
  605. u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
  606. u.MaxRepoCreation = -1
  607. sess := x.NewSession()
  608. defer sess.Close()
  609. if err = sess.Begin(); err != nil {
  610. return err
  611. }
  612. if _, err = sess.Insert(u); err != nil {
  613. return err
  614. } else if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil {
  615. return err
  616. }
  617. return sess.Commit()
  618. }
  619. func countUsers(e Engine) int64 {
  620. count, _ := e.
  621. Where("type=0").
  622. Count(new(User))
  623. return count
  624. }
  625. // CountUsers returns number of users.
  626. func CountUsers() int64 {
  627. return countUsers(x)
  628. }
  629. // Users returns number of users in given page.
  630. func Users(opts *SearchUserOptions) ([]*User, error) {
  631. if len(opts.OrderBy) == 0 {
  632. opts.OrderBy = "name ASC"
  633. }
  634. users := make([]*User, 0, opts.PageSize)
  635. sess := x.
  636. Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
  637. Where("type=0")
  638. return users, sess.
  639. OrderBy(opts.OrderBy).
  640. Find(&users)
  641. }
  642. // get user by verify code
  643. func getVerifyUser(code string) (user *User) {
  644. if len(code) <= base.TimeLimitCodeLength {
  645. return nil
  646. }
  647. // use tail hex username query user
  648. hexStr := code[base.TimeLimitCodeLength:]
  649. if b, err := hex.DecodeString(hexStr); err == nil {
  650. if user, err = GetUserByName(string(b)); user != nil {
  651. return user
  652. }
  653. log.Error(4, "user.getVerifyUser: %v", err)
  654. }
  655. return nil
  656. }
  657. // VerifyUserActiveCode verifies active code when active account
  658. func VerifyUserActiveCode(code string) (user *User) {
  659. minutes := setting.Service.ActiveCodeLives
  660. if user = getVerifyUser(code); user != nil {
  661. // time limit code
  662. prefix := code[:base.TimeLimitCodeLength]
  663. data := com.ToStr(user.ID) + user.Email + user.LowerName + user.Passwd + user.Rands
  664. if base.VerifyTimeLimitCode(data, minutes, prefix) {
  665. return user
  666. }
  667. }
  668. return nil
  669. }
  670. // VerifyActiveEmailCode verifies active email code when active account
  671. func VerifyActiveEmailCode(code, email string) *EmailAddress {
  672. minutes := setting.Service.ActiveCodeLives
  673. if user := getVerifyUser(code); user != nil {
  674. // time limit code
  675. prefix := code[:base.TimeLimitCodeLength]
  676. data := com.ToStr(user.ID) + email + user.LowerName + user.Passwd + user.Rands
  677. if base.VerifyTimeLimitCode(data, minutes, prefix) {
  678. emailAddress := &EmailAddress{Email: email}
  679. if has, _ := x.Get(emailAddress); has {
  680. return emailAddress
  681. }
  682. }
  683. }
  684. return nil
  685. }
  686. // ChangeUserName changes all corresponding setting from old user name to new one.
  687. func ChangeUserName(u *User, newUserName string) (err error) {
  688. if err = IsUsableUsername(newUserName); err != nil {
  689. return err
  690. }
  691. isExist, err := IsUserExist(0, newUserName)
  692. if err != nil {
  693. return err
  694. } else if isExist {
  695. return ErrUserAlreadyExist{newUserName}
  696. }
  697. if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil {
  698. return fmt.Errorf("ChangeUsernameInPullRequests: %v", err)
  699. }
  700. // Delete all local copies of repository wiki that user owns.
  701. if err = x.
  702. Where("owner_id=?", u.ID).
  703. Iterate(new(Repository), func(idx int, bean interface{}) error {
  704. repo := bean.(*Repository)
  705. RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath())
  706. return nil
  707. }); err != nil {
  708. return fmt.Errorf("Delete repository wiki local copy: %v", err)
  709. }
  710. return os.Rename(UserPath(u.Name), UserPath(newUserName))
  711. }
  712. // checkDupEmail checks whether there are the same email with the user
  713. func checkDupEmail(e Engine, u *User) error {
  714. u.Email = strings.ToLower(u.Email)
  715. has, err := e.
  716. Where("id!=?", u.ID).
  717. And("type=?", u.Type).
  718. And("email=?", u.Email).
  719. Get(new(User))
  720. if err != nil {
  721. return err
  722. } else if has {
  723. return ErrEmailAlreadyUsed{u.Email}
  724. }
  725. return nil
  726. }
  727. func updateUser(e Engine, u *User) error {
  728. // Organization does not need email
  729. u.Email = strings.ToLower(u.Email)
  730. if !u.IsOrganization() {
  731. if len(u.AvatarEmail) == 0 {
  732. u.AvatarEmail = u.Email
  733. }
  734. if len(u.AvatarEmail) > 0 {
  735. u.Avatar = base.HashEmail(u.AvatarEmail)
  736. }
  737. }
  738. u.LowerName = strings.ToLower(u.Name)
  739. u.Location = base.TruncateString(u.Location, 255)
  740. u.Website = base.TruncateString(u.Website, 255)
  741. u.Description = base.TruncateString(u.Description, 255)
  742. _, err := e.Id(u.ID).AllCols().Update(u)
  743. return err
  744. }
  745. // UpdateUser updates user's information.
  746. func UpdateUser(u *User) error {
  747. return updateUser(x, u)
  748. }
  749. // UpdateUserCols update user according special columns
  750. func UpdateUserCols(u *User, cols ...string) error {
  751. // Organization does not need email
  752. u.Email = strings.ToLower(u.Email)
  753. if !u.IsOrganization() {
  754. if len(u.AvatarEmail) == 0 {
  755. u.AvatarEmail = u.Email
  756. }
  757. if len(u.AvatarEmail) > 0 {
  758. u.Avatar = base.HashEmail(u.AvatarEmail)
  759. }
  760. }
  761. u.LowerName = strings.ToLower(u.Name)
  762. u.Location = base.TruncateString(u.Location, 255)
  763. u.Website = base.TruncateString(u.Website, 255)
  764. u.Description = base.TruncateString(u.Description, 255)
  765. cols = append(cols, "updated_unix")
  766. _, err := x.Id(u.ID).Cols(cols...).Update(u)
  767. return err
  768. }
  769. // UpdateUserSetting updates user's settings.
  770. func UpdateUserSetting(u *User) error {
  771. if !u.IsOrganization() {
  772. if err := checkDupEmail(x, u); err != nil {
  773. return err
  774. }
  775. }
  776. return updateUser(x, u)
  777. }
  778. // deleteBeans deletes all given beans, beans should contain delete conditions.
  779. func deleteBeans(e Engine, beans ...interface{}) (err error) {
  780. for i := range beans {
  781. if _, err = e.Delete(beans[i]); err != nil {
  782. return err
  783. }
  784. }
  785. return nil
  786. }
  787. // FIXME: need some kind of mechanism to record failure. HINT: system notice
  788. func deleteUser(e *xorm.Session, u *User) error {
  789. // Note: A user owns any repository or belongs to any organization
  790. // cannot perform delete operation.
  791. // Check ownership of repository.
  792. count, err := getRepositoryCount(e, u)
  793. if err != nil {
  794. return fmt.Errorf("GetRepositoryCount: %v", err)
  795. } else if count > 0 {
  796. return ErrUserOwnRepos{UID: u.ID}
  797. }
  798. // Check membership of organization.
  799. count, err = u.getOrganizationCount(e)
  800. if err != nil {
  801. return fmt.Errorf("GetOrganizationCount: %v", err)
  802. } else if count > 0 {
  803. return ErrUserHasOrgs{UID: u.ID}
  804. }
  805. // ***** START: Watch *****
  806. watchedRepoIDs := make([]int64, 0, 10)
  807. if err = e.Table("watch").Cols("watch.repo_id").
  808. Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil {
  809. return fmt.Errorf("get all watches: %v", err)
  810. }
  811. if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).Update(new(Repository)); err != nil {
  812. return fmt.Errorf("decrease repository num_watches: %v", err)
  813. }
  814. // ***** END: Watch *****
  815. // ***** START: Star *****
  816. starredRepoIDs := make([]int64, 0, 10)
  817. if err = e.Table("star").Cols("star.repo_id").
  818. Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil {
  819. return fmt.Errorf("get all stars: %v", err)
  820. } else if _, err = e.Decr("num_watches").In("id", starredRepoIDs).Update(new(Repository)); err != nil {
  821. return fmt.Errorf("decrease repository num_stars: %v", err)
  822. }
  823. // ***** END: Star *****
  824. // ***** START: Follow *****
  825. followeeIDs := make([]int64, 0, 10)
  826. if err = e.Table("follow").Cols("follow.follow_id").
  827. Where("follow.user_id = ?", u.ID).Find(&followeeIDs); err != nil {
  828. return fmt.Errorf("get all followees: %v", err)
  829. } else if _, err = e.Decr("num_followers").In("id", followeeIDs).Update(new(User)); err != nil {
  830. return fmt.Errorf("decrease user num_followers: %v", err)
  831. }
  832. followerIDs := make([]int64, 0, 10)
  833. if err = e.Table("follow").Cols("follow.user_id").
  834. Where("follow.follow_id = ?", u.ID).Find(&followerIDs); err != nil {
  835. return fmt.Errorf("get all followers: %v", err)
  836. } else if _, err = e.Decr("num_following").In("id", followerIDs).Update(new(User)); err != nil {
  837. return fmt.Errorf("decrease user num_following: %v", err)
  838. }
  839. // ***** END: Follow *****
  840. if err = deleteBeans(e,
  841. &AccessToken{UID: u.ID},
  842. &Collaboration{UserID: u.ID},
  843. &Access{UserID: u.ID},
  844. &Watch{UserID: u.ID},
  845. &Star{UID: u.ID},
  846. &Follow{UserID: u.ID},
  847. &Follow{FollowID: u.ID},
  848. &Action{UserID: u.ID},
  849. &IssueUser{UID: u.ID},
  850. &EmailAddress{UID: u.ID},
  851. &UserOpenID{UID: u.ID},
  852. ); err != nil {
  853. return fmt.Errorf("deleteBeans: %v", err)
  854. }
  855. // ***** START: PublicKey *****
  856. keys := make([]*PublicKey, 0, 10)
  857. if err = e.Find(&keys, &PublicKey{OwnerID: u.ID}); err != nil {
  858. return fmt.Errorf("get all public keys: %v", err)
  859. }
  860. keyIDs := make([]int64, len(keys))
  861. for i := range keys {
  862. keyIDs[i] = keys[i].ID
  863. }
  864. if err = deletePublicKeys(e, keyIDs...); err != nil {
  865. return fmt.Errorf("deletePublicKeys: %v", err)
  866. }
  867. // ***** END: PublicKey *****
  868. // Clear assignee.
  869. if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.ID); err != nil {
  870. return fmt.Errorf("clear assignee: %v", err)
  871. }
  872. // ***** START: ExternalLoginUser *****
  873. if err = removeAllAccountLinks(e, u); err != nil {
  874. return fmt.Errorf("ExternalLoginUser: %v", err)
  875. }
  876. // ***** END: ExternalLoginUser *****
  877. if _, err = e.Id(u.ID).Delete(new(User)); err != nil {
  878. return fmt.Errorf("Delete: %v", err)
  879. }
  880. // FIXME: system notice
  881. // Note: There are something just cannot be roll back,
  882. // so just keep error logs of those operations.
  883. path := UserPath(u.Name)
  884. if err := os.RemoveAll(path); err != nil {
  885. return fmt.Errorf("Failed to RemoveAll %s: %v", path, err)
  886. }
  887. if len(u.Avatar) > 0 {
  888. avatarPath := u.CustomAvatarPath()
  889. if com.IsExist(avatarPath) {
  890. if err := os.Remove(avatarPath); err != nil {
  891. return fmt.Errorf("Failed to remove %s: %v", avatarPath, err)
  892. }
  893. }
  894. }
  895. return nil
  896. }
  897. // DeleteUser completely and permanently deletes everything of a user,
  898. // but issues/comments/pulls will be kept and shown as someone has been deleted.
  899. func DeleteUser(u *User) (err error) {
  900. sess := x.NewSession()
  901. defer sess.Close()
  902. if err = sess.Begin(); err != nil {
  903. return err
  904. }
  905. if err = deleteUser(sess, u); err != nil {
  906. // Note: don't wrapper error here.
  907. return err
  908. }
  909. if err = sess.Commit(); err != nil {
  910. return err
  911. }
  912. return RewriteAllPublicKeys()
  913. }
  914. // DeleteInactivateUsers deletes all inactivate users and email addresses.
  915. func DeleteInactivateUsers() (err error) {
  916. users := make([]*User, 0, 10)
  917. if err = x.
  918. Where("is_active = ?", false).
  919. Find(&users); err != nil {
  920. return fmt.Errorf("get all inactive users: %v", err)
  921. }
  922. // FIXME: should only update authorized_keys file once after all deletions.
  923. for _, u := range users {
  924. if err = DeleteUser(u); err != nil {
  925. // Ignore users that were set inactive by admin.
  926. if IsErrUserOwnRepos(err) || IsErrUserHasOrgs(err) {
  927. continue
  928. }
  929. return err
  930. }
  931. }
  932. _, err = x.
  933. Where("is_activated = ?", false).
  934. Delete(new(EmailAddress))
  935. return err
  936. }
  937. // UserPath returns the path absolute path of user repositories.
  938. func UserPath(userName string) string {
  939. return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
  940. }
  941. // GetUserByKeyID get user information by user's public key id
  942. func GetUserByKeyID(keyID int64) (*User, error) {
  943. var user User
  944. has, err := x.Join("INNER", "public_key", "`public_key`.owner_id = `user`.id").
  945. Where("`public_key`.id=?", keyID).
  946. Get(&user)
  947. if err != nil {
  948. return nil, err
  949. }
  950. if !has {
  951. return nil, ErrUserNotExist{0, "", keyID}
  952. }
  953. return &user, nil
  954. }
  955. func getUserByID(e Engine, id int64) (*User, error) {
  956. u := new(User)
  957. has, err := e.Id(id).Get(u)
  958. if err != nil {
  959. return nil, err
  960. } else if !has {
  961. return nil, ErrUserNotExist{id, "", 0}
  962. }
  963. return u, nil
  964. }
  965. // GetUserByID returns the user object by given ID if exists.
  966. func GetUserByID(id int64) (*User, error) {
  967. return getUserByID(x, id)
  968. }
  969. // GetAssigneeByID returns the user with write access of repository by given ID.
  970. func GetAssigneeByID(repo *Repository, userID int64) (*User, error) {
  971. has, err := HasAccess(userID, repo, AccessModeWrite)
  972. if err != nil {
  973. return nil, err
  974. } else if !has {
  975. return nil, ErrUserNotExist{userID, "", 0}
  976. }
  977. return GetUserByID(userID)
  978. }
  979. // GetUserByName returns user by given name.
  980. func GetUserByName(name string) (*User, error) {
  981. return getUserByName(x, name)
  982. }
  983. func getUserByName(e Engine, name string) (*User, error) {
  984. if len(name) == 0 {
  985. return nil, ErrUserNotExist{0, name, 0}
  986. }
  987. u := &User{LowerName: strings.ToLower(name)}
  988. has, err := e.Get(u)
  989. if err != nil {
  990. return nil, err
  991. } else if !has {
  992. return nil, ErrUserNotExist{0, name, 0}
  993. }
  994. return u, nil
  995. }
  996. // GetUserEmailsByNames returns a list of e-mails corresponds to names.
  997. func GetUserEmailsByNames(names []string) []string {
  998. return getUserEmailsByNames(x, names)
  999. }
  1000. func getUserEmailsByNames(e Engine, names []string) []string {
  1001. mails := make([]string, 0, len(names))
  1002. for _, name := range names {
  1003. u, err := getUserByName(e, name)
  1004. if err != nil {
  1005. continue
  1006. }
  1007. if u.IsMailable() {
  1008. mails = append(mails, u.Email)
  1009. }
  1010. }
  1011. return mails
  1012. }
  1013. // GetUsersByIDs returns all resolved users from a list of Ids.
  1014. func GetUsersByIDs(ids []int64) ([]*User, error) {
  1015. ous := make([]*User, 0, len(ids))
  1016. if len(ids) == 0 {
  1017. return ous, nil
  1018. }
  1019. err := x.In("id", ids).
  1020. Asc("name").
  1021. Find(&ous)
  1022. return ous, err
  1023. }
  1024. // GetUserIDsByNames returns a slice of ids corresponds to names.
  1025. func GetUserIDsByNames(names []string) []int64 {
  1026. ids := make([]int64, 0, len(names))
  1027. for _, name := range names {
  1028. u, err := GetUserByName(name)
  1029. if err != nil {
  1030. continue
  1031. }
  1032. ids = append(ids, u.ID)
  1033. }
  1034. return ids
  1035. }
  1036. // UserCommit represents a commit with validation of user.
  1037. type UserCommit struct {
  1038. User *User
  1039. *git.Commit
  1040. }
  1041. // ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user.
  1042. func ValidateCommitWithEmail(c *git.Commit) *User {
  1043. u, err := GetUserByEmail(c.Author.Email)
  1044. if err != nil {
  1045. return nil
  1046. }
  1047. return u
  1048. }
  1049. // ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
  1050. func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
  1051. var (
  1052. u *User
  1053. emails = map[string]*User{}
  1054. newCommits = list.New()
  1055. e = oldCommits.Front()
  1056. )
  1057. for e != nil {
  1058. c := e.Value.(*git.Commit)
  1059. if v, ok := emails[c.Author.Email]; !ok {
  1060. u, _ = GetUserByEmail(c.Author.Email)
  1061. emails[c.Author.Email] = u
  1062. } else {
  1063. u = v
  1064. }
  1065. newCommits.PushBack(UserCommit{
  1066. User: u,
  1067. Commit: c,
  1068. })
  1069. e = e.Next()
  1070. }
  1071. return newCommits
  1072. }
  1073. // GetUserByEmail returns the user object by given e-mail if exists.
  1074. func GetUserByEmail(email string) (*User, error) {
  1075. if len(email) == 0 {
  1076. return nil, ErrUserNotExist{0, email, 0}
  1077. }
  1078. email = strings.ToLower(email)
  1079. // First try to find the user by primary email
  1080. user := &User{Email: email}
  1081. has, err := x.Get(user)
  1082. if err != nil {
  1083. return nil, err
  1084. }
  1085. if has {
  1086. return user, nil
  1087. }
  1088. // Otherwise, check in alternative list for activated email addresses
  1089. emailAddress := &EmailAddress{Email: email, IsActivated: true}
  1090. has, err = x.Get(emailAddress)
  1091. if err != nil {
  1092. return nil, err
  1093. }
  1094. if has {
  1095. return GetUserByID(emailAddress.UID)
  1096. }
  1097. return nil, ErrUserNotExist{0, email, 0}
  1098. }
  1099. // GetUser checks if a user already exists
  1100. func GetUser(user *User) (bool, error) {
  1101. return x.Get(user)
  1102. }
  1103. // SearchUserOptions contains the options for searching
  1104. type SearchUserOptions struct {
  1105. Keyword string
  1106. Type UserType
  1107. OrderBy string
  1108. Page int
  1109. PageSize int // Can be smaller than or equal to setting.UI.ExplorePagingNum
  1110. }
  1111. // SearchUserByName takes keyword and part of user name to search,
  1112. // it returns results in given range and number of total results.
  1113. func SearchUserByName(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
  1114. if len(opts.Keyword) == 0 {
  1115. return users, 0, nil
  1116. }
  1117. opts.Keyword = strings.ToLower(opts.Keyword)
  1118. if opts.PageSize <= 0 || opts.PageSize > setting.UI.ExplorePagingNum {
  1119. opts.PageSize = setting.UI.ExplorePagingNum
  1120. }
  1121. if opts.Page <= 0 {
  1122. opts.Page = 1
  1123. }
  1124. users = make([]*User, 0, opts.PageSize)
  1125. // Append conditions
  1126. cond := builder.And(
  1127. builder.Eq{"type": opts.Type},
  1128. builder.Or(
  1129. builder.Like{"lower_name", opts.Keyword},
  1130. builder.Like{"LOWER(full_name)", opts.Keyword},
  1131. ),
  1132. )
  1133. count, err := x.Where(cond).Count(new(User))
  1134. if err != nil {
  1135. return nil, 0, fmt.Errorf("Count: %v", err)
  1136. }
  1137. sess := x.Where(cond).
  1138. Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
  1139. if len(opts.OrderBy) > 0 {
  1140. sess.OrderBy(opts.OrderBy)
  1141. }
  1142. return users, count, sess.Find(&users)
  1143. }
  1144. // GetStarredRepos returns the repos starred by a particular user
  1145. func GetStarredRepos(userID int64, private bool) ([]*Repository, error) {
  1146. sess := x.Where("star.uid=?", userID).
  1147. Join("LEFT", "star", "`repository`.id=`star`.repo_id")
  1148. if !private {
  1149. sess = sess.And("is_private=?", false)
  1150. }
  1151. repos := make([]*Repository, 0, 10)
  1152. err := sess.Find(&repos)
  1153. if err != nil {
  1154. return nil, err
  1155. }
  1156. return repos, nil
  1157. }
  1158. // GetWatchedRepos returns the repos watched by a particular user
  1159. func GetWatchedRepos(userID int64, private bool) ([]*Repository, error) {
  1160. sess := x.Where("watch.user_id=?", userID).
  1161. Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
  1162. if !private {
  1163. sess = sess.And("is_private=?", false)
  1164. }
  1165. repos := make([]*Repository, 0, 10)
  1166. err := sess.Find(&repos)
  1167. if err != nil {
  1168. return nil, err
  1169. }
  1170. return repos, nil
  1171. }
  1172. // SyncExternalUsers is used to synchronize users with external authorization source
  1173. func SyncExternalUsers() {
  1174. if !taskStatusTable.StartIfNotRunning(syncExternalUsers) {
  1175. return
  1176. }
  1177. defer taskStatusTable.Stop(syncExternalUsers)
  1178. log.Trace("Doing: SyncExternalUsers")
  1179. ls, err := LoginSources()
  1180. if err != nil {
  1181. log.Error(4, "SyncExternalUsers: %v", err)
  1182. return
  1183. }
  1184. updateExisting := setting.Cron.SyncExternalUsers.UpdateExisting
  1185. for _, s := range ls {
  1186. if !s.IsActived || !s.IsSyncEnabled {
  1187. continue
  1188. }
  1189. if s.IsLDAP() {
  1190. log.Trace("Doing: SyncExternalUsers[%s]", s.Name)
  1191. var existingUsers []int64
  1192. // Find all users with this login type
  1193. var users []User
  1194. x.Where("login_type = ?", LoginLDAP).
  1195. And("login_source = ?", s.ID).
  1196. Find(&users)
  1197. sr := s.LDAP().SearchEntries()
  1198. for _, su := range sr {
  1199. if len(su.Username) == 0 {
  1200. continue
  1201. }
  1202. if len(su.Mail) == 0 {
  1203. su.Mail = fmt.Sprintf("%s@localhost", su.Username)
  1204. }
  1205. var usr *User
  1206. // Search for existing user
  1207. for _, du := range users {
  1208. if du.LowerName == strings.ToLower(su.Username) {
  1209. usr = &du
  1210. break
  1211. }
  1212. }
  1213. fullName := composeFullName(su.Name, su.Surname, su.Username)
  1214. // If no existing user found, create one
  1215. if usr == nil {
  1216. log.Trace("SyncExternalUsers[%s]: Creating user %s", s.Name, su.Username)
  1217. usr = &User{
  1218. LowerName: strings.ToLower(su.Username),
  1219. Name: su.Username,
  1220. FullName: fullName,
  1221. LoginType: s.Type,
  1222. LoginSource: s.ID,
  1223. LoginName: su.Username,
  1224. Email: su.Mail,
  1225. IsAdmin: su.IsAdmin,
  1226. IsActive: true,
  1227. }
  1228. err = CreateUser(usr)
  1229. if err != nil {
  1230. log.Error(4, "SyncExternalUsers[%s]: Error creating user %s: %v", s.Name, su.Username, err)
  1231. }
  1232. } else if updateExisting {
  1233. existingUsers = append(existingUsers, usr.ID)
  1234. // Check if user data has changed
  1235. if (len(s.LDAP().AdminFilter) > 0 && usr.IsAdmin != su.IsAdmin) ||
  1236. strings.ToLower(usr.Email) != strings.ToLower(su.Mail) ||
  1237. usr.FullName != fullName ||
  1238. !usr.IsActive {
  1239. log.Trace("SyncExternalUsers[%s]: Updating user %s", s.Name, usr.Name)
  1240. usr.FullName = fullName
  1241. usr.Email = su.Mail
  1242. // Change existing admin flag only if AdminFilter option is set
  1243. if len(s.LDAP().AdminFilter) > 0 {
  1244. usr.IsAdmin = su.IsAdmin
  1245. }
  1246. usr.IsActive = true
  1247. err = UpdateUserCols(usr, "full_name", "email", "is_admin", "is_active")
  1248. if err != nil {
  1249. log.Error(4, "SyncExternalUsers[%s]: Error updating user %s: %v", s.Name, usr.Name, err)
  1250. }
  1251. }
  1252. }
  1253. }
  1254. // Deactivate users not present in LDAP
  1255. if updateExisting {
  1256. for _, usr := range users {
  1257. found := false
  1258. for _, uid := range existingUsers {
  1259. if usr.ID == uid {
  1260. found = true
  1261. break
  1262. }
  1263. }
  1264. if !found {
  1265. log.Trace("SyncExternalUsers[%s]: Deactivating user %s", s.Name, usr.Name)
  1266. usr.IsActive = false
  1267. err = UpdateUserCols(&usr, "is_active")
  1268. if err != nil {
  1269. log.Error(4, "SyncExternalUsers[%s]: Error deactivating user %s: %v", s.Name, usr.Name, err)
  1270. }
  1271. }
  1272. }
  1273. }
  1274. }
  1275. }
  1276. }