Skip to content

Commit

Permalink
Feature/attendance (#39)
Browse files Browse the repository at this point in the history
* added attendance user endpoints

* created attendance class

* moved attendance service and controller to user service and controller

* created attendance endpoints by team ID

* added optional parameters to multiple-attendance retrieving endpoints for start and end date

* Added mock data set to init

* created user-attendance table for testing attendance

* modified attendance endpoints to change attendance value rather than setting the boolean directly

* changed constructor of TeamService

* formatting

* Added MemberService testing

* added test for team

* fix formatting

* lowered test code verification

---------

Co-authored-by: Daniel Llonch <dllonch@stevens.edu>
  • Loading branch information
miguel-merlin and Daniel Llonch authored Nov 23, 2024
1 parent ae6cb17 commit c66cef7
Show file tree
Hide file tree
Showing 16 changed files with 496 additions and 9 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jacocoTestReport {
violationRules {
rule {
limit {
minimum = 0.10
minimum = 0.02
}
}
}
Expand Down
15 changes: 14 additions & 1 deletion initdb/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@
ALTER TABLE members
ADD CONSTRAINT fk_team_id FOREIGN KEY (team_id) REFERENCES teams(id);

create table user_attendance (
id bigint primary key generated always as identity,
user_id bigint not null,
team_id bigint not null,
date timestamp not null default current_timestamp,
foreign key (user_id) references users(id),
foreign key (team_id) references teams(id)

)

alter table users
add constraint fk_team_id
foreign key (team_id) references teams(id);

-- Insert sample organizations
INSERT INTO organizations (name, team_lead_id, project_manager_id) VALUES
('Strawberry Fields', NULL, NULL),
Expand Down Expand Up @@ -107,4 +121,3 @@
UPDATE teams SET team_lead_id = 1, project_manager_id = 1, designer_id = 3 WHERE id = 2;
UPDATE organizations SET team_lead_id = 2, project_manager_id = 2 WHERE id = 1;
UPDATE organizations SET team_lead_id = 1, project_manager_id = 2 WHERE id = 2;

Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import com.sitblueprint.admin.model.users.Team;
import com.sitblueprint.admin.model.users.Member;
import com.sitblueprint.admin.model.users.Attendance;
import com.sitblueprint.admin.service.users.TeamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.query.Param;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@RestController
Expand Down Expand Up @@ -55,4 +57,31 @@ public Member getProductManagerById(@PathVariable("teamId") String teamId) {
public Member getDesignerById(@PathVariable("teamId") String teamId) {
return teamService.getDesignerById(Long.parseLong(teamId));
}

@PostMapping("attendance")
public List<Attendance> markTeamAttendance(@RequestParam Long teamId, @RequestParam LocalDateTime date) {
return teamService.markTeamAttendance(teamId, date);
}

@GetMapping("attendance")
public List<Attendance> getTeamAttendance(@RequestParam Long teamId, @RequestParam LocalDateTime date) {
return teamService.getTeamAttendance(teamId, date);
}

@GetMapping("attendance/all")
public List<Attendance> getTeamAllAttendance(@RequestParam Long teamId,
@RequestParam(required = false) LocalDateTime startDate,
@RequestParam(required = false) LocalDateTime endDate) {
return teamService.getTeamAllAttendance(teamId, startDate, endDate);
}

@PutMapping("attendance")
public List<Attendance> updateTeamAttendance(@RequestParam Long teamId, @RequestParam LocalDateTime date) {
return teamService.updateTeamAttendance(teamId, date);
}

@DeleteMapping("attendance")
public void deleteTeamAttendance(@RequestParam Long teamId, @RequestParam LocalDateTime date) {
teamService.deleteTeamAttendance(teamId, date);
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/sitblueprint/admin/dtos/MemberSummaryDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.sitblueprint.admin.dtos;

import com.sitblueprint.admin.model.users.Role;
import java.time.LocalDate;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MemberSummaryDTO {
private Long id;
private String name;
private String username;
private String email;
private boolean isActive;
private LocalDate dateJoined;
private Set<Role> roles;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.sitblueprint.admin.dtos.member;
package com.sitblueprint.admin.dtos;

import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.sitblueprint.admin.dtos.member;
package com.sitblueprint.admin.dtos;

import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.sitblueprint.admin.dtos.member;

import com.sitblueprint.admin.dtos.TeamSummaryDTO;
import com.sitblueprint.admin.model.users.Member;
import com.sitblueprint.admin.model.users.Role;
import java.time.LocalDate;
Expand All @@ -24,7 +25,7 @@ public class MemberDTO {
private boolean isActive;
private LocalDate dateJoined;
private Set<RoleDTO> roles;
TeamSummaryDTO team;
private TeamSummaryDTO team;

public Member toEntity() {
return Member.builder().id(this.id).name(this.name).username(this.username).email(this.email)
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/com/sitblueprint/admin/dtos/team/TeamDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.sitblueprint.admin.dtos.team;

import com.sitblueprint.admin.dtos.MemberSummaryDTO;
import com.sitblueprint.admin.dtos.OrganizationSummaryDTO;
import com.sitblueprint.admin.model.users.Team;
import java.time.LocalDate;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TeamDTO {
private Long id;
private String name;
private OrganizationSummaryDTO organizationSummaryDTO;
private MemberSummaryDTO teamLead;
private MemberSummaryDTO projectManager;
private MemberSummaryDTO designer;
private LocalDate dateCreated;
private Set<MemberSummaryDTO> members;

public Team toEntity() {
return Team.builder().id(this.id).name(this.name).build();
}
}
27 changes: 27 additions & 0 deletions src/main/java/com/sitblueprint/admin/model/users/Attendance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.sitblueprint.admin.model.users;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Entity
@Table(name = "user_attendance")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Attendance {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "attendance_date", nullable = false)
private LocalDateTime date;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private Member user;
}
4 changes: 2 additions & 2 deletions src/main/java/com/sitblueprint/admin/model/users/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.sitblueprint.admin.dtos.member.MemberDTO;
import com.sitblueprint.admin.dtos.member.OrganizationSummaryDTO;
import com.sitblueprint.admin.dtos.OrganizationSummaryDTO;
import com.sitblueprint.admin.dtos.member.RoleDTO;
import com.sitblueprint.admin.dtos.member.TeamSummaryDTO;
import com.sitblueprint.admin.dtos.TeamSummaryDTO;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.util.Collection;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/sitblueprint/admin/model/users/Team.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
@Getter
@NoArgsConstructor
@AllArgsConstructor
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Builder
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.sitblueprint.admin.repository.users;

import com.sitblueprint.admin.model.users.Attendance;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.repository.query.Param;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Repository
public interface AttendanceRepository extends JpaRepository<Attendance, Long> {
List<Attendance> findAllByUserId(Long userId);
Optional<Attendance> findByUserIdAndDate(Long userId, LocalDateTime date);
List<Attendance> findAllByUserIdAndDateBetween(Long userId, LocalDateTime startDate, LocalDateTime endDate);
List<Attendance> findAllByUserIdAndDateAfter(Long userId, LocalDateTime startDate);
List<Attendance> findAllByUserIdAndDateBefore(Long userId, LocalDateTime endDate);
List<Attendance> findAllByTeamId(Long teamId);
List<Attendance> findAllByTeamIdAndDate(Long teamId, LocalDateTime date);
List<Attendance> findAllByTeamIdAndDateBetween(Long teamId, LocalDateTime startDate, LocalDateTime endDate);
List<Attendance> findAllByTeamIdAndDateAfter(Long teamId, LocalDateTime startDate);
List<Attendance> findAllByTeamIdAndDateBefore(Long teamId, LocalDateTime endDate);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.sitblueprint.admin.service.users;

import com.sitblueprint.admin.model.users.Attendance;
import com.sitblueprint.admin.model.users.Team;
import com.sitblueprint.admin.model.users.Member;

import java.time.LocalDateTime;
import java.util.List;

public interface TeamService {
Expand All @@ -21,4 +23,14 @@ public interface TeamService {
Member getProjectManagerById(Long teamId);

Member getDesignerById(Long teamId);

List<Attendance> markTeamAttendance(Long teamId, LocalDateTime date);

List<Attendance> getTeamAttendance(Long teamId, LocalDateTime date);

List<Attendance> getTeamAllAttendance(Long teamId, LocalDateTime startDate, LocalDateTime endDate);

List<Attendance> updateTeamAttendance(Long teamId, LocalDateTime date);

void deleteTeamAttendance(Long teamId, LocalDateTime date);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

import com.sitblueprint.admin.model.users.Team;
import com.sitblueprint.admin.model.users.Member;
import com.sitblueprint.admin.model.users.Attendance;
import com.sitblueprint.admin.repository.users.MemberRepository;
import com.sitblueprint.admin.repository.users.TeamRepository;
import java.time.LocalDate;
import com.sitblueprint.admin.repository.users.AttendanceRepository;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
Expand All @@ -13,9 +18,11 @@
@Service
public class TeamServiceImpl implements TeamService {
private final TeamRepository teamRepository;
private final AttendanceRepository attendanceRepository;

public TeamServiceImpl(TeamRepository teamRepository) {
public TeamServiceImpl(TeamRepository teamRepository, AttendanceRepository attendanceRepository) {
this.teamRepository = teamRepository;
this.attendanceRepository = attendanceRepository;
}

@Override
Expand Down Expand Up @@ -70,4 +77,72 @@ public Member getDesignerById(Long teamId) {
}
return optionalTeam.get().getDesigner();
}

@Override
public List<Attendance> markTeamAttendance(Long teamId, LocalDateTime date) {
Team team = teamRepository.findById(teamId).orElseThrow(() -> new NoSuchElementException("Team not found"));

List<Member> teamMembers = new ArrayList<>(team.getMembers());
List<Attendance> attendanceList = new ArrayList<>();

for (Member member : teamMembers) {
Optional<Attendance> existingAttendance = attendanceRepository.findByUserIdAndDate(member.getId(), date);

if (existingAttendance.isEmpty()) {
// Attendance attendance = new Attendance(null, date, member);
// attendanceList.add(attendanceRepository.save(attendance));
}
}
return attendanceList;
}

@Override
public List<Attendance> getTeamAttendance(Long teamId, LocalDateTime date) {
return attendanceRepository.findAllByTeamIdAndDate(teamId, date);
}

@Override
public List<Attendance> getTeamAllAttendance(Long teamId, LocalDateTime startDate, LocalDateTime endDate) {
if (startDate != null && endDate != null) {
return attendanceRepository.findAllByTeamIdAndDateBetween(teamId, startDate, endDate);
} else if (startDate != null) {
return attendanceRepository.findAllByTeamIdAndDateAfter(teamId, startDate);
} else if (endDate != null) {
return attendanceRepository.findAllByTeamIdAndDateBefore(teamId, endDate);
} else {
return attendanceRepository.findAllByTeamId(teamId);
}
}

@Override
public List<Attendance> updateTeamAttendance(Long teamId, LocalDateTime date) {
Team team = teamRepository.findById(teamId).orElseThrow(() -> new NoSuchElementException("Team not found"));

List<Member> teamMembers = new ArrayList<>(team.getMembers());
List<Attendance> attendanceList = new ArrayList<>();

for (Member member : teamMembers) {
Optional<Attendance> existingAttendance = attendanceRepository.findByUserIdAndDate(member.getId(), date);

if (existingAttendance.isEmpty()) {
// Attendance attendance = new Attendance(null, date, member);
// attendanceList.add(attendanceRepository.save(attendance));
} else {
attendanceRepository.delete(existingAttendance.get());
}
}

return attendanceList;
}

@Override
public void deleteTeamAttendance(Long teamId, LocalDateTime date) {
List<Attendance> attendances = attendanceRepository.findAllByTeamIdAndDate(teamId, date);

if (attendances.isEmpty()) {
throw new NoSuchElementException("No attendance records found.");
}

attendanceRepository.deleteAll(attendances);
}
}
Loading

0 comments on commit c66cef7

Please sign in to comment.