diff --git a/backend/entities/clubs/tag/routes.go b/backend/entities/clubs/tag/routes.go index 552929089..938b59109 100644 --- a/backend/entities/clubs/tag/routes.go +++ b/backend/entities/clubs/tag/routes.go @@ -9,6 +9,7 @@ func ClubTag(clubParams types.RouteParams) { clubTags := clubParams.Router.Group("/tags") + // api/v1/clubs/:clubID/tags/* clubTags.Get("/", clubTagController.GetClubTags) clubTags.Post("/", clubParams.AuthMiddleware.ClubAuthorizeById, clubTagController.CreateClubTags) clubTags.Delete("/:tagID", clubParams.AuthMiddleware.ClubAuthorizeById, clubTagController.DeleteClubTag) diff --git a/backend/tests/api/club_member_test.go b/backend/tests/api/club_member_test.go index aab11d469..eb2793293 100644 --- a/backend/tests/api/club_member_test.go +++ b/backend/tests/api/club_member_test.go @@ -6,18 +6,57 @@ import ( "testing" "github.com/GenerateNU/sac/backend/entities/models" + "github.com/GenerateNU/sac/backend/errors" h "github.com/GenerateNU/sac/backend/tests/api/helpers" "github.com/goccy/go-json" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" ) +func TestCreateMembershipWorks(t *testing.T) { + appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) + + appAssert.TestOnStatusAndTester( + h.TestRequest{ + Method: fiber.MethodPost, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", clubUUID), + Role: &models.Super, + TestUserIDReplaces: h.StringToPointer(":userID"), + }, + h.TesterWithStatus{ + Status: fiber.StatusCreated, + Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { + var user models.User + + err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user) + + eaa.Assert.NilError(err) + + eaa.Assert.Equal(2, len(user.Member)) // SAC Super Club and the one just added + + eaa.Assert.Equal(clubUUID, user.Member[1].ID) // second club AKA the one just added + + var club models.Club + + err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club) + + eaa.Assert.NilError(err) + + eaa.Assert.Equal(1, len(club.Member)) + + eaa.Assert.Equal(eaa.App.TestUser.UUID, club.Member[0].ID) + }, + }, + ).Close() +} + func TestClubMemberWorks(t *testing.T) { appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) appAssert.TestOnStatus( h.TestRequest{ Method: fiber.MethodPost, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID), + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", clubUUID), Role: &models.Super, TestUserIDReplaces: h.StringToPointer(":userID"), }, @@ -56,3 +95,142 @@ func TestClubMemberWorks(t *testing.T) { }, ).Close() } + +func TestCreateMembershipFailsClubIdNotExists(t *testing.T) { + appAssert, _, _ := CreateSampleClub(h.InitTest(t)) + + uuid := uuid.New() + + appAssert.TestOnErrorAndTester( + h.TestRequest{ + Method: fiber.MethodPost, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", uuid), + Role: &models.Super, + TestUserIDReplaces: h.StringToPointer(":userID"), + }, + h.ErrorWithTester{ + Error: errors.ClubNotFound, + Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { + var club models.Club + + err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error + + eaa.Assert.Assert(err != nil) + }, + }, + ).Close() +} + +func TestCreateMembershipFailsUserIdNotExists(t *testing.T) { + appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) + + uuid := uuid.New() + + appAssert.TestOnErrorAndTester( + h.TestRequest{ + Method: fiber.MethodPost, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/%s", clubUUID, uuid), + Role: &models.Super, + }, + h.ErrorWithTester{ + Error: errors.UserNotFound, + Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { + var user models.User + + err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error + + eaa.Assert.Assert(err != nil) + }, + }, + ).Close() +} + +func TestDeleteMembershipWorks(t *testing.T) { + appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) + + appAssert.TestOnStatus( + h.TestRequest{ + Method: fiber.MethodPost, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", clubUUID), + Role: &models.Super, + TestUserIDReplaces: h.StringToPointer(":userID"), + }, + fiber.StatusCreated, + ).TestOnStatusAndTester( + h.TestRequest{ + Method: fiber.MethodDelete, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", clubUUID), + Role: &models.Super, + TestUserIDReplaces: h.StringToPointer(":userID"), + }, + h.TesterWithStatus{ + Status: fiber.StatusNoContent, + Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { + var user models.User + + err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user) + + eaa.Assert.NilError(err) + + eaa.Assert.Equal(1, len(user.Member)) // SAC Super Club + + var club models.Club + + err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club) + + eaa.Assert.NilError(err) + + eaa.Assert.Equal(0, len(club.Member)) + }, + }, + ).Close() +} + +func TestDeleteMembershipFailsClubIdNotExists(t *testing.T) { + appAssert, _, _ := CreateSampleClub(h.InitTest(t)) + + uuid := uuid.New() + + appAssert.TestOnErrorAndTester( + h.TestRequest{ + Method: fiber.MethodDelete, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", uuid), + Role: &models.Super, + TestUserIDReplaces: h.StringToPointer(":userID"), + }, + h.ErrorWithTester{ + Error: errors.ClubNotFound, + Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { + var club models.Club + + err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error + + eaa.Assert.Assert(err != nil) + }, + }, + ).Close() +} + +func TestDeleteMembershipFailsUserIdNotExists(t *testing.T) { + appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) + + uuid := uuid.New() + + appAssert.TestOnErrorAndTester( + h.TestRequest{ + Method: fiber.MethodDelete, + Path: fmt.Sprintf("/api/v1/clubs/%s/members/%s", clubUUID, uuid), + Role: &models.Super, + }, + h.ErrorWithTester{ + Error: errors.UserNotFound, + Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { + var user models.User + + err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error + + eaa.Assert.Assert(err != nil) + }, + }, + ).Close() +} diff --git a/backend/tests/api/user_member_test.go b/backend/tests/api/user_member_test.go index 14a1d2180..e2063d2c0 100644 --- a/backend/tests/api/user_member_test.go +++ b/backend/tests/api/user_member_test.go @@ -14,231 +14,13 @@ import ( "github.com/google/uuid" ) -func TestCreateMembershipWorks(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) - - appAssert.TestOnStatusAndTester( - h.TestRequest{ - Method: fiber.MethodPost, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID), - Role: &models.Super, - TestUserIDReplaces: h.StringToPointer(":userID"), - }, - h.TesterWithStatus{ - Status: fiber.StatusCreated, - Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { - var user models.User - - err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user) - - eaa.Assert.NilError(err) - - eaa.Assert.Equal(2, len(user.Member)) // SAC Super Club and the one just added - - eaa.Assert.Equal(clubUUID, user.Member[1].ID) // second club AKA the one just added - - var club models.Club - - err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club) - - eaa.Assert.NilError(err) - - eaa.Assert.Equal(1, len(club.Member)) - - eaa.Assert.Equal(eaa.App.TestUser.UUID, club.Member[0].ID) - }, - }, - ).Close() -} - -func TestCreateMembershipFailsClubIdNotExists(t *testing.T) { - appAssert, _, _ := CreateSampleClub(h.InitTest(t)) - - uuid := uuid.New() - - appAssert.TestOnErrorAndTester( - h.TestRequest{ - Method: fiber.MethodPost, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", uuid), - Role: &models.Super, - TestUserIDReplaces: h.StringToPointer(":userID"), - }, - h.ErrorWithTester{ - Error: errors.ClubNotFound, - Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { - var club models.Club - - err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error - - eaa.Assert.Assert(err != nil) - }, - }, - ).Close() -} - -func TestCreateMembershipFailsUserIdNotExists(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) - - uuid := uuid.New() - - appAssert.TestOnErrorAndTester( - h.TestRequest{ - Method: fiber.MethodPost, - Path: fmt.Sprintf("/api/v1/users/%s/member/%s", uuid, clubUUID), - Role: &models.Super, - }, - h.ErrorWithTester{ - Error: errors.UserNotFound, - Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { - var user models.User - - err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error - - eaa.Assert.Assert(err != nil) - }, - }, - ).Close() -} - -func TestDeleteMembershipWorks(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) - - appAssert.TestOnStatus( - h.TestRequest{ - Method: fiber.MethodPost, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID), - Role: &models.Super, - TestUserIDReplaces: h.StringToPointer(":userID"), - }, - fiber.StatusCreated, - ).TestOnStatusAndTester( - h.TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID), - Role: &models.Super, - TestUserIDReplaces: h.StringToPointer(":userID"), - }, - h.TesterWithStatus{ - Status: fiber.StatusNoContent, - Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { - var user models.User - - err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user) - - eaa.Assert.NilError(err) - - eaa.Assert.Equal(1, len(user.Member)) // SAC Super Club - - var club models.Club - - err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club) - - eaa.Assert.NilError(err) - - eaa.Assert.Equal(0, len(club.Member)) - }, - }, - ).Close() -} - -// TODO: test can't work because you become a member when you create a club -// func TestDeleteMembershipNotMembership(t *testing.T) { -// appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) - -// userClubsMemberBefore, err := transactions.GetClubMembership(appAssert.App.Conn, appAssert.App.TestUser.UUID) - -// appAssert.Assert.Assert(err == nil) - -// clubUsersMemberBefore, err := transactions.GetClubMembers(appAssert.App.Conn, clubUUID, 10, 0) - -// appAssert.Assert.Assert(err == nil) - -// appAssert.TestOnErrorAndTester( -// h.TestRequest{ -// Method: fiber.MethodDelete, -// Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID), -// Role: &models.Super, -// TestUserIDReplaces: h.StringToPointer(":userID"), -// }, -// h.ErrorWithTester{ -// Error: errors.UserNotMemberOfClub, -// Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { -// var user models.User - -// err := eaa.App.Conn.Where("id = ?", eaa.App.TestUser.UUID).Preload("Member").First(&user) - -// eaa.Assert.NilError(err) - -// eaa.Assert.Equal(userClubsMemberBefore, user.Member) - -// var club models.Club - -// err = eaa.App.Conn.Where("id = ?", clubUUID).Preload("Member").First(&club) - -// eaa.Assert.NilError(err) - -// eaa.Assert.Equal(clubUsersMemberBefore, club.Member) -// }, -// }, -// ).Close() -// } - -func TestDeleteMembershipFailsClubIdNotExists(t *testing.T) { - appAssert, _, _ := CreateSampleClub(h.InitTest(t)) - - uuid := uuid.New() - - appAssert.TestOnErrorAndTester( - h.TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", uuid), - Role: &models.Super, - TestUserIDReplaces: h.StringToPointer(":userID"), - }, - h.ErrorWithTester{ - Error: errors.ClubNotFound, - Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { - var club models.Club - - err := eaa.App.Conn.Where("id = ?", uuid).First(&club).Error - - eaa.Assert.Assert(err != nil) - }, - }, - ).Close() -} - -func TestDeleteMembershipFailsUserIdNotExists(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) - - uuid := uuid.New() - - appAssert.TestOnErrorAndTester( - h.TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%s/member/%s", uuid, clubUUID), - Role: &models.Super, - }, - h.ErrorWithTester{ - Error: errors.UserNotFound, - Tester: func(eaa h.ExistingAppAssert, resp *http.Response) { - var user models.User - - err := eaa.App.Conn.Where("id = ?", uuid).First(&user).Error - - eaa.Assert.Assert(err != nil) - }, - }, - ).Close() -} - func TestGetMembershipWorks(t *testing.T) { appAssert, _, clubUUID := CreateSampleClub(h.InitTest(t)) appAssert.TestOnStatus( h.TestRequest{ Method: fiber.MethodPost, - Path: fmt.Sprintf("/api/v1/users/:userID/member/%s", clubUUID), + Path: fmt.Sprintf("/api/v1/clubs/%s/members/:userID", clubUUID), Role: &models.Super, TestUserIDReplaces: h.StringToPointer(":userID"), }, diff --git a/frontend/lib/src/api/clubApi.ts b/frontend/lib/src/api/clubApi.ts index 03fc3cf14..9893d79df 100644 --- a/frontend/lib/src/api/clubApi.ts +++ b/frontend/lib/src/api/clubApi.ts @@ -174,6 +174,28 @@ export const clubApi = baseApi.injectEndpoints({ return z.array(userSchema).parse(response); } }), + createClubMember: builder.mutation< + User, + { clubID: string; userID: string } + >({ + query: ({ clubID, userID }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/members/${userID}`, + method: 'POST' + }), + invalidatesTags: (result, _, { userID }) => + result ? [{ type: 'User', id: userID }] : [] + }), + deleteClubMember: builder.mutation< + void, + { clubID: string; userID: string } + >({ + query: ({ clubID, userID }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/members/${userID}`, + method: 'DELETE' + }), + invalidatesTags: (result, _, { userID }) => + result ? [{ type: 'User', id: userID }] : [] + }), clubPointOfContacts: builder.query({ query: (id) => ({ url: `${CLUB_API_BASE_URL}/${id}/pocs/`, @@ -192,10 +214,10 @@ export const clubApi = baseApi.injectEndpoints({ }), clubPointOfContact: builder.query< PointOfContact, - { clubId: string; pocId: string } + { clubID: string; pocId: string } >({ - query: ({ clubId, pocId }) => ({ - url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}`, + query: ({ clubID, pocId }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}`, method: 'GET' }), providesTags: (result, _, { pocId }) => @@ -220,10 +242,10 @@ export const clubApi = baseApi.injectEndpoints({ }), updateClubPointOfContactPhoto: builder.mutation< PointOfContact, - { clubId: string; pocId: string; body: FormData } + { clubID: string; pocId: string; body: FormData } >({ - query: ({ clubId, pocId, body }) => ({ - url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}/photo`, + query: ({ clubID, pocId, body }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}/photo`, method: 'PATCH', body }), @@ -236,13 +258,13 @@ export const clubApi = baseApi.injectEndpoints({ updateClubPointOfContact: builder.mutation< PointOfContact, { - clubId: string; + clubID: string; pocId: string; body: UpdatePointOfContactRequestBody; } >({ - query: ({ clubId, pocId, body }) => ({ - url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}`, + query: ({ clubID, pocId, body }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}`, method: 'PATCH', body }), @@ -254,10 +276,10 @@ export const clubApi = baseApi.injectEndpoints({ }), deleteClubPointOfContact: builder.mutation< void, - { clubId: string; pocId: string } + { clubID: string; pocId: string } >({ - query: ({ clubId, pocId }) => ({ - url: `${CLUB_API_BASE_URL}/${clubId}/pocs/${pocId}`, + query: ({ clubID, pocId }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/pocs/${pocId}`, method: 'DELETE' }), invalidatesTags: (_result, _, { pocId }) => [ @@ -296,10 +318,10 @@ export const clubApi = baseApi.injectEndpoints({ }), deleteClubTag: builder.mutation< void, - { clubId: string; tagId: string } + { clubID: string; tagId: string } >({ - query: ({ clubId, tagId }) => ({ - url: `${CLUB_API_BASE_URL}/${clubId}/tags/${tagId}`, + query: ({ clubID, tagId }) => ({ + url: `${CLUB_API_BASE_URL}/${clubID}/tags/${tagId}`, method: 'DELETE' }), invalidatesTags: (_result, _, { tagId }) => [ diff --git a/frontend/lib/src/api/userApi.ts b/frontend/lib/src/api/userApi.ts index 8ea3030af..3a6910796 100644 --- a/frontend/lib/src/api/userApi.ts +++ b/frontend/lib/src/api/userApi.ts @@ -145,31 +145,6 @@ export const userApi = baseApi.injectEndpoints({ return z.array(clubSchema).parse(response); } }), - createUserMembership: builder.mutation< - void, - { userID: string; clubID: string } - >({ - query: ({ userID, clubID }) => ({ - url: `${USER_API_BASE_URL}/${userID}/member/${clubID}`, - method: 'POST' - }), - invalidatesTags: (_result, _, { userID }) => [ - { type: 'Follower', id: userID }, - { type: 'Member', id: userID } - ] - }), - deleteUserMembership: builder.mutation< - void, - { userID: string; clubID: string } - >({ - query: ({ userID, clubID }) => ({ - url: `${USER_API_BASE_URL}/${userID}/member/${clubID}`, - method: 'DELETE' - }), - invalidatesTags: (_result, _, { userID }) => [ - { type: 'Member', id: userID } - ] - }), userTags: builder.query({ query: () => ({ url: `${USER_API_BASE_URL}/tags/`,