Skip to content

Commit

Permalink
Fix class
Browse files Browse the repository at this point in the history
  • Loading branch information
suntt2019 committed Feb 25, 2021
1 parent 248bf52 commit 828563d
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 47 deletions.
51 changes: 23 additions & 28 deletions app/controller/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,15 @@ var inviteCodeLock sync.Mutex
func GenerateInviteCode() (code string) {
inviteCodeLock.Lock()
defer inviteCodeLock.Unlock()
var classes []models.Class
utils.PanicIfDBError(base.DB.Select("invite_code").Find(&classes), "could not find classes for generating invite codes")
crashed := true
for crashed {
// 5: Fixed invite code length
code = utils.RandStr(5)
crashed = false
for _, c := range classes {
if c.InviteCode == code {
crashed = true
continue
}
}
var count int64
utils.PanicIfDBError(base.DB.Model(models.Class{}).Where("invite_code = ?", code).Count(&count),
"could not check if invite code crashed for generating invite code")
crashed = count >= 1
}
return
}
Expand Down Expand Up @@ -85,25 +81,28 @@ func GetClass(c echo.Context) error {
resource.GetClassDetail(&class),
},
})
} else if user.In(class.Students) {
return c.JSON(http.StatusOK, response.GetClassResponse{
Message: "SUCCESS",
Error: nil,
Data: struct {
*resource.Class `json:"class"`
}{
resource.GetClass(&class),
},
})
} else {
return c.JSON(http.StatusForbidden, response.ErrorResp("PERMISSION_DENIED", nil))
count := base.DB.Model(&class).Where("id = ?", user.ID).Association("Students").Count()
if count > 0 {
return c.JSON(http.StatusOK, response.GetClassResponse{
Message: "SUCCESS",
Error: nil,
Data: struct {
*resource.Class `json:"class"`
}{
resource.GetClass(&class),
},
})
} else {
return c.JSON(http.StatusForbidden, response.ErrorResp("PERMISSION_DENIED", nil))
}
}
}

func GetClassesIManage(c echo.Context) error {
user := c.Get("user").(models.User)
var classes []models.Class
if err := base.DB.Model(&user).Preload("Managers").Preload("Students").Association("ClassesManaging").Find(&classes); err != nil {
if err := base.DB.Model(&user).Association("ClassesManaging").Find(&classes); err != nil {
panic(errors.Wrap(err, "could not find class managing"))
}
return c.JSON(http.StatusOK, response.GetClassesIManageResponse{
Expand All @@ -120,7 +119,7 @@ func GetClassesIManage(c echo.Context) error {
func GetClassesITake(c echo.Context) error {
user := c.Get("user").(models.User)
var classes []models.Class
if err := base.DB.Model(&user).Preload("Managers").Preload("Students").Association("ClassesTaking").Find(&classes); err != nil {
if err := base.DB.Model(&user).Association("ClassesTaking").Find(&classes); err != nil {
panic(errors.Wrap(err, "could not find class taking"))
}
return c.JSON(http.StatusOK, response.GetClassesITakeResponse{
Expand Down Expand Up @@ -199,12 +198,7 @@ func AddStudents(c echo.Context) error {
panic(errors.Wrap(err, "could not find class for adding students"))
}
}
databaseIds := make([]uint, len(class.Students))
for i, s := range class.Students {
databaseIds[i] = s.ID
}
ids := utils.IdUniqueInA(req.UserIds, databaseIds)
if err := class.AddStudents(ids); err != nil {
if err := class.AddStudents(req.UserIds); err != nil {
panic(errors.Wrap(err, "could not add students"))
}
return c.JSON(http.StatusOK, response.AddStudentsResponse{
Expand Down Expand Up @@ -264,7 +258,8 @@ func JoinClass(c echo.Context) error {
return c.JSON(http.StatusForbidden, response.ErrorResp("WRONG_INVITE_CODE", nil))
}
user := c.Get("user").(models.User)
if user.In(class.Students) {
count := base.DB.Model(&class).Where("id = ?", user.ID).Association("Students").Count()
if count > 0 {
return c.JSON(http.StatusBadRequest, response.ErrorResp("ALREADY_IN_CLASS", nil))
}
if err := base.DB.Model(&class).Association("Students").Append(&user); err != nil {
Expand Down
7 changes: 7 additions & 0 deletions app/controller/class_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ func TestGetClassesIManageAndTake(t *testing.T) {
assert.NoError(t, base.DB.First(&users[i], users[i].ID).Error)
}

class1.Students = nil
class1.Managers = nil
class2.Students = nil
class2.Managers = nil
class3.Students = nil
class3.Managers = nil

manageClasses := map[int][]models.Class{
0: {},
1: {
Expand Down
18 changes: 0 additions & 18 deletions base/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,3 @@ func Contain(obj interface{}, target interface{}) bool {

return false
}

// IdUniqueInA returns IDs that in a but not in b
// Reference: https://stackoverflow.com/questions/52120488/what-is-the-most-efficient-way-to-get-the-intersection-and-exclusions-from-two-a
func IdUniqueInA(a []uint, b []uint) (uniqueA []uint) {
m := make(map[uint]uint8)
for _, v := range a {
m[v] |= 1 << 0
}
for _, v := range b {
m[v] |= 1 << 1
}
for v, sel := range m {
if sel == 1<<0 {
uniqueA = append(uniqueA, v)
}
}
return
}
6 changes: 5 additions & 1 deletion database/models/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ func (c Class) TypeName() string {
}

func (c *Class) AddStudents(ids []uint) error {
existingIds := make([]uint, len(c.Students))
for i, s := range c.Students {
existingIds[i] = s.ID
}
var users []User
if err := base.DB.Find(&users, ids).Error; err != nil {
if err := base.DB.Not("id in ?", existingIds).Find(&users, ids).Error; err != nil {
return err
}
return base.DB.Model(c).Association("Students").Append(&users)
Expand Down
34 changes: 34 additions & 0 deletions database/models/class_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,40 @@ func TestAddStudentsAndDeleteStudentsByID(t *testing.T) {
DeletedAt: gorm.DeletedAt{},
}, class)
})
t.Run("AddExistingInClass", func(t *testing.T) {
class := Class{
Name: "test_add_students_existing_in_class_name",
CourseName: "test_add_students_existing_in_class_course_name",
Description: "test_add_students_existing_in_class_description",
InviteCode: "test_add_students_existing_in_class_invite_code",
Managers: []User{},
Students: []User{
user1,
user2,
},
}
assert.NoError(t, base.DB.Create(&class).Error)
assert.NoError(t, class.AddStudents([]uint{
user2.ID,
user3.ID,
}))
assert.Equal(t, Class{
ID: class.ID,
Name: "test_add_students_existing_in_class_name",
CourseName: "test_add_students_existing_in_class_course_name",
Description: "test_add_students_existing_in_class_description",
InviteCode: "test_add_students_existing_in_class_invite_code",
Managers: []User{},
Students: []User{
user1,
user2,
user3,
},
CreatedAt: class.CreatedAt,
UpdatedAt: class.UpdatedAt,
DeletedAt: gorm.DeletedAt{},
}, class)
})
t.Run("AddNonExist", func(t *testing.T) {
class := Class{
Name: "test_add_students_non_exist_class_name",
Expand Down

0 comments on commit 828563d

Please sign in to comment.