Skip to content

Commit

Permalink
feat(meeting): ✨ get attendance for meeting
Browse files Browse the repository at this point in the history
- use custom response struct
  • Loading branch information
anirudhgray committed Oct 21, 2023
1 parent 888eaa7 commit aece0ff
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 11 deletions.
22 changes: 19 additions & 3 deletions controllers/meeting.controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,7 @@ func (mc *MeetingController) MarkAttendance(c *gin.Context) {
return
}

// Retrieve the authenticated user from the context
currentUser, _ := c.Get("user")

// Type-assert the user to the models.User struct
userID := currentUser.(*models.User).ID

// Call the meeting service to mark attendance
Expand All @@ -243,3 +240,22 @@ func (mc *MeetingController) MarkAttendance(c *gin.Context) {

c.JSON(http.StatusOK, gin.H{"message": "Attendance marked successfully.", "onTime": onTime})
}

// GetAttendanceForMeeting retrieves attendance for a meeting.
func (mc *MeetingController) GetAttendanceForMeeting(c *gin.Context) {
// Get meeting ID from route parameters
meetingID, teamID, err := getTeamAndMeetingFromQueryParams(c)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": "Invalid meeting or team ID", "error": err.Error()})
return
}

// Call the meeting service to get attendance for the meeting
attendance, err := mc.meetingService.GetAttendanceForMeeting(meetingID, teamID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to get attendance for the meeting", "error": err.Error()})
return
}

c.JSON(http.StatusOK, attendance)
}
13 changes: 13 additions & 0 deletions mocks/meeting.service_mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ func (m *MockMeetingService) MarkAttendanceForUserInMeeting(userID, meetingID ui
return ret0, ret1
}

// GetAttendanceForMeeting mocks the GetAttendanceForMeeting method.
func (m *MockMeetingService) GetAttendanceForMeeting(meetingID, teamID uint) ([]models.MeetingAttendanceListResponse, error) {
ret := m.ctrl.Call(m, "GetAttendanceForMeeting", meetingID, teamID)
ret0, _ := ret[0].([]models.MeetingAttendanceListResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}

// MockMeetingServiceMockRecorder is a mock recorder for MockMeetingService.
type MockMeetingServiceMockRecorder struct {
mock *MockMeetingService
Expand Down Expand Up @@ -145,3 +153,8 @@ func (mr *MockMeetingServiceMockRecorder) DeleteMeetingByID(meetingID, teamid ui
func (mr *MockMeetingServiceMockRecorder) MarkAttendanceForUserInMeeting(userID, meetingID uint, attendanceTime time.Time, teamid uint) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarkAttendanceForUserInMeeting", reflect.TypeOf((*MockMeetingService)(nil).MarkAttendanceForUserInMeeting), userID, meetingID, attendanceTime, teamid)
}

// GetAttendanceForMeeting mocks the GetAttendanceForMeeting method.
func (mr *MockMeetingServiceMockRecorder) GetAttendanceForMeeting(meetingID, teamID uint) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAttendanceForMeeting", reflect.TypeOf((*MockMeetingService)(nil).GetAttendanceForMeeting), meetingID, teamID)
}
10 changes: 9 additions & 1 deletion models/meeting.model.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type MeetingAttendance struct {
UserID uint `gorm:"primaryKey;not null"`
MeetingID uint `gorm:"primaryKey;not null"`
AttendanceMarkedAt time.Time `gorm:"not null"`
OnTime bool `gorm:"default:true"`
OnTime bool
}

func (ma *MeetingAttendance) BeforeCreate(tx *gorm.DB) error {
Expand All @@ -69,3 +69,11 @@ func (ma *MeetingAttendance) BeforeCreate(tx *gorm.DB) error {
}
return nil
}

type MeetingAttendanceListResponse struct {
ID uint
MeetingID uint
AttendanceMarkedAt time.Time
OnTime bool
User User
}
3 changes: 3 additions & 0 deletions routers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ func RegisterRoutes(route *gin.Engine) {

// mark attendance for a user in a meeting
team.PATCH("/:teamID/meetings/:meetingID/attendance", middleware.BaseAuthMiddleware(), middleware.AuthorizeMember(), meetingController.MarkAttendance)

// admin get attendance for a meeting
team.GET("/:teamID/meetings/:meetingID/attendance", middleware.BaseAuthMiddleware(), middleware.AuthorizeAdmin(), meetingController.GetAttendanceForMeeting)
}
}

Expand Down
48 changes: 41 additions & 7 deletions services/meeting.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type MeetingServiceInterface interface {
EndAttendance(meetingID uint, teamid uint) (models.Meeting, error)
DeleteMeetingByID(meetingID uint, teamid uint) error
MarkAttendanceForUserInMeeting(userID, meetingID uint, attendanceTime time.Time, teamid uint) (bool, error)
GetAttendanceForMeeting(meetingID, teamID uint) ([]models.MeetingAttendanceListResponse, error)
}

// CreateMeeting creates a new meeting in the database.
Expand Down Expand Up @@ -239,17 +240,19 @@ func (ms *MeetingService) MarkAttendanceForUserInMeeting(userID, meetingID uint,
return false, errors.New("attendance already marked")
}

var onTime bool
// if attendance period ended (but meeting period still on), mark attendance as late
if meeting.AttendanceOver && meeting.MeetingPeriod {
onTime = false
} else {
onTime = true
}

meetingAttendance := models.MeetingAttendance{
UserID: userID,
MeetingID: meetingID,
AttendanceMarkedAt: attendanceTime,
}

// if attendance period ended (but meeting period still on), mark attendance as late
if meeting.AttendanceOver && meeting.MeetingPeriod {
meetingAttendance.OnTime = false
} else {
meetingAttendance.OnTime = true
OnTime: onTime,
}

if err := ms.meetingRepo.AddMeetingAttendance(meetingAttendance); err != nil {
Expand All @@ -259,4 +262,35 @@ func (ms *MeetingService) MarkAttendanceForUserInMeeting(userID, meetingID uint,
return meetingAttendance.OnTime, nil
}

// GetAttendanceForMeeting retrieves attendance for a meeting.
func (ms *MeetingService) GetAttendanceForMeeting(meetingID, teamID uint) ([]models.MeetingAttendanceListResponse, error) {
_, err := ms.GetMeetingByID(meetingID, teamID)
if err != nil {
return []models.MeetingAttendanceListResponse{}, err
}
attendance, err := ms.meetingRepo.GetMeetingAttendanceByMeetingID(meetingID)
if err != nil {
return nil, err
}

userRepo := repository.NewUserRepository()
// Get user details for each attendance record, and make array of MeetingAttendanceResponse
var attendanceResponse []models.MeetingAttendanceListResponse
for _, attendanceRecord := range attendance {
user, err := userRepo.GetUserByID(attendanceRecord.UserID)
if err != nil {
return nil, err
}
attendanceResponse = append(attendanceResponse, models.MeetingAttendanceListResponse{
ID: attendanceRecord.ID,
MeetingID: attendanceRecord.MeetingID,
AttendanceMarkedAt: attendanceRecord.AttendanceMarkedAt,
OnTime: attendanceRecord.OnTime,
User: user,
})
}

return attendanceResponse, nil
}

// GetMeetingStatsByMeetingID retrieves meeting stats for a given meeting ID. Stats: total attendance, on time attendance, late attendance.

0 comments on commit aece0ff

Please sign in to comment.