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.

521 lines
13 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  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. "crypto/sha256"
  7. "encoding/hex"
  8. "errors"
  9. "fmt"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. "time"
  14. "github.com/gogits/git"
  15. "github.com/gogits/gogs/modules/base"
  16. "github.com/gogits/gogs/modules/log"
  17. )
  18. // User types.
  19. const (
  20. UT_INDIVIDUAL = iota + 1
  21. UT_ORGANIZATION
  22. )
  23. var (
  24. ErrUserOwnRepos = errors.New("User still have ownership of repositories")
  25. ErrUserAlreadyExist = errors.New("User already exist")
  26. ErrUserNotExist = errors.New("User does not exist")
  27. ErrEmailAlreadyUsed = errors.New("E-mail already used")
  28. ErrUserNameIllegal = errors.New("User name contains illegal characters")
  29. )
  30. // User represents the object of individual and member of organization.
  31. type User struct {
  32. Id int64
  33. LowerName string `xorm:"unique not null"`
  34. Name string `xorm:"unique not null"`
  35. FullName string
  36. Email string `xorm:"unique not null"`
  37. Passwd string `xorm:"not null"`
  38. LoginType int
  39. LoginSource int64 `xorm:"not null default 0"`
  40. Type int
  41. NumFollowers int
  42. NumFollowings int
  43. NumStars int
  44. NumRepos int
  45. Avatar string `xorm:"varchar(2048) not null"`
  46. AvatarEmail string `xorm:"not null"`
  47. Location string
  48. Website string
  49. IsActive bool
  50. IsAdmin bool
  51. Rands string `xorm:"VARCHAR(10)"`
  52. Salt string `xorm:"VARCHAR(10)"`
  53. Created time.Time `xorm:"created"`
  54. Updated time.Time `xorm:"updated"`
  55. }
  56. // HomeLink returns the user home page link.
  57. func (user *User) HomeLink() string {
  58. return "/user/" + user.Name
  59. }
  60. // AvatarLink returns the user gravatar link.
  61. func (user *User) AvatarLink() string {
  62. if base.DisableGravatar {
  63. return "/img/avatar_default.jpg"
  64. } else if base.Service.EnableCacheAvatar {
  65. return "/avatar/" + user.Avatar
  66. }
  67. return "//1.gravatar.com/avatar/" + user.Avatar
  68. }
  69. // NewGitSig generates and returns the signature of given user.
  70. func (user *User) NewGitSig() *git.Signature {
  71. return &git.Signature{
  72. Name: user.Name,
  73. Email: user.Email,
  74. When: time.Now(),
  75. }
  76. }
  77. // EncodePasswd encodes password to safe format.
  78. func (user *User) EncodePasswd() {
  79. newPasswd := base.PBKDF2([]byte(user.Passwd), []byte(user.Salt), 10000, 50, sha256.New)
  80. user.Passwd = fmt.Sprintf("%x", newPasswd)
  81. }
  82. // Member represents user is member of organization.
  83. type Member struct {
  84. Id int64
  85. OrgId int64 `xorm:"unique(member) index"`
  86. UserId int64 `xorm:"unique(member)"`
  87. }
  88. // IsUserExist checks if given user name exist,
  89. // the user name should be noncased unique.
  90. func IsUserExist(name string) (bool, error) {
  91. if len(name) == 0 {
  92. return false, nil
  93. }
  94. return orm.Get(&User{LowerName: strings.ToLower(name)})
  95. }
  96. // IsEmailUsed returns true if the e-mail has been used.
  97. func IsEmailUsed(email string) (bool, error) {
  98. if len(email) == 0 {
  99. return false, nil
  100. }
  101. return orm.Get(&User{Email: email})
  102. }
  103. // return a user salt token
  104. func GetUserSalt() string {
  105. return base.GetRandomString(10)
  106. }
  107. // RegisterUser creates record of a new user.
  108. func RegisterUser(user *User) (*User, error) {
  109. if !IsLegalName(user.Name) {
  110. return nil, ErrUserNameIllegal
  111. }
  112. isExist, err := IsUserExist(user.Name)
  113. if err != nil {
  114. return nil, err
  115. } else if isExist {
  116. return nil, ErrUserAlreadyExist
  117. }
  118. isExist, err = IsEmailUsed(user.Email)
  119. if err != nil {
  120. return nil, err
  121. } else if isExist {
  122. return nil, ErrEmailAlreadyUsed
  123. }
  124. user.LowerName = strings.ToLower(user.Name)
  125. user.Avatar = base.EncodeMd5(user.Email)
  126. user.AvatarEmail = user.Email
  127. user.Rands = GetUserSalt()
  128. user.Salt = GetUserSalt()
  129. user.EncodePasswd()
  130. if _, err = orm.Insert(user); err != nil {
  131. return nil, err
  132. } else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil {
  133. if _, err := orm.Id(user.Id).Delete(&User{}); err != nil {
  134. return nil, errors.New(fmt.Sprintf(
  135. "both create userpath %s and delete table record faild: %v", user.Name, err))
  136. }
  137. return nil, err
  138. }
  139. if user.Id == 1 {
  140. user.IsAdmin = true
  141. user.IsActive = true
  142. _, err = orm.Id(user.Id).UseBool().Update(user)
  143. }
  144. return user, err
  145. }
  146. // GetUsers returns given number of user objects with offset.
  147. func GetUsers(num, offset int) ([]User, error) {
  148. users := make([]User, 0, num)
  149. err := orm.Limit(num, offset).Asc("id").Find(&users)
  150. return users, err
  151. }
  152. // get user by erify code
  153. func getVerifyUser(code string) (user *User) {
  154. if len(code) <= base.TimeLimitCodeLength {
  155. return nil
  156. }
  157. // use tail hex username query user
  158. hexStr := code[base.TimeLimitCodeLength:]
  159. if b, err := hex.DecodeString(hexStr); err == nil {
  160. if user, err = GetUserByName(string(b)); user != nil {
  161. return user
  162. }
  163. log.Error("user.getVerifyUser: %v", err)
  164. }
  165. return nil
  166. }
  167. // verify active code when active account
  168. func VerifyUserActiveCode(code string) (user *User) {
  169. minutes := base.Service.ActiveCodeLives
  170. if user = getVerifyUser(code); user != nil {
  171. // time limit code
  172. prefix := code[:base.TimeLimitCodeLength]
  173. data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
  174. if base.VerifyTimeLimitCode(data, minutes, prefix) {
  175. return user
  176. }
  177. }
  178. return nil
  179. }
  180. // ChangeUserName changes all corresponding setting from old user name to new one.
  181. func ChangeUserName(user *User, newUserName string) (err error) {
  182. newUserName = strings.ToLower(newUserName)
  183. // Update accesses of user.
  184. accesses := make([]Access, 0, 10)
  185. if err = orm.Find(&accesses, &Access{UserName: user.LowerName}); err != nil {
  186. return err
  187. }
  188. sess := orm.NewSession()
  189. defer sess.Close()
  190. if err = sess.Begin(); err != nil {
  191. return err
  192. }
  193. for i := range accesses {
  194. accesses[i].UserName = newUserName
  195. if strings.HasPrefix(accesses[i].RepoName, user.LowerName+"/") {
  196. accesses[i].RepoName = strings.Replace(accesses[i].RepoName, user.LowerName, newUserName, 1)
  197. }
  198. if err = UpdateAccessWithSession(sess, &accesses[i]); err != nil {
  199. return err
  200. }
  201. }
  202. repos, err := GetRepositories(user, true)
  203. if err != nil {
  204. return err
  205. }
  206. for i := range repos {
  207. accesses = make([]Access, 0, 10)
  208. // Update accesses of user repository.
  209. if err = orm.Find(&accesses, &Access{RepoName: user.LowerName + "/" + repos[i].LowerName}); err != nil {
  210. return err
  211. }
  212. for j := range accesses {
  213. accesses[j].UserName = newUserName
  214. accesses[j].RepoName = newUserName + "/" + repos[i].LowerName
  215. if err = UpdateAccessWithSession(sess, &accesses[j]); err != nil {
  216. return err
  217. }
  218. }
  219. }
  220. // Change user directory name.
  221. if err = os.Rename(UserPath(user.LowerName), UserPath(newUserName)); err != nil {
  222. sess.Rollback()
  223. return err
  224. }
  225. return sess.Commit()
  226. }
  227. // UpdateUser updates user's information.
  228. func UpdateUser(user *User) (err error) {
  229. user.LowerName = strings.ToLower(user.Name)
  230. if len(user.Location) > 255 {
  231. user.Location = user.Location[:255]
  232. }
  233. if len(user.Website) > 255 {
  234. user.Website = user.Website[:255]
  235. }
  236. _, err = orm.Id(user.Id).AllCols().Update(user)
  237. return err
  238. }
  239. // DeleteUser completely deletes everything of the user.
  240. func DeleteUser(user *User) error {
  241. // Check ownership of repository.
  242. count, err := GetRepositoryCount(user)
  243. if err != nil {
  244. return errors.New("modesl.GetRepositories: " + err.Error())
  245. } else if count > 0 {
  246. return ErrUserOwnRepos
  247. }
  248. // TODO: check issues, other repos' commits
  249. // Delete all followers.
  250. if _, err = orm.Delete(&Follow{FollowId: user.Id}); err != nil {
  251. return err
  252. }
  253. // Delete oauth2.
  254. if _, err = orm.Delete(&Oauth2{Uid: user.Id}); err != nil {
  255. return err
  256. }
  257. // Delete all feeds.
  258. if _, err = orm.Delete(&Action{UserId: user.Id}); err != nil {
  259. return err
  260. }
  261. // Delete all watches.
  262. if _, err = orm.Delete(&Watch{Uid: user.Id}); err != nil {
  263. return err
  264. }
  265. // Delete all accesses.
  266. if _, err = orm.Delete(&Access{UserName: user.LowerName}); err != nil {
  267. return err
  268. }
  269. // Delete all SSH keys.
  270. keys := make([]*PublicKey, 0, 10)
  271. if err = orm.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil {
  272. return err
  273. }
  274. for _, key := range keys {
  275. if err = DeletePublicKey(key); err != nil {
  276. return err
  277. }
  278. }
  279. // Delete user directory.
  280. if err = os.RemoveAll(UserPath(user.Name)); err != nil {
  281. return err
  282. }
  283. _, err = orm.Delete(user)
  284. return err
  285. }
  286. // UserPath returns the path absolute path of user repositories.
  287. func UserPath(userName string) string {
  288. return filepath.Join(base.RepoRootPath, strings.ToLower(userName))
  289. }
  290. func GetUserByKeyId(keyId int64) (*User, error) {
  291. user := new(User)
  292. rawSql := "SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?"
  293. has, err := orm.Sql(rawSql, keyId).Get(user)
  294. if err != nil {
  295. return nil, err
  296. } else if !has {
  297. err = errors.New("not exist key owner")
  298. return nil, err
  299. }
  300. return user, nil
  301. }
  302. // GetUserById returns the user object by given id if exists.
  303. func GetUserById(id int64) (*User, error) {
  304. user := new(User)
  305. has, err := orm.Id(id).Get(user)
  306. if err != nil {
  307. return nil, err
  308. }
  309. if !has {
  310. return nil, ErrUserNotExist
  311. }
  312. return user, nil
  313. }
  314. // GetUserByName returns the user object by given name if exists.
  315. func GetUserByName(name string) (*User, error) {
  316. if len(name) == 0 {
  317. return nil, ErrUserNotExist
  318. }
  319. user := &User{LowerName: strings.ToLower(name)}
  320. has, err := orm.Get(user)
  321. if err != nil {
  322. return nil, err
  323. } else if !has {
  324. return nil, ErrUserNotExist
  325. }
  326. return user, nil
  327. }
  328. // GetUserEmailsByNames returns a slice of e-mails corresponds to names.
  329. func GetUserEmailsByNames(names []string) []string {
  330. mails := make([]string, 0, len(names))
  331. for _, name := range names {
  332. u, err := GetUserByName(name)
  333. if err != nil {
  334. continue
  335. }
  336. mails = append(mails, u.Email)
  337. }
  338. return mails
  339. }
  340. // GetUserIdsByNames returns a slice of ids corresponds to names.
  341. func GetUserIdsByNames(names []string) []int64 {
  342. ids := make([]int64, 0, len(names))
  343. for _, name := range names {
  344. u, err := GetUserByName(name)
  345. if err != nil {
  346. continue
  347. }
  348. ids = append(ids, u.Id)
  349. }
  350. return ids
  351. }
  352. // GetUserByEmail returns the user object by given e-mail if exists.
  353. func GetUserByEmail(email string) (*User, error) {
  354. if len(email) == 0 {
  355. return nil, ErrUserNotExist
  356. }
  357. user := &User{Email: strings.ToLower(email)}
  358. has, err := orm.Get(user)
  359. if err != nil {
  360. return nil, err
  361. } else if !has {
  362. return nil, ErrUserNotExist
  363. }
  364. return user, nil
  365. }
  366. // SearchUserByName returns given number of users whose name contains keyword.
  367. func SearchUserByName(key string, limit int) (us []*User, err error) {
  368. // Prevent SQL inject.
  369. key = strings.TrimSpace(key)
  370. if len(key) == 0 {
  371. return us, nil
  372. }
  373. key = strings.Split(key, " ")[0]
  374. if len(key) == 0 {
  375. return us, nil
  376. }
  377. key = strings.ToLower(key)
  378. us = make([]*User, 0, limit)
  379. err = orm.Limit(limit).Where("lower_name like '%" + key + "%'").Find(&us)
  380. return us, err
  381. }
  382. // LoginUserPlain validates user by raw user name and password.
  383. func LoginUserPlain(uname, passwd string) (*User, error) {
  384. var u *User
  385. if strings.Contains(uname, "@") {
  386. u = &User{Email: uname}
  387. } else {
  388. u = &User{LowerName: strings.ToLower(uname)}
  389. }
  390. has, err := orm.Get(u)
  391. if err != nil {
  392. return nil, err
  393. } else if !has {
  394. return nil, ErrUserNotExist
  395. }
  396. newUser := &User{Passwd: passwd, Salt: u.Salt}
  397. newUser.EncodePasswd()
  398. if u.Passwd != newUser.Passwd {
  399. return nil, ErrUserNotExist
  400. }
  401. return u, nil
  402. }
  403. // Follow is connection request for receiving user notifycation.
  404. type Follow struct {
  405. Id int64
  406. UserId int64 `xorm:"unique(follow)"`
  407. FollowId int64 `xorm:"unique(follow)"`
  408. }
  409. // FollowUser marks someone be another's follower.
  410. func FollowUser(userId int64, followId int64) (err error) {
  411. session := orm.NewSession()
  412. defer session.Close()
  413. session.Begin()
  414. if _, err = session.Insert(&Follow{UserId: userId, FollowId: followId}); err != nil {
  415. session.Rollback()
  416. return err
  417. }
  418. rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?"
  419. if _, err = session.Exec(rawSql, followId); err != nil {
  420. session.Rollback()
  421. return err
  422. }
  423. rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?"
  424. if _, err = session.Exec(rawSql, userId); err != nil {
  425. session.Rollback()
  426. return err
  427. }
  428. return session.Commit()
  429. }
  430. // UnFollowUser unmarks someone be another's follower.
  431. func UnFollowUser(userId int64, unFollowId int64) (err error) {
  432. session := orm.NewSession()
  433. defer session.Close()
  434. session.Begin()
  435. if _, err = session.Delete(&Follow{UserId: userId, FollowId: unFollowId}); err != nil {
  436. session.Rollback()
  437. return err
  438. }
  439. rawSql := "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?"
  440. if _, err = session.Exec(rawSql, unFollowId); err != nil {
  441. session.Rollback()
  442. return err
  443. }
  444. rawSql = "UPDATE `user` SET num_followings = num_followings - 1 WHERE id = ?"
  445. if _, err = session.Exec(rawSql, userId); err != nil {
  446. session.Rollback()
  447. return err
  448. }
  449. return session.Commit()
  450. }