gitea源码

user_test.go 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user_test
  4. import (
  5. "crypto/rand"
  6. "fmt"
  7. "strings"
  8. "testing"
  9. "time"
  10. "code.gitea.io/gitea/models/auth"
  11. "code.gitea.io/gitea/models/db"
  12. "code.gitea.io/gitea/models/unittest"
  13. user_model "code.gitea.io/gitea/models/user"
  14. "code.gitea.io/gitea/modules/auth/password/hash"
  15. "code.gitea.io/gitea/modules/container"
  16. "code.gitea.io/gitea/modules/optional"
  17. "code.gitea.io/gitea/modules/setting"
  18. "code.gitea.io/gitea/modules/structs"
  19. "code.gitea.io/gitea/modules/test"
  20. "code.gitea.io/gitea/modules/timeutil"
  21. "github.com/stretchr/testify/assert"
  22. "github.com/stretchr/testify/require"
  23. )
  24. func TestIsUsableUsername(t *testing.T) {
  25. assert.NoError(t, user_model.IsUsableUsername("a"))
  26. assert.NoError(t, user_model.IsUsableUsername("foo.wiki"))
  27. assert.NoError(t, user_model.IsUsableUsername("foo.git"))
  28. assert.Error(t, user_model.IsUsableUsername("a--b"))
  29. assert.Error(t, user_model.IsUsableUsername("-1_."))
  30. assert.Error(t, user_model.IsUsableUsername(".profile"))
  31. assert.Error(t, user_model.IsUsableUsername("-"))
  32. assert.Error(t, user_model.IsUsableUsername("🌞"))
  33. assert.Error(t, user_model.IsUsableUsername("the..repo"))
  34. assert.Error(t, user_model.IsUsableUsername("foo.RSS"))
  35. assert.Error(t, user_model.IsUsableUsername("foo.PnG"))
  36. }
  37. func TestOAuth2Application_LoadUser(t *testing.T) {
  38. assert.NoError(t, unittest.PrepareTestDatabase())
  39. app := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: 1})
  40. user, err := user_model.GetUserByID(t.Context(), app.UID)
  41. assert.NoError(t, err)
  42. assert.NotNil(t, user)
  43. }
  44. func TestUserEmails(t *testing.T) {
  45. assert.NoError(t, unittest.PrepareTestDatabase())
  46. t.Run("GetUserEmailsByNames", func(t *testing.T) {
  47. // ignore none active user email
  48. assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(t.Context(), []string{"user8", "user9"}))
  49. assert.ElementsMatch(t, []string{"user8@example.com", "user5@example.com"}, user_model.GetUserEmailsByNames(t.Context(), []string{"user8", "user5"}))
  50. assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(t.Context(), []string{"user8", "org7"}))
  51. })
  52. t.Run("GetUsersByEmails", func(t *testing.T) {
  53. defer test.MockVariableValue(&setting.Service.NoReplyAddress, "NoReply.gitea.internal")()
  54. testGetUserByEmail := func(t *testing.T, email string, uid int64) {
  55. m, err := user_model.GetUsersByEmails(t.Context(), []string{email})
  56. require.NoError(t, err)
  57. user := m.GetByEmail(email)
  58. if uid == 0 {
  59. require.Nil(t, user)
  60. return
  61. }
  62. require.NotNil(t, user)
  63. assert.Equal(t, uid, user.ID)
  64. }
  65. cases := []struct {
  66. Email string
  67. UID int64
  68. }{
  69. {"UseR1@example.com", 1},
  70. {"user1-2@example.COM", 1},
  71. {"USER2@" + setting.Service.NoReplyAddress, 2},
  72. {"user4@example.com", 4},
  73. {"no-such", 0},
  74. }
  75. for _, c := range cases {
  76. t.Run(c.Email, func(t *testing.T) {
  77. testGetUserByEmail(t, c.Email, c.UID)
  78. })
  79. }
  80. t.Run("NoReplyConflict", func(t *testing.T) {
  81. setting.Service.NoReplyAddress = "example.com"
  82. testGetUserByEmail(t, "user1-2@example.COM", 1)
  83. })
  84. })
  85. }
  86. func TestCanCreateOrganization(t *testing.T) {
  87. assert.NoError(t, unittest.PrepareTestDatabase())
  88. admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  89. assert.True(t, admin.CanCreateOrganization())
  90. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  91. assert.True(t, user.CanCreateOrganization())
  92. // Disable user create organization permission.
  93. user.AllowCreateOrganization = false
  94. assert.False(t, user.CanCreateOrganization())
  95. setting.Admin.DisableRegularOrgCreation = true
  96. user.AllowCreateOrganization = true
  97. assert.True(t, admin.CanCreateOrganization())
  98. assert.False(t, user.CanCreateOrganization())
  99. }
  100. func TestSearchUsers(t *testing.T) {
  101. assert.NoError(t, unittest.PrepareTestDatabase())
  102. testSuccess := func(opts user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
  103. users, _, err := user_model.SearchUsers(t.Context(), opts)
  104. assert.NoError(t, err)
  105. cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts)
  106. if assert.Len(t, users, len(expectedUserOrOrgIDs), "case: %s", cassText) {
  107. for i, expectedID := range expectedUserOrOrgIDs {
  108. assert.Equal(t, expectedID, users[i].ID, "case: %s", cassText)
  109. }
  110. }
  111. }
  112. // test orgs
  113. testOrgSuccess := func(opts user_model.SearchUserOptions, expectedOrgIDs []int64) {
  114. opts.Type = user_model.UserTypeOrganization
  115. testSuccess(opts, expectedOrgIDs)
  116. }
  117. testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1, PageSize: 2}},
  118. []int64{3, 6})
  119. testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 2, PageSize: 2}},
  120. []int64{7, 17})
  121. testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 3, PageSize: 2}},
  122. []int64{19, 25})
  123. testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}},
  124. []int64{26, 41})
  125. testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 5, PageSize: 2}},
  126. []int64{42})
  127. testOrgSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 6, PageSize: 2}},
  128. []int64{})
  129. // test users
  130. testUserSuccess := func(opts user_model.SearchUserOptions, expectedUserIDs []int64) {
  131. opts.Type = user_model.UserTypeIndividual
  132. testSuccess(opts, expectedUserIDs)
  133. }
  134. testUserSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
  135. []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
  136. testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(false)},
  137. []int64{9})
  138. testUserSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
  139. []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
  140. testUserSuccess(user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
  141. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  142. // order by name asc default
  143. testUserSuccess(user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
  144. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  145. testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: optional.Some(true)},
  146. []int64{1})
  147. testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: optional.Some(true)},
  148. []int64{29})
  149. testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: optional.Some(true)},
  150. []int64{37})
  151. testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)},
  152. []int64{24})
  153. }
  154. func TestEmailNotificationPreferences(t *testing.T) {
  155. assert.NoError(t, unittest.PrepareTestDatabase())
  156. for _, test := range []struct {
  157. expected string
  158. userID int64
  159. }{
  160. {user_model.EmailNotificationsEnabled, 1},
  161. {user_model.EmailNotificationsEnabled, 2},
  162. {user_model.EmailNotificationsOnMention, 3},
  163. {user_model.EmailNotificationsOnMention, 4},
  164. {user_model.EmailNotificationsEnabled, 5},
  165. {user_model.EmailNotificationsEnabled, 6},
  166. {user_model.EmailNotificationsDisabled, 7},
  167. {user_model.EmailNotificationsEnabled, 8},
  168. {user_model.EmailNotificationsOnMention, 9},
  169. } {
  170. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.userID})
  171. assert.Equal(t, test.expected, user.EmailNotificationsPreference)
  172. }
  173. }
  174. func TestHashPasswordDeterministic(t *testing.T) {
  175. b := make([]byte, 16)
  176. u := &user_model.User{}
  177. algos := hash.RecommendedHashAlgorithms
  178. for j := range algos {
  179. u.PasswdHashAlgo = algos[j]
  180. for range 50 {
  181. // generate a random password
  182. rand.Read(b)
  183. pass := string(b)
  184. // save the current password in the user - hash it and store the result
  185. u.SetPassword(pass)
  186. r1 := u.Passwd
  187. // run again
  188. u.SetPassword(pass)
  189. r2 := u.Passwd
  190. assert.NotEqual(t, r1, r2)
  191. assert.True(t, u.ValidatePassword(pass))
  192. }
  193. }
  194. }
  195. func BenchmarkHashPassword(b *testing.B) {
  196. // BenchmarkHashPassword ensures that it takes a reasonable amount of time
  197. // to hash a password - in order to protect from brute-force attacks.
  198. pass := "password1337"
  199. u := &user_model.User{Passwd: pass}
  200. b.ResetTimer()
  201. for b.Loop() {
  202. u.SetPassword(pass)
  203. }
  204. }
  205. func TestNewGitSig(t *testing.T) {
  206. users := make([]*user_model.User, 0, 20)
  207. err := db.GetEngine(t.Context()).Find(&users)
  208. assert.NoError(t, err)
  209. for _, user := range users {
  210. sig := user.NewGitSig()
  211. assert.NotContains(t, sig.Name, "<")
  212. assert.NotContains(t, sig.Name, ">")
  213. assert.NotContains(t, sig.Name, "\n")
  214. assert.NotEmpty(t, strings.TrimSpace(sig.Name))
  215. }
  216. }
  217. func TestDisplayName(t *testing.T) {
  218. users := make([]*user_model.User, 0, 20)
  219. err := db.GetEngine(t.Context()).Find(&users)
  220. assert.NoError(t, err)
  221. for _, user := range users {
  222. displayName := user.DisplayName()
  223. assert.Equal(t, strings.TrimSpace(displayName), displayName)
  224. if len(strings.TrimSpace(user.FullName)) == 0 {
  225. assert.Equal(t, user.Name, displayName)
  226. }
  227. assert.NotEmpty(t, strings.TrimSpace(displayName))
  228. }
  229. }
  230. func TestCreateUserInvalidEmail(t *testing.T) {
  231. user := &user_model.User{
  232. Name: "GiteaBot",
  233. Email: "GiteaBot@gitea.io\r\n",
  234. Passwd: ";p['////..-++']",
  235. IsAdmin: false,
  236. Theme: setting.UI.DefaultTheme,
  237. MustChangePassword: false,
  238. }
  239. err := user_model.CreateUser(t.Context(), user, &user_model.Meta{})
  240. assert.Error(t, err)
  241. assert.True(t, user_model.IsErrEmailCharIsNotSupported(err))
  242. }
  243. func TestCreateUserEmailAlreadyUsed(t *testing.T) {
  244. assert.NoError(t, unittest.PrepareTestDatabase())
  245. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  246. // add new user with user2's email
  247. user.Name = "testuser"
  248. user.LowerName = strings.ToLower(user.Name)
  249. user.ID = 0
  250. err := user_model.CreateUser(t.Context(), user, &user_model.Meta{})
  251. assert.Error(t, err)
  252. assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
  253. }
  254. func TestCreateUserCustomTimestamps(t *testing.T) {
  255. assert.NoError(t, unittest.PrepareTestDatabase())
  256. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  257. // Add new user with a custom creation timestamp.
  258. var creationTimestamp timeutil.TimeStamp = 12345
  259. user.Name = "testuser"
  260. user.LowerName = strings.ToLower(user.Name)
  261. user.ID = 0
  262. user.Email = "unique@example.com"
  263. user.CreatedUnix = creationTimestamp
  264. err := user_model.CreateUser(t.Context(), user, &user_model.Meta{})
  265. assert.NoError(t, err)
  266. fetched, err := user_model.GetUserByID(t.Context(), user.ID)
  267. assert.NoError(t, err)
  268. assert.Equal(t, creationTimestamp, fetched.CreatedUnix)
  269. assert.Equal(t, creationTimestamp, fetched.UpdatedUnix)
  270. }
  271. func TestCreateUserWithoutCustomTimestamps(t *testing.T) {
  272. assert.NoError(t, unittest.PrepareTestDatabase())
  273. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  274. // There is no way to use a mocked time for the XORM auto-time functionality,
  275. // so use the real clock to approximate the expected timestamp.
  276. timestampStart := time.Now().Unix()
  277. // Add new user without a custom creation timestamp.
  278. user.Name = "Testuser"
  279. user.LowerName = strings.ToLower(user.Name)
  280. user.ID = 0
  281. user.Email = "unique@example.com"
  282. user.CreatedUnix = 0
  283. user.UpdatedUnix = 0
  284. err := user_model.CreateUser(t.Context(), user, &user_model.Meta{})
  285. assert.NoError(t, err)
  286. timestampEnd := time.Now().Unix()
  287. fetched, err := user_model.GetUserByID(t.Context(), user.ID)
  288. assert.NoError(t, err)
  289. assert.LessOrEqual(t, timestampStart, fetched.CreatedUnix)
  290. assert.LessOrEqual(t, fetched.CreatedUnix, timestampEnd)
  291. assert.LessOrEqual(t, timestampStart, fetched.UpdatedUnix)
  292. assert.LessOrEqual(t, fetched.UpdatedUnix, timestampEnd)
  293. }
  294. func TestGetUserIDsByNames(t *testing.T) {
  295. assert.NoError(t, unittest.PrepareTestDatabase())
  296. // ignore non existing
  297. IDs, err := user_model.GetUserIDsByNames(t.Context(), []string{"user1", "user2", "none_existing_user"}, true)
  298. assert.NoError(t, err)
  299. assert.Equal(t, []int64{1, 2}, IDs)
  300. // ignore non existing
  301. IDs, err = user_model.GetUserIDsByNames(t.Context(), []string{"user1", "do_not_exist"}, false)
  302. assert.Error(t, err)
  303. assert.Equal(t, []int64(nil), IDs)
  304. }
  305. func TestGetMaileableUsersByIDs(t *testing.T) {
  306. assert.NoError(t, unittest.PrepareTestDatabase())
  307. results, err := user_model.GetMailableUsersByIDs(t.Context(), []int64{1, 4}, false)
  308. assert.NoError(t, err)
  309. assert.Len(t, results, 1)
  310. if len(results) > 1 {
  311. assert.Equal(t, 1, results[0].ID)
  312. }
  313. results, err = user_model.GetMailableUsersByIDs(t.Context(), []int64{1, 4}, true)
  314. assert.NoError(t, err)
  315. assert.Len(t, results, 2)
  316. if len(results) > 2 {
  317. assert.Equal(t, 1, results[0].ID)
  318. assert.Equal(t, 4, results[1].ID)
  319. }
  320. }
  321. func TestNewUserRedirect(t *testing.T) {
  322. // redirect to a completely new name
  323. assert.NoError(t, unittest.PrepareTestDatabase())
  324. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  325. assert.NoError(t, user_model.NewUserRedirect(t.Context(), user.ID, user.Name, "newusername"))
  326. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  327. LowerName: user.LowerName,
  328. RedirectUserID: user.ID,
  329. })
  330. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  331. LowerName: "olduser1",
  332. RedirectUserID: user.ID,
  333. })
  334. }
  335. func TestNewUserRedirect2(t *testing.T) {
  336. // redirect to previously used name
  337. assert.NoError(t, unittest.PrepareTestDatabase())
  338. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  339. assert.NoError(t, user_model.NewUserRedirect(t.Context(), user.ID, user.Name, "olduser1"))
  340. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  341. LowerName: user.LowerName,
  342. RedirectUserID: user.ID,
  343. })
  344. unittest.AssertNotExistsBean(t, &user_model.Redirect{
  345. LowerName: "olduser1",
  346. RedirectUserID: user.ID,
  347. })
  348. }
  349. func TestNewUserRedirect3(t *testing.T) {
  350. // redirect for a previously-unredirected user
  351. assert.NoError(t, unittest.PrepareTestDatabase())
  352. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  353. assert.NoError(t, user_model.NewUserRedirect(t.Context(), user.ID, user.Name, "newusername"))
  354. unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
  355. LowerName: user.LowerName,
  356. RedirectUserID: user.ID,
  357. })
  358. }
  359. func TestGetUserByOpenID(t *testing.T) {
  360. assert.NoError(t, unittest.PrepareTestDatabase())
  361. _, err := user_model.GetUserByOpenID(t.Context(), "https://unknown")
  362. if assert.Error(t, err) {
  363. assert.True(t, user_model.IsErrUserNotExist(err))
  364. }
  365. user, err := user_model.GetUserByOpenID(t.Context(), "https://user1.domain1.tld")
  366. if assert.NoError(t, err) {
  367. assert.Equal(t, int64(1), user.ID)
  368. }
  369. user, err = user_model.GetUserByOpenID(t.Context(), "https://domain1.tld/user2/")
  370. if assert.NoError(t, err) {
  371. assert.Equal(t, int64(2), user.ID)
  372. }
  373. }
  374. func TestFollowUser(t *testing.T) {
  375. assert.NoError(t, unittest.PrepareTestDatabase())
  376. testSuccess := func(follower, followed *user_model.User) {
  377. assert.NoError(t, user_model.FollowUser(t.Context(), follower, followed))
  378. unittest.AssertExistsAndLoadBean(t, &user_model.Follow{UserID: follower.ID, FollowID: followed.ID})
  379. }
  380. user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
  381. user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
  382. user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
  383. testSuccess(user4, user2)
  384. testSuccess(user5, user2)
  385. assert.NoError(t, user_model.FollowUser(t.Context(), user2, user2))
  386. unittest.CheckConsistencyFor(t, &user_model.User{})
  387. }
  388. func TestUnfollowUser(t *testing.T) {
  389. assert.NoError(t, unittest.PrepareTestDatabase())
  390. testSuccess := func(followerID, followedID int64) {
  391. assert.NoError(t, user_model.UnfollowUser(t.Context(), followerID, followedID))
  392. unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID})
  393. }
  394. testSuccess(4, 2)
  395. testSuccess(5, 2)
  396. testSuccess(2, 2)
  397. unittest.CheckConsistencyFor(t, &user_model.User{})
  398. }
  399. func TestIsUserVisibleToViewer(t *testing.T) {
  400. assert.NoError(t, unittest.PrepareTestDatabase())
  401. user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) // admin, public
  402. user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // normal, public
  403. user20 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}) // public, same team as user31
  404. user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) // public, is restricted
  405. user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31}) // private, same team as user20
  406. user33 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 33}) // limited, follows 31
  407. test := func(u, viewer *user_model.User, expected bool) {
  408. name := func(u *user_model.User) string {
  409. if u == nil {
  410. return "<nil>"
  411. }
  412. return u.Name
  413. }
  414. assert.Equal(t, expected, user_model.IsUserVisibleToViewer(t.Context(), u, viewer), "user %v should be visible to viewer %v: %v", name(u), name(viewer), expected)
  415. }
  416. // admin viewer
  417. test(user1, user1, true)
  418. test(user20, user1, true)
  419. test(user31, user1, true)
  420. test(user33, user1, true)
  421. // non admin viewer
  422. test(user4, user4, true)
  423. test(user20, user4, true)
  424. test(user31, user4, false)
  425. test(user33, user4, true)
  426. test(user4, nil, true)
  427. // public user
  428. test(user4, user20, true)
  429. test(user4, user31, true)
  430. test(user4, user33, true)
  431. // limited user
  432. test(user33, user33, true)
  433. test(user33, user4, true)
  434. test(user33, user29, false)
  435. test(user33, nil, false)
  436. // private user
  437. test(user31, user31, true)
  438. test(user31, user4, false)
  439. test(user31, user20, true)
  440. test(user31, user29, false)
  441. test(user31, user33, true)
  442. test(user31, nil, false)
  443. }
  444. func Test_ValidateUser(t *testing.T) {
  445. defer test.MockVariableValue(&setting.Service.AllowedUserVisibilityModesSlice, []bool{true, false, true})()
  446. kases := map[*user_model.User]bool{
  447. {ID: 1, Visibility: structs.VisibleTypePublic}: true,
  448. {ID: 2, Visibility: structs.VisibleTypeLimited}: false,
  449. {ID: 2, Visibility: structs.VisibleTypePrivate}: true,
  450. }
  451. for kase, expected := range kases {
  452. assert.Equal(t, expected, nil == user_model.ValidateUser(kase), "case: %+v", kase)
  453. }
  454. }
  455. func Test_NormalizeUserFromEmail(t *testing.T) {
  456. testCases := []struct {
  457. Input string
  458. Expected string
  459. IsNormalizedValid bool
  460. }{
  461. {"name@example.com", "name", true},
  462. {"test'`´name", "testname", true},
  463. {"Sinéad.O'Connor", "Sinead.OConnor", true},
  464. {"Æsir", "AEsir", true},
  465. {"éé", "ee", true}, // \u00e9\u0065\u0301
  466. {"Awareness Hub", "Awareness-Hub", true},
  467. {"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
  468. {".bad.", ".bad.", false},
  469. {"new😀user", "new😀user", false}, // No plans to support
  470. {`"quoted"`, `"quoted"`, false}, // No plans to support
  471. }
  472. for _, testCase := range testCases {
  473. normalizedName, err := user_model.NormalizeUserName(testCase.Input)
  474. assert.NoError(t, err)
  475. assert.Equal(t, testCase.Expected, normalizedName)
  476. if testCase.IsNormalizedValid {
  477. assert.NoError(t, user_model.IsUsableUsername(normalizedName))
  478. } else {
  479. assert.Error(t, user_model.IsUsableUsername(normalizedName))
  480. }
  481. }
  482. }
  483. func TestEmailTo(t *testing.T) {
  484. testCases := []struct {
  485. fullName string
  486. mail string
  487. result string
  488. }{
  489. {"Awareness Hub", "awareness@hub.net", "Awareness Hub <awareness@hub.net>"},
  490. {"name@example.com", "name@example.com", "name@example.com"},
  491. {"Hi Its <Mee>", "ee@mail.box", "Hi Its Mee <ee@mail.box>"},
  492. {"Sinéad.O'Connor", "sinead.oconnor@gmail.com", "=?utf-8?q?Sin=C3=A9ad.O'Connor?= <sinead.oconnor@gmail.com>"},
  493. {"Æsir", "aesir@gmx.de", "=?utf-8?q?=C3=86sir?= <aesir@gmx.de>"},
  494. {"new😀user", "new.user@alo.com", "=?utf-8?q?new=F0=9F=98=80user?= <new.user@alo.com>"},
  495. {`"quoted"`, "quoted@test.com", "quoted <quoted@test.com>"},
  496. }
  497. for _, testCase := range testCases {
  498. t.Run(testCase.result, func(t *testing.T) {
  499. testUser := &user_model.User{FullName: testCase.fullName, Email: testCase.mail}
  500. assert.Equal(t, testCase.result, testUser.EmailTo())
  501. })
  502. }
  503. }
  504. func TestDisabledUserFeatures(t *testing.T) {
  505. assert.NoError(t, unittest.PrepareTestDatabase())
  506. testValues := container.SetOf(setting.UserFeatureDeletion,
  507. setting.UserFeatureManageSSHKeys,
  508. setting.UserFeatureManageGPGKeys)
  509. defer test.MockVariableValue(&setting.Admin.ExternalUserDisableFeatures, testValues)()
  510. user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
  511. assert.Empty(t, setting.Admin.UserDisabledFeatures.Values())
  512. // no features should be disabled with a plain login type
  513. assert.LessOrEqual(t, user.LoginType, auth.Plain)
  514. assert.Empty(t, user_model.DisabledFeaturesWithLoginType(user).Values())
  515. for _, f := range testValues.Values() {
  516. assert.False(t, user_model.IsFeatureDisabledWithLoginType(user, f))
  517. }
  518. // check disabled features with external login type
  519. user.LoginType = auth.OAuth2
  520. // all features should be disabled
  521. assert.NotEmpty(t, user_model.DisabledFeaturesWithLoginType(user).Values())
  522. for _, f := range testValues.Values() {
  523. assert.True(t, user_model.IsFeatureDisabledWithLoginType(user, f))
  524. }
  525. }
  526. func TestGetInactiveUsers(t *testing.T) {
  527. assert.NoError(t, unittest.PrepareTestDatabase())
  528. // all inactive users
  529. // user1's createdunix is 1730468968
  530. users, err := user_model.GetInactiveUsers(t.Context(), 0)
  531. assert.NoError(t, err)
  532. assert.Len(t, users, 1)
  533. interval := time.Now().Unix() - 1730468968 + 3600*24
  534. users, err = user_model.GetInactiveUsers(t.Context(), time.Duration(interval*int64(time.Second)))
  535. assert.NoError(t, err)
  536. assert.Empty(t, users)
  537. }
  538. func TestCanCreateRepo(t *testing.T) {
  539. defer test.MockVariableValue(&setting.Repository.MaxCreationLimit)()
  540. const noLimit = -1
  541. doerNormal := &user_model.User{}
  542. doerAdmin := &user_model.User{IsAdmin: true}
  543. t.Run("NoGlobalLimit", func(t *testing.T) {
  544. setting.Repository.MaxCreationLimit = noLimit
  545. assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
  546. assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
  547. assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
  548. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
  549. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
  550. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
  551. })
  552. t.Run("GlobalLimit50", func(t *testing.T) {
  553. setting.Repository.MaxCreationLimit = 50
  554. assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
  555. assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: noLimit})) // limited by global limit
  556. assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
  557. assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
  558. assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: 100}))
  559. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
  560. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: noLimit}))
  561. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
  562. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
  563. assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: 100}))
  564. })
  565. }