organizations_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. // Copyright 2022 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 db
  5. import (
  6. "context"
  7. "os"
  8. "path/filepath"
  9. "testing"
  10. "time"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. "gogs.io/gogs/internal/conf"
  14. "gogs.io/gogs/internal/dbtest"
  15. "gogs.io/gogs/internal/errutil"
  16. )
  17. func TestOrganizations(t *testing.T) {
  18. if testing.Short() {
  19. t.Skip()
  20. }
  21. t.Parallel()
  22. ctx := context.Background()
  23. tables := []any{
  24. new(User), new(EmailAddress), new(OrgUser), new(Team), new(TeamUser), new(Repository), new(Watch), new(Star),
  25. new(Follow), new(Issue), new(PublicKey), new(AccessToken), new(Collaboration), new(Access), new(Action),
  26. new(IssueUser), new(TeamRepo),
  27. }
  28. db := &organizations{
  29. DB: dbtest.NewDB(t, "orgs", tables...),
  30. }
  31. for _, tc := range []struct {
  32. name string
  33. test func(t *testing.T, ctx context.Context, db *organizations)
  34. }{
  35. {"Create", orgsCreate},
  36. {"GetByName", orgsGetByName},
  37. {"SearchByName", orgsSearchByName},
  38. {"List", orgsList},
  39. {"CountByUser", orgsCountByUser},
  40. {"Count", orgsCount},
  41. {"DeleteByID", orgsDeleteByID},
  42. {"AddMember", orgsAddMember},
  43. {"RemoveMember", orgsRemoveMember},
  44. {"HasMember", orgsHasMember},
  45. {"ListMembers", orgsListMembers},
  46. {"IsOwnedBy", orgsIsOwnedBy},
  47. {"SetMemberVisibility", orgsSetMemberVisibility},
  48. } {
  49. t.Run(tc.name, func(t *testing.T) {
  50. t.Cleanup(func() {
  51. err := clearTables(t, db.DB, tables...)
  52. require.NoError(t, err)
  53. })
  54. tc.test(t, ctx, db)
  55. })
  56. if t.Failed() {
  57. break
  58. }
  59. }
  60. }
  61. func orgsCreate(t *testing.T, ctx context.Context, db *organizations) {
  62. usersStore := NewUsersStore(db.DB)
  63. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  64. require.NoError(t, err)
  65. t.Run("name not allowed", func(t *testing.T) {
  66. _, err := db.Create(ctx, "-", alice.ID, CreateOrganizationOptions{})
  67. wantErr := ErrNameNotAllowed{
  68. args: errutil.Args{
  69. "reason": "reserved",
  70. "name": "-",
  71. },
  72. }
  73. assert.Equal(t, wantErr, err)
  74. })
  75. // Users and organizations share the same namespace for names.
  76. t.Run("name already exists", func(t *testing.T) {
  77. _, err := db.Create(ctx, alice.Name, alice.ID, CreateOrganizationOptions{})
  78. wantErr := ErrOrganizationAlreadyExist{
  79. args: errutil.Args{
  80. "name": alice.Name,
  81. },
  82. }
  83. assert.Equal(t, wantErr, err)
  84. })
  85. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsCreate-tempPictureAvatarUploadPath")
  86. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  87. org, err := db.Create(
  88. ctx,
  89. "acme",
  90. alice.ID,
  91. CreateOrganizationOptions{
  92. FullName: "Acme Corp",
  93. Email: "admin@acme.com",
  94. Location: "Earth",
  95. Website: "acme.com",
  96. Description: "A popcorn company",
  97. },
  98. )
  99. require.NoError(t, err)
  100. got, err := db.GetByName(ctx, org.Name)
  101. require.NoError(t, err)
  102. assert.Equal(t, org.Name, got.Name)
  103. assert.Equal(t, org.FullName, got.FullName)
  104. assert.Equal(t, org.Email, got.Email)
  105. assert.Equal(t, org.Location, got.Location)
  106. assert.Equal(t, org.Website, got.Website)
  107. assert.Equal(t, org.Description, got.Description)
  108. assert.Equal(t, -1, got.MaxRepoCreation)
  109. assert.Equal(t, 1, got.NumTeams)
  110. assert.Equal(t, 1, got.NumMembers)
  111. assert.Equal(t, db.NowFunc().Format(time.RFC3339), got.Created.UTC().Format(time.RFC3339))
  112. assert.Equal(t, db.NowFunc().Format(time.RFC3339), got.Updated.UTC().Format(time.RFC3339))
  113. }
  114. func orgsGetByName(t *testing.T, ctx context.Context, db *organizations) {
  115. t.Run("correct user type", func(t *testing.T) {
  116. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "usersGetByUsername-tempPictureAvatarUploadPath")
  117. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  118. org1, err := db.Create(ctx, "org1", 1, CreateOrganizationOptions{})
  119. require.NoError(t, err)
  120. got, err := db.GetByName(ctx, org1.Name)
  121. require.NoError(t, err)
  122. assert.Equal(t, org1.Name, got.Name)
  123. _, err = db.GetByName(ctx, "bad_name")
  124. wantErr := ErrOrganizationNotExist{args: errutil.Args{"name": "bad_name"}}
  125. assert.Equal(t, wantErr, err)
  126. })
  127. t.Run("wrong user type", func(t *testing.T) {
  128. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  129. require.NoError(t, err)
  130. _, err = db.GetByName(ctx, alice.Name)
  131. wantErr := ErrOrganizationNotExist{args: errutil.Args{"name": alice.Name}}
  132. assert.Equal(t, wantErr, err)
  133. })
  134. }
  135. func orgsList(t *testing.T, ctx context.Context, db *organizations) {
  136. usersStore := NewUsersStore(db.DB)
  137. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  138. require.NoError(t, err)
  139. bob, err := usersStore.Create(ctx, "bob", "bob@example.com", CreateUserOptions{})
  140. require.NoError(t, err)
  141. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsList-tempPictureAvatarUploadPath")
  142. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  143. org1, err := db.Create(ctx, "org1-alice-owned", alice.ID, CreateOrganizationOptions{})
  144. require.NoError(t, err)
  145. org2, err := db.Create(ctx, "org2-alice-owned", alice.ID, CreateOrganizationOptions{})
  146. require.NoError(t, err)
  147. err = db.SetMemberVisibility(ctx, org2.ID, alice.ID, true)
  148. require.NoError(t, err)
  149. err = db.AddMember(ctx, org2.ID, bob.ID)
  150. require.NoError(t, err)
  151. org3, err := db.Create(ctx, "org3-bob-owned", bob.ID, CreateOrganizationOptions{})
  152. require.NoError(t, err)
  153. tests := []struct {
  154. name string
  155. opts ListOrganizationsOptions
  156. wantOrgNames []string
  157. }{
  158. {
  159. name: "only public memberships for a user",
  160. opts: ListOrganizationsOptions{
  161. MemberID: alice.ID,
  162. IncludePrivateMembers: false,
  163. },
  164. wantOrgNames: []string{org2.Name},
  165. },
  166. {
  167. name: "all memberships for a user",
  168. opts: ListOrganizationsOptions{
  169. MemberID: alice.ID,
  170. IncludePrivateMembers: true,
  171. },
  172. wantOrgNames: []string{org1.Name, org2.Name},
  173. },
  174. {
  175. name: "only public ownership for a user",
  176. opts: ListOrganizationsOptions{
  177. OwnerID: alice.ID,
  178. IncludePrivateMembers: false,
  179. },
  180. wantOrgNames: []string{org2.Name},
  181. },
  182. {
  183. name: "all ownership for a user",
  184. opts: ListOrganizationsOptions{
  185. OwnerID: alice.ID,
  186. IncludePrivateMembers: true,
  187. },
  188. wantOrgNames: []string{org1.Name, org2.Name},
  189. },
  190. {
  191. name: "no membership for a non-existent user",
  192. opts: ListOrganizationsOptions{
  193. MemberID: 404,
  194. IncludePrivateMembers: true,
  195. },
  196. wantOrgNames: []string{},
  197. },
  198. }
  199. for _, test := range tests {
  200. t.Run(test.name, func(t *testing.T) {
  201. got, err := db.List(ctx, test.opts)
  202. require.NoError(t, err)
  203. gotOrgNames := make([]string, len(got))
  204. for i := range got {
  205. gotOrgNames[i] = got[i].Name
  206. }
  207. assert.Equal(t, test.wantOrgNames, gotOrgNames)
  208. })
  209. }
  210. t.Run("pagination", func(t *testing.T) {
  211. got, err := db.List(ctx, ListOrganizationsOptions{Page: 1, PageSize: 1})
  212. require.NoError(t, err)
  213. require.Len(t, got, 1)
  214. assert.Equal(t, org1.ID, got[0].ID)
  215. got, err = db.List(ctx, ListOrganizationsOptions{Page: 2, PageSize: 1})
  216. require.NoError(t, err)
  217. require.Len(t, got, 1)
  218. assert.Equal(t, org2.ID, got[0].ID)
  219. got, err = db.List(ctx, ListOrganizationsOptions{Page: 1, PageSize: 4})
  220. require.NoError(t, err)
  221. require.Len(t, got, 3)
  222. assert.Equal(t, org1.ID, got[0].ID)
  223. assert.Equal(t, org2.ID, got[1].ID)
  224. assert.Equal(t, org3.ID, got[2].ID)
  225. })
  226. }
  227. func orgsSearchByName(t *testing.T, ctx context.Context, db *organizations) {
  228. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsSearchByName-tempPictureAvatarUploadPath")
  229. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  230. tempRepositoryRoot := filepath.Join(os.TempDir(), "orgsSearchByName-tempRepositoryRoot")
  231. conf.SetMockRepository(t, conf.RepositoryOpts{Root: tempRepositoryRoot})
  232. org1, err := db.Create(ctx, "org1", 1, CreateOrganizationOptions{FullName: "Acme Corp"})
  233. require.NoError(t, err)
  234. org2, err := db.Create(ctx, "org2", 1, CreateOrganizationOptions{FullName: "Acme Corp 2"})
  235. require.NoError(t, err)
  236. t.Run("search for username org1", func(t *testing.T) {
  237. orgs, count, err := db.SearchByName(ctx, "G1", 1, 1, "")
  238. require.NoError(t, err)
  239. require.Len(t, orgs, int(count))
  240. assert.Equal(t, int64(1), count)
  241. assert.Equal(t, org1.ID, orgs[0].ID)
  242. })
  243. t.Run("search for username org2", func(t *testing.T) {
  244. orgs, count, err := db.SearchByName(ctx, "G2", 1, 1, "")
  245. require.NoError(t, err)
  246. require.Len(t, orgs, int(count))
  247. assert.Equal(t, int64(1), count)
  248. assert.Equal(t, org2.ID, orgs[0].ID)
  249. })
  250. t.Run("search for full name acme", func(t *testing.T) {
  251. orgs, count, err := db.SearchByName(ctx, "ACME", 1, 10, "")
  252. require.NoError(t, err)
  253. require.Len(t, orgs, int(count))
  254. assert.Equal(t, int64(2), count)
  255. })
  256. t.Run("search for full name acme ORDER BY id DESC LIMIT 1", func(t *testing.T) {
  257. orgs, count, err := db.SearchByName(ctx, "ACME", 1, 1, "id DESC")
  258. require.NoError(t, err)
  259. require.Len(t, orgs, 1)
  260. assert.Equal(t, int64(2), count)
  261. assert.Equal(t, org2.ID, orgs[0].ID)
  262. })
  263. }
  264. func orgsCountByUser(t *testing.T, ctx context.Context, db *organizations) {
  265. usersStore := NewUsersStore(db.DB)
  266. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  267. require.NoError(t, err)
  268. bob, err := usersStore.Create(ctx, "bob", "bob@example.com", CreateUserOptions{})
  269. require.NoError(t, err)
  270. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsCountByUser-tempPictureAvatarUploadPath")
  271. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  272. org1, err := db.Create(ctx, "org1", alice.ID, CreateOrganizationOptions{})
  273. require.NoError(t, err)
  274. err = db.AddMember(ctx, org1.ID, bob.ID)
  275. require.NoError(t, err)
  276. got, err := db.CountByUser(ctx, alice.ID)
  277. require.NoError(t, err)
  278. assert.Equal(t, int64(1), got)
  279. got, err = db.CountByUser(ctx, 404)
  280. require.NoError(t, err)
  281. assert.Equal(t, int64(0), got)
  282. }
  283. func orgsCount(t *testing.T, db *organizations) {
  284. ctx := context.Background()
  285. // Has no organization initially
  286. got := db.Count(ctx)
  287. assert.Equal(t, int64(0), got)
  288. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "usersCount-tempPictureAvatarUploadPath")
  289. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  290. _, err := db.Create(ctx, "org1", 1, CreateOrganizationOptions{})
  291. require.NoError(t, err)
  292. // Create a user shouldn't count
  293. _, err = NewUsersStore(db.DB).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  294. require.NoError(t, err)
  295. got = db.Count(ctx)
  296. assert.Equal(t, int64(1), got)
  297. }
  298. func orgsDeleteByID(t *testing.T, db *organizations) {
  299. ctx := context.Background()
  300. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsDeleteByID-tempPictureAvatarUploadPath")
  301. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  302. t.Run("organization still has repository ownership", func(t *testing.T) {
  303. org1, err := db.Create(ctx, "org1", 404, CreateOrganizationOptions{})
  304. require.NoError(t, err)
  305. _, err = NewRepositoriesStore(db.DB).Create(ctx, org1.ID, CreateRepoOptions{Name: "repo1"})
  306. require.NoError(t, err)
  307. err = db.DeleteByID(ctx, org1.ID)
  308. wantErr := ErrOrganizationOwnRepos{errutil.Args{"orgID": org1.ID}}
  309. assert.Equal(t, wantErr, err)
  310. })
  311. alice, err := NewUsersStore(db.DB).Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  312. require.NoError(t, err)
  313. org2, err := db.Create(ctx, "org2", alice.ID, CreateOrganizationOptions{})
  314. require.NoError(t, err)
  315. // Mock team membership
  316. // TODO: Use Organizations.CreateTeam to replace SQL hack when the method is available.
  317. team1 := &Team{
  318. OrgID: org2.ID,
  319. LowerName: "team1",
  320. Name: "team1",
  321. NumMembers: 1,
  322. }
  323. err = db.DB.Create(team1).Error
  324. require.NoError(t, err)
  325. // TODO: Use Organizations.AddTeamMember to replace SQL hack when the method is available.
  326. err = db.DB.Create(
  327. &TeamUser{
  328. OrgID: org2.ID,
  329. TeamID: team1.ID,
  330. UID: alice.ID,
  331. },
  332. ).Error
  333. require.NoError(t, err)
  334. // Pull the trigger
  335. err = db.DeleteByID(ctx, org2.ID)
  336. require.NoError(t, err)
  337. // Verify after-the-fact data
  338. for _, table := range []any{
  339. &Team{OrgID: org2.ID},
  340. &TeamUser{OrgID: org2.ID},
  341. } {
  342. var count int64
  343. err = db.DB.Model(table).Where(table).Count(&count).Error
  344. require.NoError(t, err, "table for %T", table)
  345. assert.Equal(t, int64(0), count, "table for %T", table)
  346. }
  347. _, err = db.GetByName(ctx, org2.Name)
  348. wantErr := ErrOrganizationNotExist{errutil.Args{"name": org2.Name}}
  349. assert.Equal(t, wantErr, err)
  350. }
  351. func orgsAddMember(t *testing.T, db *organizations) {
  352. ctx := context.Background()
  353. usersStore := NewUsersStore(db.DB)
  354. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  355. require.NoError(t, err)
  356. bob, err := usersStore.Create(ctx, "bob", "bob@exmaple.com", CreateUserOptions{})
  357. require.NoError(t, err)
  358. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsAddMember-tempPictureAvatarUploadPath")
  359. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  360. org1, err := db.Create(ctx, "org1", alice.ID, CreateOrganizationOptions{})
  361. require.NoError(t, err)
  362. // Not yet a member
  363. gotOrgs, err := db.List(ctx, ListOrganizationsOptions{MemberID: bob.ID, IncludePrivateMembers: true})
  364. require.NoError(t, err)
  365. assert.Len(t, gotOrgs, 0)
  366. // Add member
  367. err = db.AddMember(ctx, org1.ID, bob.ID)
  368. require.NoError(t, err)
  369. // Now a member
  370. gotOrgs, err = db.List(ctx, ListOrganizationsOptions{MemberID: bob.ID, IncludePrivateMembers: true})
  371. require.NoError(t, err)
  372. assert.Len(t, gotOrgs, 1)
  373. assert.Equal(t, org1.ID, gotOrgs[0].ID)
  374. // Add member again shouldn't fail
  375. err = db.AddMember(ctx, org1.ID, bob.ID)
  376. require.NoError(t, err)
  377. gotOrg, err := db.GetByName(ctx, org1.Name)
  378. require.NoError(t, err)
  379. assert.Equal(t, 2, gotOrg.NumMembers)
  380. }
  381. func orgsRemoveMember(t *testing.T, db *organizations) {
  382. ctx := context.Background()
  383. usersStore := NewUsersStore(db.DB)
  384. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  385. require.NoError(t, err)
  386. bob, err := usersStore.Create(ctx, "bob", "bob@exmaple.com", CreateUserOptions{})
  387. require.NoError(t, err)
  388. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsRemoveMember-tempPictureAvatarUploadPath")
  389. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  390. org1, err := db.Create(ctx, "org1", alice.ID, CreateOrganizationOptions{})
  391. require.NoError(t, err)
  392. t.Run("remove non-existent member", func(t *testing.T) {
  393. err = db.RemoveMember(ctx, org1.ID, bob.ID)
  394. require.NoError(t, err)
  395. })
  396. t.Run("remove last owner", func(t *testing.T) {
  397. err = db.RemoveMember(ctx, org1.ID, alice.ID)
  398. wantErr := ErrLastOrgOwner{errutil.Args{"orgID": org1.ID, "userID": alice.ID}}
  399. assert.Equal(t, wantErr, err)
  400. })
  401. err = db.AddMember(ctx, org1.ID, bob.ID)
  402. require.NoError(t, err)
  403. // Mock repository, watches, accesses and collaborations
  404. reposStore := NewRepositoriesStore(db.DB)
  405. repo1, err := reposStore.Create(ctx, org1.ID, CreateRepoOptions{Name: "repo1", Private: true})
  406. require.NoError(t, err)
  407. // TODO: Use Repositories.AddCollaborator to replace SQL hack when the method is available.
  408. err = db.DB.Create(
  409. &Collaboration{
  410. UserID: bob.ID,
  411. RepoID: repo1.ID,
  412. Mode: AccessModeRead,
  413. },
  414. ).Error
  415. require.NoError(t, err)
  416. // Mock team membership
  417. // TODO: Use Organizations.CreateTeam to replace SQL hack when the method is available.
  418. team1 := &Team{
  419. OrgID: org1.ID,
  420. LowerName: "team1",
  421. Name: "team1",
  422. NumMembers: 1,
  423. }
  424. err = db.DB.Create(team1).Error
  425. require.NoError(t, err)
  426. // TODO: Use Organizations.AddTeamMember to replace SQL hack when the method is available.
  427. err = db.DB.Create(
  428. &TeamUser{
  429. OrgID: org1.ID,
  430. TeamID: team1.ID,
  431. UID: bob.ID,
  432. },
  433. ).Error
  434. require.NoError(t, err)
  435. // TODO: Use Organizations.AddTeamRepository to replace SQL hack when the method is available.
  436. err = db.DB.Create(
  437. &TeamRepo{
  438. OrgID: org1.ID,
  439. TeamID: team1.ID,
  440. RepoID: repo1.ID,
  441. },
  442. ).Error
  443. require.NoError(t, err)
  444. permsStore := NewPermsStore(db.DB)
  445. err = permsStore.SetRepoPerms(ctx, repo1.ID, map[int64]AccessMode{bob.ID: AccessModeRead})
  446. require.NoError(t, err)
  447. err = reposStore.Watch(
  448. ctx,
  449. WatchRepositoryOptions{
  450. UserID: bob.ID,
  451. RepoID: repo1.ID,
  452. RepoOwnerID: repo1.OwnerID,
  453. RepoIsPrivate: repo1.IsPrivate,
  454. },
  455. )
  456. require.NoError(t, err)
  457. // Pull the trigger
  458. err = db.RemoveMember(ctx, org1.ID, bob.ID)
  459. require.NoError(t, err)
  460. // Verify after-the-fact data
  461. gotRepo, err := reposStore.GetByID(ctx, repo1.ID)
  462. require.NoError(t, err)
  463. assert.Equal(t, 1, gotRepo.NumWatches)
  464. gotAccessMode := permsStore.AccessMode(ctx, repo1.ID, bob.ID, AccessModeOptions{Private: repo1.IsPrivate})
  465. assert.Equal(t, AccessModeNone, gotAccessMode)
  466. // TODO: Use Repositories.ListCollaborators to replace SQL hack when the method is available.
  467. var count int64
  468. err = db.DB.Model(&Collaboration{}).Where(&Collaboration{RepoID: repo1.ID}).Count(&count).Error
  469. require.NoError(t, err)
  470. assert.Equal(t, int64(0), count)
  471. gotTeam, err := db.GetTeamByName(ctx, org1.ID, team1.Name)
  472. require.NoError(t, err)
  473. assert.Equal(t, 0, gotTeam.NumMembers)
  474. gotOrg, err := db.GetByName(ctx, org1.Name)
  475. require.NoError(t, err)
  476. assert.Equal(t, 1, gotOrg.NumMembers)
  477. }
  478. func orgsHasMember(t *testing.T, db *organizations) {
  479. ctx := context.Background()
  480. got, _ := db.HasMember(ctx, 1, 1)
  481. assert.False(t, got)
  482. err := db.AddMember(ctx, 1, 1)
  483. require.NoError(t, err)
  484. got, _ = db.HasMember(ctx, 1, 1)
  485. assert.True(t, got)
  486. }
  487. func orgsListMembers(t *testing.T, db *organizations) {
  488. ctx := context.Background()
  489. usersStore := NewUsersStore(db.DB)
  490. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  491. require.NoError(t, err)
  492. bob, err := usersStore.Create(ctx, "bob", "bob@exmaple.com", CreateUserOptions{})
  493. require.NoError(t, err)
  494. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsListMembers-tempPictureAvatarUploadPath")
  495. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  496. org1, err := db.Create(ctx, "org1", alice.ID, CreateOrganizationOptions{})
  497. require.NoError(t, err)
  498. err = db.AddMember(ctx, org1.ID, bob.ID)
  499. require.NoError(t, err)
  500. got, err := db.ListMembers(ctx, org1.ID, ListOrgMembersOptions{Limit: 1})
  501. require.NoError(t, err)
  502. require.Len(t, got, 1)
  503. assert.Equal(t, alice.ID, got[0].ID)
  504. got, err = db.ListMembers(ctx, org1.ID, ListOrgMembersOptions{})
  505. require.NoError(t, err)
  506. require.Len(t, got, 2)
  507. assert.Equal(t, alice.ID, got[0].ID)
  508. assert.Equal(t, bob.ID, got[1].ID)
  509. }
  510. func orgsIsOwnedBy(t *testing.T, db *organizations) {
  511. ctx := context.Background()
  512. usersStore := NewUsersStore(db.DB)
  513. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  514. require.NoError(t, err)
  515. bob, err := usersStore.Create(ctx, "bob", "bob@exmaple.com", CreateUserOptions{})
  516. require.NoError(t, err)
  517. cindy, err := usersStore.Create(ctx, "cindy", "cindy@exmaple.com", CreateUserOptions{})
  518. require.NoError(t, err)
  519. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsListMembers-tempPictureAvatarUploadPath")
  520. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  521. org1, err := db.Create(ctx, "org1", alice.ID, CreateOrganizationOptions{})
  522. require.NoError(t, err)
  523. err = db.AddMember(ctx, org1.ID, bob.ID)
  524. require.NoError(t, err)
  525. got := db.IsOwnedBy(ctx, org1.ID, alice.ID)
  526. assert.True(t, got)
  527. got = db.IsOwnedBy(ctx, org1.ID, bob.ID)
  528. assert.False(t, got)
  529. got = db.IsOwnedBy(ctx, org1.ID, cindy.ID)
  530. assert.False(t, got)
  531. }
  532. func orgsSetMemberVisibility(t *testing.T, db *organizations) {
  533. ctx := context.Background()
  534. usersStore := NewUsersStore(db.DB)
  535. alice, err := usersStore.Create(ctx, "alice", "alice@example.com", CreateUserOptions{})
  536. require.NoError(t, err)
  537. tempPictureAvatarUploadPath := filepath.Join(os.TempDir(), "orgsListMembers-tempPictureAvatarUploadPath")
  538. conf.SetMockPicture(t, conf.PictureOpts{AvatarUploadPath: tempPictureAvatarUploadPath})
  539. org1, err := db.Create(ctx, "org1", alice.ID, CreateOrganizationOptions{})
  540. require.NoError(t, err)
  541. got, err := db.List(ctx, ListOrganizationsOptions{MemberID: alice.ID})
  542. require.NoError(t, err)
  543. assert.Len(t, got, 0)
  544. err = db.SetMemberVisibility(ctx, org1.ID, alice.ID, true)
  545. require.NoError(t, err)
  546. got, err = db.List(ctx, ListOrganizationsOptions{MemberID: alice.ID})
  547. require.NoError(t, err)
  548. assert.Len(t, got, 1)
  549. }