diff --git a/backend/src/controllers/club_follower.go b/backend/src/controllers/club_follower.go index b6beb8f02..76239e150 100644 --- a/backend/src/controllers/club_follower.go +++ b/backend/src/controllers/club_follower.go @@ -1,6 +1,8 @@ package controllers import ( + "strconv" + "github.com/GenerateNU/sac/backend/src/services" "github.com/gofiber/fiber/v2" ) @@ -13,11 +15,14 @@ func NewClubFollowerController(clubFollowerService services.ClubFollowerServiceI return &ClubFollowerController{clubFollowerService: clubFollowerService} } -func (cf *ClubFollowerController) GetUserFollowingClubs(c *fiber.Ctx) error { - clubs, err := cf.clubFollowerService.GetUserFollowingClubs(c.Params("userID")) +func (cf *ClubFollowerController) GetClubFollowers(c *fiber.Ctx) error { + defaultLimit := 10 + defaultPage := 1 + + followers, err := cf.clubFollowerService.GetClubFollowers(c.Params("clubID"), c.Query("limit", strconv.Itoa(defaultLimit)), c.Query("page", strconv.Itoa(defaultPage))) if err != nil { return err.FiberError(c) } - return c.Status(fiber.StatusOK).JSON(&clubs) + return c.Status(fiber.StatusOK).JSON(followers) } diff --git a/backend/src/server/server.go b/backend/src/server/server.go index 9da9724d1..c1a8d08ab 100644 --- a/backend/src/server/server.go +++ b/backend/src/server/server.go @@ -73,14 +73,3 @@ func newFiberApp() *fiber.App { return app } - -func userFollowerRoutes(router fiber.Router, userFollowerService services.UserFollowerServiceInterface) { - userFollowerController := controllers.NewUserFollowerController(userFollowerService) - - userFollower := router.Group("/:userID/follower") - - userFollower.Put("/:clubID", userFollowerController.CreateFollowing) - userFollower.Delete("/:clubID", userFollowerController.DeleteFollowing) - userFollower.Get("/", userFollowerController.GetAllFollowing) -} - diff --git a/backend/src/services/club_follower.go b/backend/src/services/club_follower.go index 921c4c658..1cd636e04 100644 --- a/backend/src/services/club_follower.go +++ b/backend/src/services/club_follower.go @@ -10,7 +10,7 @@ import ( ) type ClubFollowerServiceInterface interface { - GetUserFollowingClubs(userID string) ([]models.Club, *errors.Error) + GetClubFollowers(clubID string, limit string, page string) ([]models.User, *errors.Error) } type ClubFollowerService struct { @@ -22,11 +22,21 @@ func NewClubFollowerService(db *gorm.DB, validate *validator.Validate) *ClubFoll return &ClubFollowerService{DB: db, Validate: validate} } -func (cf *ClubFollowerService) GetUserFollowingClubs(userID string) ([]models.Club, *errors.Error) { - userIDAsUUID, err := utilities.ValidateID(userID) +func (cf *ClubFollowerService) GetClubFollowers(clubID string, limit string, page string) ([]models.User, *errors.Error) { + idAsUUID, err := utilities.ValidateID(clubID) if err != nil { - return nil, err + return nil, &errors.FailedToValidateID } - return transactions.GetClubFollowing(cf.DB, *userIDAsUUID) + limitAsInt, err := utilities.ValidateNonNegative(limit) + if err != nil { + return nil, &errors.FailedToValidateLimit + } + + pageAsInt, err := utilities.ValidateNonNegative(page) + if err != nil { + return nil, &errors.FailedToValidatePage + } + + return transactions.GetClubFollowers(cf.DB, *idAsUUID, *limitAsInt, *pageAsInt) } diff --git a/backend/src/transactions/club_follower.go b/backend/src/transactions/club_follower.go index 748646a9d..a2e747c80 100644 --- a/backend/src/transactions/club_follower.go +++ b/backend/src/transactions/club_follower.go @@ -7,15 +7,8 @@ import ( "gorm.io/gorm" ) -func GetUserFollowingClubs(db *gorm.DB, club_id uuid.UUID) ([]models.User, *errors.Error) { +func GetClubFollowers(db *gorm.DB, clubID uuid.UUID, limit int, page int) ([]models.User, *errors.Error) { var users []models.User - club, err := GetClub(db, club_id) - if err != nil { - return nil, &errors.ClubNotFound - } - if err := db.Model(&club).Association("Follower").Find(&users); err != nil { - return nil, &errors.FailedToGetClubFollowers - } return users, nil } diff --git a/backend/src/transactions/contacts.go b/backend/src/transactions/contacts.go index 51ac2bb00..a47405fae 100644 --- a/backend/src/transactions/contacts.go +++ b/backend/src/transactions/contacts.go @@ -42,42 +42,3 @@ func DeleteContact(db *gorm.DB, id uuid.UUID) *errors.Error { } return nil } - -func UpdateClub(db *gorm.DB, id uuid.UUID, club models.Club) (*models.Club, *errors.Error) { - result := db.Model(&models.User{}).Where("id = ?", id).Updates(club) - if result.Error != nil { - if stdliberrors.Is(result.Error, gorm.ErrRecordNotFound) { - return nil, &errors.UserNotFound - } else { - return nil, &errors.FailedToUpdateClub - } - } - var existingClub models.Club - - err := db.First(&existingClub, id).Error - if err != nil { - if stdliberrors.Is(err, gorm.ErrRecordNotFound) { - return nil, &errors.ClubNotFound - } else { - return nil, &errors.FailedToCreateClub - } - } - - if err := db.Model(&existingClub).Updates(&club).Error; err != nil { - return nil, &errors.FailedToUpdateUser - } - - return &existingClub, nil -} - -func DeleteClub(db *gorm.DB, id uuid.UUID) *errors.Error { - if result := db.Delete(&models.Club{}, id); result.RowsAffected == 0 { - if result.Error == nil { - return &errors.ClubNotFound - } else { - return &errors.FailedToDeleteClub - } - } - - return nil -} diff --git a/backend/src/transactions/user_follower.go b/backend/src/transactions/user_follower.go index 449b72c44..1b24e1e47 100644 --- a/backend/src/transactions/user_follower.go +++ b/backend/src/transactions/user_follower.go @@ -7,7 +7,6 @@ import ( "gorm.io/gorm" ) -// Create following for a user func CreateFollowing(db *gorm.DB, userId uuid.UUID, clubId uuid.UUID) *errors.Error { user, err := GetUserWithFollowers(db, userId) if err != nil { @@ -24,7 +23,6 @@ func CreateFollowing(db *gorm.DB, userId uuid.UUID, clubId uuid.UUID) *errors.Er return nil } -// Delete following for a user func DeleteFollowing(db *gorm.DB, userId uuid.UUID, clubId uuid.UUID) *errors.Error { user, err := GetUser(db, userId) if err != nil { @@ -34,16 +32,12 @@ func DeleteFollowing(db *gorm.DB, userId uuid.UUID, clubId uuid.UUID) *errors.Er if err != nil { return &errors.ClubNotFound } - // What to return here? - // Should we return User or Success message? if err := db.Model(&user).Association("Follower").Delete(club); err != nil { return &errors.FailedToUpdateUser } return nil } -// Get all following for a user - func GetClubFollowing(db *gorm.DB, userId uuid.UUID) ([]models.Club, *errors.Error) { var clubs []models.Club diff --git a/backend/tests/api/club_follower_test.go b/backend/tests/api/club_follower_test.go index 3285f5ca4..ca8701d29 100644 --- a/backend/tests/api/club_follower_test.go +++ b/backend/tests/api/club_follower_test.go @@ -1,98 +1 @@ package tests - -import ( - stdliberrors "errors" - "fmt" - "net/http" - "testing" - - "github.com/GenerateNU/sac/backend/src/errors" - "github.com/GenerateNU/sac/backend/src/models" - "github.com/GenerateNU/sac/backend/src/transactions" - "github.com/gofiber/fiber/v2" - "github.com/google/uuid" - "github.com/huandu/go-assert" - "gorm.io/gorm" -) - - -func TestGetClubFollowersWorks(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - - TestRequest{ - Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/clubs/%s/follower", clubUUID), - }.TestOnStatusAndDB(t, &appAssert, - DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var dbClub *models.Club - err := app.Conn.Preload("Follower").First(dbClub, clubUUID).Error - assert.NilError(err) - assert.Equal(len(dbClub.Follower), 1) - - var user *models.User - err = app.Conn.First(user, userUUID).Error - assert.NilError(err) - - user, _ = transactions.GetUser(app.Conn, userUUID) - userFollower := &dbClub.Follower[0] - assert.Equal(userFollower, user) - }, - }, - ) - appAssert.Close() -} - - -func TestGetClubFollowersFailsClubNotExist(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - clubUUIDNotExist := uuid.New() - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - - TestRequest{ - Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/clubs/%s/follower", clubUUIDNotExist), - }.TestOnErrorAndDB(t, &appAssert, - ErrorWithDBTester{ - Error: errors.ClubNotFound, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var club models.Club - err := app.Conn.Where("id = ?", clubUUIDNotExist).First(&club).Error - assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) - }, - }, - ).Close() -} - -func TestGetClubFollowersFailsClubIdBadRequest(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - - badRequests := []string{ - "0", - "-1", - "1.1", - "foo", - "null", - } - for _, badRequest := range badRequests { - TestRequest{ - Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/clubs/%s/follower", badRequest), - }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() - } -} \ No newline at end of file diff --git a/backend/tests/api/user_follower_test.go b/backend/tests/api/user_follower_test.go index 52837fd00..ca8701d29 100644 --- a/backend/tests/api/user_follower_test.go +++ b/backend/tests/api/user_follower_test.go @@ -1,295 +1 @@ package tests - -import ( - stdliberrors "errors" - "fmt" - "net/http" - "testing" - - "github.com/GenerateNU/sac/backend/src/errors" - "github.com/GenerateNU/sac/backend/src/models" - "github.com/GenerateNU/sac/backend/src/transactions" - "github.com/gofiber/fiber/v2" - "github.com/google/uuid" - "github.com/huandu/go-assert" - "gorm.io/gorm" -) - -func TestCreateUserFollowingWorks(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatusAndDB(t, &appAssert, - DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var dbUser models.User - err := app.Conn.Preload("Follower").First(&dbUser, userUUID).Error - assert.NilError(err) - - assert.Equal(len(dbUser.Follower), 1) - }, - }, - ) - appAssert.Close() -} - -func TestCreateUserFollowingFailsClubIdBadRequest(t *testing.T) { - appAssert, userUUID := CreateSampleUser(t, nil) - - badRequests := []string{ - "0", - "-1", - "1.1", - "foo", - "null", - } - - for _, badRequest := range badRequests { - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, badRequest), - }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() - } -} - -func TestCreateUserFollowingFailsUserIdBadRequest(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(t, nil) - - badRequests := []string{ - "0", - "-1", - "1.1", - "foo", - "null", - } - - for _, badRequest := range badRequests { - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", badRequest, clubUUID), - }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() - } -} - -func TestCreateUserFollowingFailsUserNotExist(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(t, nil) - userUUIDNotExist := uuid.New() - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUIDNotExist, clubUUID), - }.TestOnErrorAndDB(t, &appAssert, - ErrorWithDBTester{ - Error: errors.UserNotFound, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var user models.User - err := app.Conn.Where("id = ?", userUUIDNotExist).First(&user).Error - assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) - }, - }, - ).Close() -} - -func TestCreateUserFollowingFailsClubNotExist(t *testing.T) { - appAssert, userUUID := CreateSampleUser(t, nil) - clubUUIDNotExist := uuid.New() - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUIDNotExist), - }.TestOnErrorAndDB(t, &appAssert, - ErrorWithDBTester{ - Error: errors.ClubNotFound, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var club models.Club - err := app.Conn.Where("id = ?", clubUUIDNotExist).First(&club).Error - assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) - }, - }, - ).Close() -} - -func TestDeleteUserFollowingWorks(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatusAndDB(t, &appAssert, - DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var dbUser models.User - err := app.Conn.Preload("Follower").First(&dbUser, userUUID).Error - assert.NilError(err) - - assert.Equal(len(dbUser.Follower), 0) - }, - }, - ) - appAssert.Close() -} - -func TestDeleteUserFollowingFailsClubIdBadRequest(t *testing.T) { - appAssert, userUUID := CreateSampleUser(t, nil) - - badRequests := []string{ - "0", - "-1", - "1.1", - "foo", - "null", - } - - for _, badRequest := range badRequests { - TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, badRequest), - }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() - } -} - -func TestDeleteUserFollowingFailsUserIdBadRequest(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(t, nil) - - badRequests := []string{ - "0", - "-1", - "1.1", - "foo", - "null", - } - - for _, badRequest := range badRequests { - TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", badRequest, clubUUID), - }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() - } -} - - -func TestDeleteUserFollowingFailsUserNotExist(t *testing.T) { - appAssert, _, clubUUID := CreateSampleClub(t, nil) - userUUIDNotExist := uuid.New() - - TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUIDNotExist, clubUUID), - }.TestOnErrorAndDB(t, &appAssert, - ErrorWithDBTester{ - Error: errors.UserNotFound, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var user models.User - err := app.Conn.Where("id = ?", userUUIDNotExist).First(&user).Error - assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) - }, - }, - ).Close() -} - -func TestDeleteUserFollowingFailsClubNotExist(t *testing.T) { - appAssert, userUUID := CreateSampleUser(t, nil) - clubUUIDNotExist := uuid.New() - - TestRequest{ - Method: fiber.MethodDelete, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUIDNotExist), - }.TestOnErrorAndDB(t, &appAssert, - ErrorWithDBTester{ - Error: errors.ClubNotFound, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var club models.Club - err := app.Conn.Where("id = ?", clubUUIDNotExist).First(&club).Error - assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) - }, - }, - ).Close() -} - -func TestGetUserFollowingWorks(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - TestRequest{ - Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/users/%s/follower", userUUID), - }.TestOnStatusAndDB(t, &appAssert, - DBTesterWithStatus{ - Status: fiber.StatusCreated, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var dbUser *models.User - err := app.Conn.Preload("Follower").First(dbUser, userUUID).Error - assert.NilError(err) - assert.Equal(len(dbUser.Follower), 1) - - var club *models.Club - err = app.Conn.First(club, clubUUID).Error - assert.NilError(err) - - club, _ = transactions.GetClub(app.Conn, clubUUID) - clubFollowed := &dbUser.Follower[0] - assert.Equal(clubFollowed, club) - }, - }, - ) - appAssert.Close() -} - - -func TestGetUserFailsUserNotExist(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - userUUIDNotExist := uuid.New() - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - - TestRequest{ - Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/users/%s/follower", userUUIDNotExist), - }.TestOnErrorAndDB(t, &appAssert, - ErrorWithDBTester{ - Error: errors.ClubNotFound, - DBTester: func(app TestApp, assert *assert.A, resp *http.Response) { - var user models.User - err := app.Conn.Where("id = ?", userUUIDNotExist).First(&user).Error - assert.Assert(stdliberrors.Is(err, gorm.ErrRecordNotFound)) - }, - }, - ).Close() -} - -func TestGetUserFailsUserIdBadRequest(t *testing.T) { - appAssert, userUUID, clubUUID := CreateSampleClub(t, nil) - - TestRequest{ - Method: fiber.MethodPut, - Path: fmt.Sprintf("/api/v1/users/%s/follower/%s", userUUID, clubUUID), - }.TestOnStatus(t, &appAssert, fiber.StatusCreated) - - badRequests := []string{ - "0", - "-1", - "1.1", - "foo", - "null", - } - for _, badRequest := range badRequests { - TestRequest{ - Method: fiber.MethodGet, - Path: fmt.Sprintf("/api/v1/users/%s/follower", badRequest), - }.TestOnError(t, &appAssert, errors.FailedToValidateID).Close() - } -} \ No newline at end of file