From 8fee13e2f96f9466054cc38a5a843b2c1e248b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Sun, 21 Dec 2025 23:13:05 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=A3=D0=BA=D0=B7=D0=B0=D0=BB=20JDK25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 6 ++++++ src/main/java/org/lab/Main.java | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 79bf52a..429fefa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,12 @@ plugins { id("java") } +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + group = "org.lab" version = "1.0-SNAPSHOT" diff --git a/src/main/java/org/lab/Main.java b/src/main/java/org/lab/Main.java index 22028ef..00fdd8f 100644 --- a/src/main/java/org/lab/Main.java +++ b/src/main/java/org/lab/Main.java @@ -1,4 +1,8 @@ -void main() { - IO.println("Hello and welcome!"); -} +package org.lab; + +public class Main { + void main() { + IO.println("Hello and welcome!"); + } +} From e3c48fbd4715224a37d7fec122fddee94a5219da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Sun, 21 Dec 2025 23:13:20 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/lab/model/BugReport/BugReport.java | 11 ++ .../lab/model/BugReport/BugReportRole.java | 7 ++ .../lab/model/BugReport/BugReportStatus.java | 8 ++ .../lab/model/MilestoneModel/Milestone.java | 72 ++++++++++++ .../model/MilestoneModel/MilestoneStatus.java | 7 ++ .../org/lab/model/ProjectModel/Project.java | 111 ++++++++++++++++++ .../lab/model/ProjectModel/ProjectMember.java | 6 + .../lab/model/ProjectModel/ProjectRole.java | 8 ++ .../java/org/lab/model/TaskModel/Task.java | 11 ++ .../org/lab/model/TaskModel/TaskRole.java | 6 + .../org/lab/model/TaskModel/TaskStatus.java | 8 ++ .../org/lab/model/TicketModel/Ticket.java | 74 ++++++++++++ .../java/org/lab/model/UserModel/User.java | 4 + 13 files changed, 333 insertions(+) create mode 100644 src/main/java/org/lab/model/BugReport/BugReport.java create mode 100644 src/main/java/org/lab/model/BugReport/BugReportRole.java create mode 100644 src/main/java/org/lab/model/BugReport/BugReportStatus.java create mode 100644 src/main/java/org/lab/model/MilestoneModel/Milestone.java create mode 100644 src/main/java/org/lab/model/MilestoneModel/MilestoneStatus.java create mode 100644 src/main/java/org/lab/model/ProjectModel/Project.java create mode 100644 src/main/java/org/lab/model/ProjectModel/ProjectMember.java create mode 100644 src/main/java/org/lab/model/ProjectModel/ProjectRole.java create mode 100644 src/main/java/org/lab/model/TaskModel/Task.java create mode 100644 src/main/java/org/lab/model/TaskModel/TaskRole.java create mode 100644 src/main/java/org/lab/model/TaskModel/TaskStatus.java create mode 100644 src/main/java/org/lab/model/TicketModel/Ticket.java create mode 100644 src/main/java/org/lab/model/UserModel/User.java diff --git a/src/main/java/org/lab/model/BugReport/BugReport.java b/src/main/java/org/lab/model/BugReport/BugReport.java new file mode 100644 index 0000000..790167c --- /dev/null +++ b/src/main/java/org/lab/model/BugReport/BugReport.java @@ -0,0 +1,11 @@ +package org.lab.model.BugReport; + +import org.lab.model.TicketModel.Ticket; + +public final class BugReport extends Ticket { + + public BugReport(String id, String name, String description) { + super(id, name, description, BugReportStatus.OPEN); + } + +} diff --git a/src/main/java/org/lab/model/BugReport/BugReportRole.java b/src/main/java/org/lab/model/BugReport/BugReportRole.java new file mode 100644 index 0000000..5dc4232 --- /dev/null +++ b/src/main/java/org/lab/model/BugReport/BugReportRole.java @@ -0,0 +1,7 @@ +package org.lab.model.BugReport; + +public enum BugReportRole { + DEV, + TESTER, + REPORTER, +} diff --git a/src/main/java/org/lab/model/BugReport/BugReportStatus.java b/src/main/java/org/lab/model/BugReport/BugReportStatus.java new file mode 100644 index 0000000..e7372c6 --- /dev/null +++ b/src/main/java/org/lab/model/BugReport/BugReportStatus.java @@ -0,0 +1,8 @@ +package org.lab.model.BugReport; + +public enum BugReportStatus { + OPEN, + FIXED, + TESTED, + CLOSED +} diff --git a/src/main/java/org/lab/model/MilestoneModel/Milestone.java b/src/main/java/org/lab/model/MilestoneModel/Milestone.java new file mode 100644 index 0000000..c58d47b --- /dev/null +++ b/src/main/java/org/lab/model/MilestoneModel/Milestone.java @@ -0,0 +1,72 @@ +package org.lab.model.MilestoneModel; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import org.lab.model.TaskModel.Task; + +public class Milestone { + private String id; + private String name; + private LocalDate start; + private LocalDate end; + private MilestoneStatus status; + + private final List tasks; + + public Milestone(String id, String name, LocalDate start, LocalDate end) { + this.id = Objects.requireNonNull(id); + this.name = Objects.requireNonNull(name); + this.start = Objects.requireNonNull(start); + this.end = Objects.requireNonNull(end); + status = MilestoneStatus.OPEN; + tasks = new ArrayList<>(); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = Objects.requireNonNull(name); + } + + public LocalDate getStart() { + return start; + } + + public void setStart(LocalDate start) { + this.start = Objects.requireNonNull(start); + } + + public LocalDate getEnd() { + return end; + } + + public void setEnd(LocalDate end) { + this.end = Objects.requireNonNull(end); + } + + public MilestoneStatus getStatus() { + return status; + } + + public void setStatus(MilestoneStatus status) { + this.status = Objects.requireNonNull(status); + } + + public void addTask(Task task) { + tasks.add(Objects.requireNonNull(task)); + } + + public List getTasks() { + return Collections.unmodifiableList(tasks); + } +} diff --git a/src/main/java/org/lab/model/MilestoneModel/MilestoneStatus.java b/src/main/java/org/lab/model/MilestoneModel/MilestoneStatus.java new file mode 100644 index 0000000..1e8c46a --- /dev/null +++ b/src/main/java/org/lab/model/MilestoneModel/MilestoneStatus.java @@ -0,0 +1,7 @@ +package org.lab.model.MilestoneModel; + +public enum MilestoneStatus { + OPEN, + ACTIVE, + CLOSED, +} diff --git a/src/main/java/org/lab/model/ProjectModel/Project.java b/src/main/java/org/lab/model/ProjectModel/Project.java new file mode 100644 index 0000000..df1c8ac --- /dev/null +++ b/src/main/java/org/lab/model/ProjectModel/Project.java @@ -0,0 +1,111 @@ +package org.lab.model.ProjectModel; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.lab.model.BugReport.BugReport; +import org.lab.model.MilestoneModel.Milestone; + +public class Project { + private String id; + private String name; + private ProjectMember lead; + private ProjectMember manager; + private final Set members; + + private Milestone activeMilestone; + private final Set milestones; + + private final Set bugReports; + + public Project(String id, String name, ProjectMember manager) { + this.id = Objects.requireNonNull(id); + this.name = Objects.requireNonNull(name); + this.manager = Objects.requireNonNull(manager); + + members = new HashSet<>(); + milestones = new HashSet<>(); + bugReports = new HashSet<>(); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = Objects.requireNonNull(name); + } + + public ProjectMember getLead() { + return lead; + } + + public void setLead(ProjectMember lead) { + if (!members.contains(lead)) { + throw new IllegalArgumentException("user must be in project"); + } + + if (lead.role() != ProjectRole.LEAD) { + throw new IllegalArgumentException("project member must be lead"); + } + + this.lead = lead; + } + + public ProjectMember getManager() { + return manager; + } + + public void setManager(ProjectMember manager) { + if (!members.contains(manager)) { + throw new IllegalArgumentException("user must be in project"); + } + + if (manager.role() != ProjectRole.MANAGER) { + throw new IllegalArgumentException("project member must be manager"); + } + + this.manager = Objects.requireNonNull(manager); + } + + public void addMember(ProjectMember member) { + members.add(member); + } + + public Set getMembers() { + return members; + } + + public Milestone getActiveMilestone() { + return activeMilestone; + } + + public void setActiveMilestone(Milestone activeMilestone) { + if (!milestones.contains(activeMilestone)) { + throw new IllegalArgumentException("milestones must be in project"); + } + + this.activeMilestone = activeMilestone; + } + + public void addMilestone(Milestone milestone) { + milestones.add(milestone); + } + + public Set getMilestones() { + return milestones; + } + + public void attachBugReport(BugReport report) { + bugReports.add(report); + } + + public Set getBugReports() { + return bugReports; + } +} diff --git a/src/main/java/org/lab/model/ProjectModel/ProjectMember.java b/src/main/java/org/lab/model/ProjectModel/ProjectMember.java new file mode 100644 index 0000000..cb831ba --- /dev/null +++ b/src/main/java/org/lab/model/ProjectModel/ProjectMember.java @@ -0,0 +1,6 @@ +package org.lab.model.ProjectModel; + +import org.lab.model.UserModel.User; + +public record ProjectMember(User user, ProjectRole role) { +} diff --git a/src/main/java/org/lab/model/ProjectModel/ProjectRole.java b/src/main/java/org/lab/model/ProjectModel/ProjectRole.java new file mode 100644 index 0000000..9b7cdc8 --- /dev/null +++ b/src/main/java/org/lab/model/ProjectModel/ProjectRole.java @@ -0,0 +1,8 @@ +package org.lab.model.ProjectModel; + +public enum ProjectRole { + LEAD, + DEV, + TESTER, + MANAGER, +} diff --git a/src/main/java/org/lab/model/TaskModel/Task.java b/src/main/java/org/lab/model/TaskModel/Task.java new file mode 100644 index 0000000..f1e0622 --- /dev/null +++ b/src/main/java/org/lab/model/TaskModel/Task.java @@ -0,0 +1,11 @@ +package org.lab.model.TaskModel; + +import org.lab.model.TicketModel.Ticket; + +public final class Task extends Ticket { + + public Task(String id, String name, String description) { + super(id, name, description, TaskStatus.OPENED); + } + +} diff --git a/src/main/java/org/lab/model/TaskModel/TaskRole.java b/src/main/java/org/lab/model/TaskModel/TaskRole.java new file mode 100644 index 0000000..3b64cf0 --- /dev/null +++ b/src/main/java/org/lab/model/TaskModel/TaskRole.java @@ -0,0 +1,6 @@ +package org.lab.model.TaskModel; + +public enum TaskRole { + DEV, + TESTER, +} diff --git a/src/main/java/org/lab/model/TaskModel/TaskStatus.java b/src/main/java/org/lab/model/TaskModel/TaskStatus.java new file mode 100644 index 0000000..377ebfe --- /dev/null +++ b/src/main/java/org/lab/model/TaskModel/TaskStatus.java @@ -0,0 +1,8 @@ +package org.lab.model.TaskModel; + +public enum TaskStatus { + OPENED, + READY_FOR_WORK, + IN_PROGESS, + CLOSED, +} diff --git a/src/main/java/org/lab/model/TicketModel/Ticket.java b/src/main/java/org/lab/model/TicketModel/Ticket.java new file mode 100644 index 0000000..b8cd69a --- /dev/null +++ b/src/main/java/org/lab/model/TicketModel/Ticket.java @@ -0,0 +1,74 @@ +package org.lab.model.TicketModel; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.lab.model.ProjectModel.ProjectMember; + +public abstract class Ticket { + private String id; + private String name; + private String description; + + private final Map> members; + + private ProjectMember assignee; + private TStatus status; + + public Ticket(String id, String name, String description, TStatus initialStatus) { + this.id = Objects.requireNonNull(id); + this.name = Objects.requireNonNull(name); + this.description = Objects.requireNonNull(description); + members = new HashMap<>(); + status = Objects.requireNonNull(initialStatus); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = Objects.requireNonNull(name); + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = Objects.requireNonNull(description); + } + + public void addToTicker(TRole role, ProjectMember member) { + members.putIfAbsent(role, new ArrayList<>()); + members.get(role).add(member); + } + + public Map> getTicketMembers() { + return Collections.unmodifiableMap(members); + } + + public ProjectMember getAssignee() { + return assignee; + } + + public void assign(ProjectMember assignee) { + this.assignee = assignee; + } + + public TStatus getStatus() { + return status; + } + + public void setStatus(TStatus status) { + this.status = Objects.requireNonNull(status); + } +} diff --git a/src/main/java/org/lab/model/UserModel/User.java b/src/main/java/org/lab/model/UserModel/User.java new file mode 100644 index 0000000..07d2ddb --- /dev/null +++ b/src/main/java/org/lab/model/UserModel/User.java @@ -0,0 +1,4 @@ +package org.lab.model.UserModel; + +public record User(String id, String email, String name) { +} From 758c3bac7bc5f9c64611672745d7e20cfc5aa92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Mon, 22 Dec 2025 00:50:13 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=80=D0=B5=D0=BF=D1=8B=20=D1=81=20=D1=81=D0=BE=D1=85?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/lab/dto/BugReportDTO.java | 4 +++ src/main/java/org/lab/dto/MilestoneDTO.java | 6 ++++ src/main/java/org/lab/dto/ProjectDTO.java | 6 ++++ src/main/java/org/lab/dto/TaskDTO.java | 4 +++ src/main/java/org/lab/dto/UserDTO.java | 4 +++ .../MilestoneRepo/InMemoryMilestoneRepo.java | 21 ++++++++++++ .../MilestoneRepo/MilestoneRepo.java | 8 +++++ .../ProjectRepo/InMemoryProjectRepo.java | 21 ++++++++++++ .../repositories/ProjectRepo/ProjectRepo.java | 8 +++++ .../TicketRepo/InMemoryTicketRepo.java | 32 +++++++++++++++++++ .../repositories/TicketRepo/TicketRepo.java | 12 +++++++ .../UserRepo/InMemoryUserRepo.java | 21 ++++++++++++ .../lab/repositories/UserRepo/UserRepo.java | 8 +++++ 13 files changed, 155 insertions(+) create mode 100644 src/main/java/org/lab/dto/BugReportDTO.java create mode 100644 src/main/java/org/lab/dto/MilestoneDTO.java create mode 100644 src/main/java/org/lab/dto/ProjectDTO.java create mode 100644 src/main/java/org/lab/dto/TaskDTO.java create mode 100644 src/main/java/org/lab/dto/UserDTO.java create mode 100644 src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java create mode 100644 src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java create mode 100644 src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java create mode 100644 src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java create mode 100644 src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java create mode 100644 src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java create mode 100644 src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java create mode 100644 src/main/java/org/lab/repositories/UserRepo/UserRepo.java diff --git a/src/main/java/org/lab/dto/BugReportDTO.java b/src/main/java/org/lab/dto/BugReportDTO.java new file mode 100644 index 0000000..a9bc67a --- /dev/null +++ b/src/main/java/org/lab/dto/BugReportDTO.java @@ -0,0 +1,4 @@ +package org.lab.dto; + +public record BugReportDTO(String name, String description) { +} diff --git a/src/main/java/org/lab/dto/MilestoneDTO.java b/src/main/java/org/lab/dto/MilestoneDTO.java new file mode 100644 index 0000000..4466c60 --- /dev/null +++ b/src/main/java/org/lab/dto/MilestoneDTO.java @@ -0,0 +1,6 @@ +package org.lab.dto; + +import java.time.LocalDate; + +public record MilestoneDTO(String name, LocalDate start, LocalDate end) { +} \ No newline at end of file diff --git a/src/main/java/org/lab/dto/ProjectDTO.java b/src/main/java/org/lab/dto/ProjectDTO.java new file mode 100644 index 0000000..c9cd52d --- /dev/null +++ b/src/main/java/org/lab/dto/ProjectDTO.java @@ -0,0 +1,6 @@ +package org.lab.dto; + +import org.lab.model.ProjectModel.ProjectMember; + +public record ProjectDTO(String name, ProjectMember manager) { +} \ No newline at end of file diff --git a/src/main/java/org/lab/dto/TaskDTO.java b/src/main/java/org/lab/dto/TaskDTO.java new file mode 100644 index 0000000..e1cad7d --- /dev/null +++ b/src/main/java/org/lab/dto/TaskDTO.java @@ -0,0 +1,4 @@ +package org.lab.dto; + +public record TaskDTO(String name, String description) { +} diff --git a/src/main/java/org/lab/dto/UserDTO.java b/src/main/java/org/lab/dto/UserDTO.java new file mode 100644 index 0000000..a88c563 --- /dev/null +++ b/src/main/java/org/lab/dto/UserDTO.java @@ -0,0 +1,4 @@ +package org.lab.dto; + +public record UserDTO(String email, String name) { +} diff --git a/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java b/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java new file mode 100644 index 0000000..e8a3231 --- /dev/null +++ b/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java @@ -0,0 +1,21 @@ +package org.lab.repositories.MilestoneRepo; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.lab.dto.MilestoneDTO; +import org.lab.model.MilestoneModel.Milestone; + +public class InMemoryMilestoneRepo implements MilestoneRepo { + private final Map store = new HashMap<>(); + + @Override + public Milestone save(MilestoneDTO milestoneDTO) { + var uuid = UUID.randomUUID(); + var milestone = new Milestone(uuid.toString(), milestoneDTO.name(), milestoneDTO.start(), milestoneDTO.end()); + store.put(uuid, milestone); + return milestone; + } + +} diff --git a/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java b/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java new file mode 100644 index 0000000..ccfccc7 --- /dev/null +++ b/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java @@ -0,0 +1,8 @@ +package org.lab.repositories.MilestoneRepo; + +import org.lab.dto.MilestoneDTO; +import org.lab.model.MilestoneModel.Milestone; + +public interface MilestoneRepo { + Milestone save(MilestoneDTO milestoneDTO); +} diff --git a/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java b/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java new file mode 100644 index 0000000..d1f8b1c --- /dev/null +++ b/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java @@ -0,0 +1,21 @@ +package org.lab.repositories.ProjectRepo; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.lab.dto.ProjectDTO; +import org.lab.model.ProjectModel.Project; + +public class InMemoryProjectRepo implements ProjectRepo { + private final Map store = new HashMap<>(); + + @Override + public Project save(ProjectDTO projectDTO) { + var uuid = UUID.randomUUID(); + var project = new Project(uuid.toString(), projectDTO.name(), projectDTO.manager()); + store.put(uuid, project); + return project; + } + +} diff --git a/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java b/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java new file mode 100644 index 0000000..5d651d0 --- /dev/null +++ b/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java @@ -0,0 +1,8 @@ +package org.lab.repositories.ProjectRepo; + +import org.lab.dto.ProjectDTO; +import org.lab.model.ProjectModel.Project; + +public interface ProjectRepo { + Project save(ProjectDTO projectDTO); +} diff --git a/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java b/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java new file mode 100644 index 0000000..12e3827 --- /dev/null +++ b/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java @@ -0,0 +1,32 @@ +package org.lab.repositories.TicketRepo; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.lab.dto.BugReportDTO; +import org.lab.dto.TaskDTO; +import org.lab.model.BugReport.BugReport; +import org.lab.model.TaskModel.Task; + +public class InMemoryTicketRepo implements TicketRepo { + private final Map taskStore = new HashMap<>(); + private final Map bugReportStore = new HashMap<>(); + + @Override + public Task saveTask(TaskDTO taskDTO) { + var uuid = UUID.randomUUID(); + var task = new Task(uuid.toString(), taskDTO.name(), taskDTO.description()); + taskStore.put(uuid, task); + return task; + } + + @Override + public BugReport saveBugReport(BugReportDTO bugReportDTO) { + var uuid = UUID.randomUUID(); + var bugReport = new BugReport(uuid.toString(), bugReportDTO.name(), bugReportDTO.description()); + bugReportStore.put(uuid, bugReport); + return bugReport; + } + +} diff --git a/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java b/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java new file mode 100644 index 0000000..d87297b --- /dev/null +++ b/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java @@ -0,0 +1,12 @@ +package org.lab.repositories.TicketRepo; + +import org.lab.dto.BugReportDTO; +import org.lab.dto.TaskDTO; +import org.lab.model.BugReport.BugReport; +import org.lab.model.TaskModel.Task; + +public interface TicketRepo { + Task saveTask(TaskDTO taskDTO); + + BugReport saveBugReport(BugReportDTO bugReportDTO); +} diff --git a/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java b/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java new file mode 100644 index 0000000..c0453d0 --- /dev/null +++ b/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java @@ -0,0 +1,21 @@ +package org.lab.repositories.UserRepo; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.lab.dto.UserDTO; +import org.lab.model.UserModel.User; + +public class InMemoryUserRepo implements UserRepo { + private final Map store = new HashMap<>(); + + @Override + public User save(UserDTO userDTO) { + var uuid = UUID.randomUUID(); + var user = new User(uuid.toString(), userDTO.email(), userDTO.name()); + store.put(uuid, user); + return user; + } + +} diff --git a/src/main/java/org/lab/repositories/UserRepo/UserRepo.java b/src/main/java/org/lab/repositories/UserRepo/UserRepo.java new file mode 100644 index 0000000..f009859 --- /dev/null +++ b/src/main/java/org/lab/repositories/UserRepo/UserRepo.java @@ -0,0 +1,8 @@ +package org.lab.repositories.UserRepo; + +import org.lab.dto.UserDTO; +import org.lab.model.UserModel.User; + +public interface UserRepo { + User save(UserDTO userDTO); +} From 78db9891c526563659dab84bfbd12cb55585ee54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Mon, 22 Dec 2025 01:45:08 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/lab/model/ProjectModel/Project.java | 2 + .../ProjectRepo/InMemoryProjectRepo.java | 10 +++ .../repositories/ProjectRepo/ProjectRepo.java | 5 ++ .../TicketRepo/InMemoryTicketRepo.java | 12 ++++ .../repositories/TicketRepo/TicketRepo.java | 7 ++ .../UserRepo/InMemoryUserRepo.java | 8 +++ .../lab/repositories/UserRepo/UserRepo.java | 4 ++ .../java/org/lab/services/UserService.java | 68 +++++++++++++++++++ 8 files changed, 116 insertions(+) create mode 100644 src/main/java/org/lab/services/UserService.java diff --git a/src/main/java/org/lab/model/ProjectModel/Project.java b/src/main/java/org/lab/model/ProjectModel/Project.java index df1c8ac..a95edf8 100644 --- a/src/main/java/org/lab/model/ProjectModel/Project.java +++ b/src/main/java/org/lab/model/ProjectModel/Project.java @@ -25,6 +25,8 @@ public Project(String id, String name, ProjectMember manager) { this.manager = Objects.requireNonNull(manager); members = new HashSet<>(); + members.add(manager); + milestones = new HashSet<>(); bugReports = new HashSet<>(); } diff --git a/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java b/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java index d1f8b1c..bf64300 100644 --- a/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java +++ b/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java @@ -1,11 +1,13 @@ package org.lab.repositories.ProjectRepo; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import org.lab.dto.ProjectDTO; import org.lab.model.ProjectModel.Project; +import org.lab.model.UserModel.User; public class InMemoryProjectRepo implements ProjectRepo { private final Map store = new HashMap<>(); @@ -18,4 +20,12 @@ public Project save(ProjectDTO projectDTO) { return project; } + @Override + public List getUserProjects(User user) { + return store.values().stream() + .filter((project) -> project.getMembers().stream() + .anyMatch((projectMember) -> projectMember.user().equals(user))) + .toList(); + } + } diff --git a/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java b/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java index 5d651d0..104d1da 100644 --- a/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java +++ b/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java @@ -1,8 +1,13 @@ package org.lab.repositories.ProjectRepo; +import java.util.List; + import org.lab.dto.ProjectDTO; import org.lab.model.ProjectModel.Project; +import org.lab.model.UserModel.User; public interface ProjectRepo { Project save(ProjectDTO projectDTO); + + List getUserProjects(User user); } diff --git a/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java b/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java index 12e3827..27c1ddf 100644 --- a/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java +++ b/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java @@ -1,6 +1,7 @@ package org.lab.repositories.TicketRepo; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -8,6 +9,7 @@ import org.lab.dto.TaskDTO; import org.lab.model.BugReport.BugReport; import org.lab.model.TaskModel.Task; +import org.lab.model.UserModel.User; public class InMemoryTicketRepo implements TicketRepo { private final Map taskStore = new HashMap<>(); @@ -29,4 +31,14 @@ public BugReport saveBugReport(BugReportDTO bugReportDTO) { return bugReport; } + @Override + public List getUserTasks(User user) { + return taskStore.values().stream().filter((task) -> task.getAssignee().equals(user)).toList(); + } + + @Override + public List getUserBugReports(User user) { + return bugReportStore.values().stream().filter((task) -> task.getAssignee().equals(user)).toList(); + } + } diff --git a/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java b/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java index d87297b..031f808 100644 --- a/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java +++ b/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java @@ -1,12 +1,19 @@ package org.lab.repositories.TicketRepo; +import java.util.List; + import org.lab.dto.BugReportDTO; import org.lab.dto.TaskDTO; import org.lab.model.BugReport.BugReport; import org.lab.model.TaskModel.Task; +import org.lab.model.UserModel.User; public interface TicketRepo { Task saveTask(TaskDTO taskDTO); BugReport saveBugReport(BugReportDTO bugReportDTO); + + List getUserTasks(User user); + + List getUserBugReports(User user); } diff --git a/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java b/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java index c0453d0..ee359cb 100644 --- a/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java +++ b/src/main/java/org/lab/repositories/UserRepo/InMemoryUserRepo.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.UUID; import org.lab.dto.UserDTO; @@ -18,4 +19,11 @@ public User save(UserDTO userDTO) { return user; } + @Override + public Optional getUserById(String id) { + var uuid = UUID.fromString(id); + var user = Optional.ofNullable(store.get(uuid)); + return user; + } + } diff --git a/src/main/java/org/lab/repositories/UserRepo/UserRepo.java b/src/main/java/org/lab/repositories/UserRepo/UserRepo.java index f009859..ad9042d 100644 --- a/src/main/java/org/lab/repositories/UserRepo/UserRepo.java +++ b/src/main/java/org/lab/repositories/UserRepo/UserRepo.java @@ -1,8 +1,12 @@ package org.lab.repositories.UserRepo; +import java.util.Optional; + import org.lab.dto.UserDTO; import org.lab.model.UserModel.User; public interface UserRepo { User save(UserDTO userDTO); + + Optional getUserById(String id); } diff --git a/src/main/java/org/lab/services/UserService.java b/src/main/java/org/lab/services/UserService.java new file mode 100644 index 0000000..c01d634 --- /dev/null +++ b/src/main/java/org/lab/services/UserService.java @@ -0,0 +1,68 @@ +package org.lab.services; + +import java.util.List; + +import org.lab.dto.ProjectDTO; +import org.lab.dto.UserDTO; +import org.lab.model.BugReport.BugReport; +import org.lab.model.ProjectModel.Project; +import org.lab.model.ProjectModel.ProjectMember; +import org.lab.model.ProjectModel.ProjectRole; +import org.lab.model.TaskModel.Task; +import org.lab.model.UserModel.User; +import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.TicketRepo.TicketRepo; +import org.lab.repositories.UserRepo.UserRepo; + +public class UserService { + private final UserRepo userRepo; + private final ProjectRepo projectRepo; + private final TicketRepo ticketRepo; + + public UserService(UserRepo userRepo, ProjectRepo projectRepo, TicketRepo ticketRepo) { + this.userRepo = userRepo; + this.projectRepo = projectRepo; + this.ticketRepo = ticketRepo; + } + + public User registerUser(String name, String email) { + if (name == "") { + throw new IllegalArgumentException("user name cannot be empty"); + } + + if (email == "") { + throw new IllegalArgumentException("user email cannot be empty"); + } + + var userDTO = new UserDTO(email, name); + return userRepo.save(userDTO); + } + + public Project createProject(String name, String managerUserId) { + return userRepo.getUserById(managerUserId) + .map((user) -> { + var projectManager = new ProjectMember(user, ProjectRole.MANAGER); + var projectDTO = new ProjectDTO(name, projectManager); + return projectRepo.save(projectDTO); + }) + .orElseThrow(() -> new IllegalArgumentException("no such user " + managerUserId)); + } + + public List getUserProjects(String userId) { + return userRepo.getUserById(userId) + .map((user) -> projectRepo.getUserProjects(user)) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + } + + List getUserTasks(String userId) { + return userRepo.getUserById(userId) + .map((user) -> ticketRepo.getUserTasks(user)) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + } + + List getUserBugReports(String userId) { + return userRepo.getUserById(userId) + .map((user) -> ticketRepo.getUserBugReports(user)) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + } +} From 42c7421e2454067da7feac3c1eec3343a0b9f819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Mon, 22 Dec 2025 02:24:42 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=D0=BC=D0=B8?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BC=D0=B5=D0=BD=D0=B5=D0=B4=D0=B6?= =?UTF-8?q?=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectRepo/InMemoryProjectRepo.java | 10 ++- .../repositories/ProjectRepo/ProjectRepo.java | 3 + .../java/org/lab/services/ProjectService.java | 67 +++++++++++++++++++ .../java/org/lab/services/UserService.java | 13 ---- 4 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/lab/services/ProjectService.java diff --git a/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java b/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java index bf64300..66fb31f 100644 --- a/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java +++ b/src/main/java/org/lab/repositories/ProjectRepo/InMemoryProjectRepo.java @@ -3,6 +3,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; import org.lab.dto.ProjectDTO; @@ -20,6 +21,13 @@ public Project save(ProjectDTO projectDTO) { return project; } + @Override + public Optional getProjectById(String id) { + var uuid = UUID.fromString(id); + var project = Optional.ofNullable(store.get(uuid)); + return project; + } + @Override public List getUserProjects(User user) { return store.values().stream() @@ -27,5 +35,5 @@ public List getUserProjects(User user) { .anyMatch((projectMember) -> projectMember.user().equals(user))) .toList(); } - + } diff --git a/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java b/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java index 104d1da..7f76a8e 100644 --- a/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java +++ b/src/main/java/org/lab/repositories/ProjectRepo/ProjectRepo.java @@ -1,6 +1,7 @@ package org.lab.repositories.ProjectRepo; import java.util.List; +import java.util.Optional; import org.lab.dto.ProjectDTO; import org.lab.model.ProjectModel.Project; @@ -9,5 +10,7 @@ public interface ProjectRepo { Project save(ProjectDTO projectDTO); + Optional getProjectById(String id); + List getUserProjects(User user); } diff --git a/src/main/java/org/lab/services/ProjectService.java b/src/main/java/org/lab/services/ProjectService.java new file mode 100644 index 0000000..42d815e --- /dev/null +++ b/src/main/java/org/lab/services/ProjectService.java @@ -0,0 +1,67 @@ +package org.lab.services; + +import org.lab.dto.ProjectDTO; +import org.lab.model.ProjectModel.Project; +import org.lab.model.ProjectModel.ProjectMember; +import org.lab.model.ProjectModel.ProjectRole; +import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.UserRepo.UserRepo; + +public class ProjectService { + private final UserRepo userRepo; + private final ProjectRepo projectRepo; + + public ProjectService(UserRepo userRepo, ProjectRepo projectRepo) { + this.userRepo = userRepo; + this.projectRepo = projectRepo; + } + + private Project getProjectIfManager(String managerId, String projectId) { + var manager = userRepo.getUserById(managerId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + managerId)); + + var managerProject = projectRepo.getProjectById(projectId) + .map((project) -> project) + .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); + + if (!managerProject.getManager().equals(manager)) { + throw new IllegalArgumentException("user " + managerId + " is not manager of project " + projectId); + } + + return managerProject; + } + + public Project createProject(String name, String managerUserId) { + return userRepo.getUserById(managerUserId) + .map((user) -> { + var projectManager = new ProjectMember(user, ProjectRole.MANAGER); + var projectDTO = new ProjectDTO(name, projectManager); + return projectRepo.save(projectDTO); + }) + .orElseThrow(() -> new IllegalArgumentException("no such user " + managerUserId)); + } + + public Project updateLead(String managerId, String projectId, String leadId) { + var project = getProjectIfManager(managerId, projectId); + var leadUser = userRepo.getUserById(leadId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + leadId)); + + var projectLead = new ProjectMember(leadUser, ProjectRole.LEAD); + project.addMember(projectLead); + project.setLead(projectLead); + return project; + } + + public Project addMember(String managerId, String projectId, String memberId, ProjectRole role) { + var project = getProjectIfManager(managerId, projectId); + var memberUser = userRepo.getUserById(memberId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + memberId)); + + var projectLead = new ProjectMember(memberUser, role); + project.addMember(projectLead); + return project; + } +} diff --git a/src/main/java/org/lab/services/UserService.java b/src/main/java/org/lab/services/UserService.java index c01d634..85a7bae 100644 --- a/src/main/java/org/lab/services/UserService.java +++ b/src/main/java/org/lab/services/UserService.java @@ -2,12 +2,9 @@ import java.util.List; -import org.lab.dto.ProjectDTO; import org.lab.dto.UserDTO; import org.lab.model.BugReport.BugReport; import org.lab.model.ProjectModel.Project; -import org.lab.model.ProjectModel.ProjectMember; -import org.lab.model.ProjectModel.ProjectRole; import org.lab.model.TaskModel.Task; import org.lab.model.UserModel.User; import org.lab.repositories.ProjectRepo.ProjectRepo; @@ -38,16 +35,6 @@ public User registerUser(String name, String email) { return userRepo.save(userDTO); } - public Project createProject(String name, String managerUserId) { - return userRepo.getUserById(managerUserId) - .map((user) -> { - var projectManager = new ProjectMember(user, ProjectRole.MANAGER); - var projectDTO = new ProjectDTO(name, projectManager); - return projectRepo.save(projectDTO); - }) - .orElseThrow(() -> new IllegalArgumentException("no such user " + managerUserId)); - } - public List getUserProjects(String userId) { return userRepo.getUserById(userId) .map((user) -> projectRepo.getUserProjects(user)) From ad1ed96a4d1301295c5716b719b442e4123dbe0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Tue, 23 Dec 2025 18:59:43 +0300 Subject: [PATCH 06/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=20milestone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/lab/dto/MilestoneDTO.java | 4 +- .../lab/model/MilestoneModel/Milestone.java | 11 +++- .../MilestoneRepo/InMemoryMilestoneRepo.java | 11 +++- .../MilestoneRepo/MilestoneRepo.java | 4 ++ .../java/org/lab/services/AccessControl.java | 53 +++++++++++++++++++ .../org/lab/services/MilestoneService.java | 36 +++++++++++++ .../java/org/lab/services/ProjectService.java | 25 +++------ 7 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/lab/services/AccessControl.java create mode 100644 src/main/java/org/lab/services/MilestoneService.java diff --git a/src/main/java/org/lab/dto/MilestoneDTO.java b/src/main/java/org/lab/dto/MilestoneDTO.java index 4466c60..1ab6b73 100644 --- a/src/main/java/org/lab/dto/MilestoneDTO.java +++ b/src/main/java/org/lab/dto/MilestoneDTO.java @@ -2,5 +2,7 @@ import java.time.LocalDate; -public record MilestoneDTO(String name, LocalDate start, LocalDate end) { +import org.lab.model.ProjectModel.Project; + +public record MilestoneDTO(Project project, String name, LocalDate start, LocalDate end) { } \ No newline at end of file diff --git a/src/main/java/org/lab/model/MilestoneModel/Milestone.java b/src/main/java/org/lab/model/MilestoneModel/Milestone.java index c58d47b..5f50fee 100644 --- a/src/main/java/org/lab/model/MilestoneModel/Milestone.java +++ b/src/main/java/org/lab/model/MilestoneModel/Milestone.java @@ -6,10 +6,12 @@ import java.util.List; import java.util.Objects; +import org.lab.model.ProjectModel.Project; import org.lab.model.TaskModel.Task; public class Milestone { - private String id; + private final String id; + private final Project project; private String name; private LocalDate start; private LocalDate end; @@ -17,8 +19,9 @@ public class Milestone { private final List tasks; - public Milestone(String id, String name, LocalDate start, LocalDate end) { + public Milestone(String id, Project project, String name, LocalDate start, LocalDate end) { this.id = Objects.requireNonNull(id); + this.project = project; this.name = Objects.requireNonNull(name); this.start = Objects.requireNonNull(start); this.end = Objects.requireNonNull(end); @@ -30,6 +33,10 @@ public String getId() { return id; } + public Project getProject() { + return project; + } + public String getName() { return name; } diff --git a/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java b/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java index e8a3231..8877e11 100644 --- a/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java +++ b/src/main/java/org/lab/repositories/MilestoneRepo/InMemoryMilestoneRepo.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.UUID; import org.lab.dto.MilestoneDTO; @@ -13,9 +14,17 @@ public class InMemoryMilestoneRepo implements MilestoneRepo { @Override public Milestone save(MilestoneDTO milestoneDTO) { var uuid = UUID.randomUUID(); - var milestone = new Milestone(uuid.toString(), milestoneDTO.name(), milestoneDTO.start(), milestoneDTO.end()); + var milestone = new Milestone(uuid.toString(), milestoneDTO.project(), milestoneDTO.name(), + milestoneDTO.start(), milestoneDTO.end()); store.put(uuid, milestone); return milestone; } + @Override + public Optional getMilestoneById(String id) { + var uuid = UUID.fromString(id); + var milestone = Optional.ofNullable(store.get(uuid)); + return milestone; + } + } diff --git a/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java b/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java index ccfccc7..b46c9f2 100644 --- a/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java +++ b/src/main/java/org/lab/repositories/MilestoneRepo/MilestoneRepo.java @@ -1,8 +1,12 @@ package org.lab.repositories.MilestoneRepo; +import java.util.Optional; + import org.lab.dto.MilestoneDTO; import org.lab.model.MilestoneModel.Milestone; public interface MilestoneRepo { Milestone save(MilestoneDTO milestoneDTO); + + Optional getMilestoneById(String id); } diff --git a/src/main/java/org/lab/services/AccessControl.java b/src/main/java/org/lab/services/AccessControl.java new file mode 100644 index 0000000..b2209c9 --- /dev/null +++ b/src/main/java/org/lab/services/AccessControl.java @@ -0,0 +1,53 @@ +package org.lab.services; + +import org.lab.model.MilestoneModel.Milestone; +import org.lab.model.ProjectModel.Project; +import org.lab.repositories.MilestoneRepo.MilestoneRepo; +import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.UserRepo.UserRepo; + +public class AccessControl { + private final UserRepo userRepo; + private final ProjectRepo projectRepo; + private final MilestoneRepo milestoneRepo; + + public AccessControl(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo) { + this.userRepo = userRepo; + this.projectRepo = projectRepo; + this.milestoneRepo = milestoneRepo; + } + + public Project getProjectIfManager(String managerId, String projectId) { + var manager = userRepo.getUserById(managerId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + managerId)); + + var managerProject = projectRepo.getProjectById(projectId) + .map((project) -> project) + .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); + + if (!managerProject.getManager().equals(manager)) { + throw new IllegalArgumentException("user " + managerId + " is not manager of project " + projectId); + } + + return managerProject; + } + + public Milestone getMilestoneIfManager(String managerId, String milestoneId) { + var manager = userRepo.getUserById(managerId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + managerId)); + + var projectMilestone = milestoneRepo.getMilestoneById(milestoneId) + .map((milestone) -> milestone) + .orElseThrow(() -> new IllegalArgumentException("no such milestone " + milestoneId)); + + var project = projectMilestone.getProject(); + + if (!project.getManager().equals(manager)) { + throw new IllegalArgumentException("user " + managerId + " is not manager of project " + project.getId()); + } + + return projectMilestone; + } +} diff --git a/src/main/java/org/lab/services/MilestoneService.java b/src/main/java/org/lab/services/MilestoneService.java new file mode 100644 index 0000000..c3e3c31 --- /dev/null +++ b/src/main/java/org/lab/services/MilestoneService.java @@ -0,0 +1,36 @@ +package org.lab.services; + +import java.time.LocalDate; + +import org.lab.dto.MilestoneDTO; +import org.lab.model.MilestoneModel.Milestone; +import org.lab.model.MilestoneModel.MilestoneStatus; +import org.lab.repositories.MilestoneRepo.MilestoneRepo; +import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.UserRepo.UserRepo; + +public class MilestoneService { + private final MilestoneRepo milestoneRepo; + + private final AccessControl accessControl; + + public MilestoneService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo) { + this.milestoneRepo = milestoneRepo; + + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo); + } + + public Milestone createMilestone(String managerId, String projectId, String name, LocalDate start, LocalDate end) { + var project = accessControl.getProjectIfManager(managerId, projectId); + var milestoneDTO = new MilestoneDTO(project, name, start, end); + var milestone = milestoneRepo.save(milestoneDTO); + project.addMilestone(milestone); + return milestone; + } + + public Milestone updateMilestoneStatus(String managerId, String milestoneId, MilestoneStatus status) { + var milestone = accessControl.getMilestoneIfManager(managerId, milestoneId); + milestone.setStatus(status); + return milestone; + } +} diff --git a/src/main/java/org/lab/services/ProjectService.java b/src/main/java/org/lab/services/ProjectService.java index 42d815e..9a44f2f 100644 --- a/src/main/java/org/lab/services/ProjectService.java +++ b/src/main/java/org/lab/services/ProjectService.java @@ -4,6 +4,7 @@ import org.lab.model.ProjectModel.Project; import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.ProjectModel.ProjectRole; +import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; import org.lab.repositories.UserRepo.UserRepo; @@ -11,25 +12,13 @@ public class ProjectService { private final UserRepo userRepo; private final ProjectRepo projectRepo; - public ProjectService(UserRepo userRepo, ProjectRepo projectRepo) { + private final AccessControl accessControl; + + public ProjectService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo) { this.userRepo = userRepo; this.projectRepo = projectRepo; - } - - private Project getProjectIfManager(String managerId, String projectId) { - var manager = userRepo.getUserById(managerId) - .map((user) -> user) - .orElseThrow(() -> new IllegalArgumentException("no such user " + managerId)); - - var managerProject = projectRepo.getProjectById(projectId) - .map((project) -> project) - .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); - - if (!managerProject.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + managerId + " is not manager of project " + projectId); - } - return managerProject; + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo); } public Project createProject(String name, String managerUserId) { @@ -43,7 +32,7 @@ public Project createProject(String name, String managerUserId) { } public Project updateLead(String managerId, String projectId, String leadId) { - var project = getProjectIfManager(managerId, projectId); + var project = accessControl.getProjectIfManager(managerId, projectId); var leadUser = userRepo.getUserById(leadId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + leadId)); @@ -55,7 +44,7 @@ public Project updateLead(String managerId, String projectId, String leadId) { } public Project addMember(String managerId, String projectId, String memberId, ProjectRole role) { - var project = getProjectIfManager(managerId, projectId); + var project = accessControl.getProjectIfManager(managerId, projectId); var memberUser = userRepo.getUserById(memberId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + memberId)); From 7ee18e55791f66c7d3da5a33ee57461f2e1f1208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Tue, 23 Dec 2025 20:37:23 +0300 Subject: [PATCH 07/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20TaskService,=20=D1=80=D0=B0=D0=B7=D0=BD=D0=B5=D1=81=20?= =?UTF-8?q?TicketRepo=20=D0=BD=D0=B0=20TaskRepo=20=D0=B8=20BugReportRepo,?= =?UTF-8?q?=20=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BD=D0=B5=D0=B1=D0=B5?= =?UTF-8?q?=D0=B7=D0=BE=D0=BF=D0=B0=D1=81=D0=BD=D1=8B=D0=B5=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=B7=D0=B2=D1=80=D0=B0=D1=82=D1=8B=20=D0=B8=D0=B7=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/lab/dto/TaskDTO.java | 4 +- .../org/lab/model/ProjectModel/Project.java | 11 +++- .../java/org/lab/model/TaskModel/Task.java | 18 ++++- .../org/lab/model/TicketModel/Ticket.java | 2 +- .../BugReportRepo.java} | 15 ++--- .../BugReportRepo/InMemoryBugReportRepo.java | 36 ++++++++++ .../TaskRepo/InMemoryTaskRepo.java | 35 ++++++++++ .../lab/repositories/TaskRepo/TaskRepo.java | 16 +++++ .../TicketRepo/InMemoryTicketRepo.java | 44 ------------- .../java/org/lab/services/AccessControl.java | 66 ++++++++++++++++--- .../org/lab/services/MilestoneService.java | 18 ++--- .../java/org/lab/services/ProjectService.java | 20 +++--- .../java/org/lab/services/TaskService.java | 59 +++++++++++++++++ .../java/org/lab/services/UserService.java | 18 ++--- 14 files changed, 268 insertions(+), 94 deletions(-) rename src/main/java/org/lab/repositories/{TicketRepo/TicketRepo.java => BugReportRepo/BugReportRepo.java} (53%) create mode 100644 src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java create mode 100644 src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java create mode 100644 src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java delete mode 100644 src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java create mode 100644 src/main/java/org/lab/services/TaskService.java diff --git a/src/main/java/org/lab/dto/TaskDTO.java b/src/main/java/org/lab/dto/TaskDTO.java index e1cad7d..8cb7037 100644 --- a/src/main/java/org/lab/dto/TaskDTO.java +++ b/src/main/java/org/lab/dto/TaskDTO.java @@ -1,4 +1,6 @@ package org.lab.dto; -public record TaskDTO(String name, String description) { +import org.lab.model.MilestoneModel.Milestone; + +public record TaskDTO(Milestone milestone, String name, String description) { } diff --git a/src/main/java/org/lab/model/ProjectModel/Project.java b/src/main/java/org/lab/model/ProjectModel/Project.java index a95edf8..602d85b 100644 --- a/src/main/java/org/lab/model/ProjectModel/Project.java +++ b/src/main/java/org/lab/model/ProjectModel/Project.java @@ -31,7 +31,7 @@ public Project(String id, String name, ProjectMember manager) { bugReports = new HashSet<>(); } - public String getId() { + public String getId() { return id; } @@ -96,6 +96,15 @@ public void setActiveMilestone(Milestone activeMilestone) { } public void addMilestone(Milestone milestone) { + if (!milestone.getProject().getId().equals(id)) { + String message = new StringBuilder() + .append("cannot add ").append(milestone.getId()).append(" to project ").append(id).append((". ")) + .append(milestone.getId()).append(" already in project ").append(milestone.getProject().getId()) + .toString(); + + throw new IllegalArgumentException(message); + } + milestones.add(milestone); } diff --git a/src/main/java/org/lab/model/TaskModel/Task.java b/src/main/java/org/lab/model/TaskModel/Task.java index f1e0622..97a5115 100644 --- a/src/main/java/org/lab/model/TaskModel/Task.java +++ b/src/main/java/org/lab/model/TaskModel/Task.java @@ -1,11 +1,27 @@ package org.lab.model.TaskModel; +import org.lab.model.MilestoneModel.Milestone; +import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.TicketModel.Ticket; public final class Task extends Ticket { + private final Milestone milestone; - public Task(String id, String name, String description) { + public Task(String id, Milestone milestone, String name, String description) { super(id, name, description, TaskStatus.OPENED); + + this.milestone = milestone; + } + + public Milestone getMilestone() { + return milestone; } + public void addDev(ProjectMember dev) { + addToTicker(TaskRole.DEV, dev); + } + + public void addTester(ProjectMember tester) { + addToTicker(TaskRole.TESTER, tester); + } } diff --git a/src/main/java/org/lab/model/TicketModel/Ticket.java b/src/main/java/org/lab/model/TicketModel/Ticket.java index b8cd69a..577268a 100644 --- a/src/main/java/org/lab/model/TicketModel/Ticket.java +++ b/src/main/java/org/lab/model/TicketModel/Ticket.java @@ -47,7 +47,7 @@ public void setDescription(String description) { this.description = Objects.requireNonNull(description); } - public void addToTicker(TRole role, ProjectMember member) { + protected void addToTicker(TRole role, ProjectMember member) { members.putIfAbsent(role, new ArrayList<>()); members.get(role).add(member); } diff --git a/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java b/src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java similarity index 53% rename from src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java rename to src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java index 031f808..f6fd36d 100644 --- a/src/main/java/org/lab/repositories/TicketRepo/TicketRepo.java +++ b/src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java @@ -1,19 +1,16 @@ -package org.lab.repositories.TicketRepo; +package org.lab.repositories.BugReportRepo; import java.util.List; +import java.util.Optional; import org.lab.dto.BugReportDTO; -import org.lab.dto.TaskDTO; import org.lab.model.BugReport.BugReport; -import org.lab.model.TaskModel.Task; import org.lab.model.UserModel.User; -public interface TicketRepo { - Task saveTask(TaskDTO taskDTO); - +public interface BugReportRepo { BugReport saveBugReport(BugReportDTO bugReportDTO); - List getUserTasks(User user); - List getUserBugReports(User user); -} + + Optional getBugReportById(String id); +} \ No newline at end of file diff --git a/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java b/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java new file mode 100644 index 0000000..0f2d973 --- /dev/null +++ b/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java @@ -0,0 +1,36 @@ +package org.lab.repositories.BugReportRepo; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.lab.dto.BugReportDTO; +import org.lab.model.BugReport.BugReport; +import org.lab.model.UserModel.User; + +public class InMemoryBugReportRepo implements BugReportRepo { + private final Map store = new HashMap<>(); + + @Override + public BugReport saveBugReport(BugReportDTO bugReportDTO) { + var uuid = UUID.randomUUID(); + var bugReport = new BugReport(uuid.toString(), bugReportDTO.name(), bugReportDTO.description()); + store.put(uuid, bugReport); + return bugReport; + } + + @Override + public List getUserBugReports(User user) { + return store.values().stream().filter((bugReport) -> bugReport.getAssignee().equals(user)).toList(); + } + + @Override + public Optional getBugReportById(String id) { + var uuid = UUID.fromString(id); + var bugReport = Optional.ofNullable(store.get(uuid)); + return bugReport; + } + +} diff --git a/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java b/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java new file mode 100644 index 0000000..e116e18 --- /dev/null +++ b/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java @@ -0,0 +1,35 @@ +package org.lab.repositories.TaskRepo; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import org.lab.dto.TaskDTO; +import org.lab.model.TaskModel.Task; +import org.lab.model.UserModel.User; + +public class InMemoryTaskRepo implements TaskRepo { + private final Map store = new HashMap<>(); + + @Override + public Task saveTask(TaskDTO taskDTO) { + var uuid = UUID.randomUUID(); + var task = new Task(uuid.toString(), taskDTO.milestone(), taskDTO.name(), taskDTO.description()); + store.put(uuid, task); + return task; + } + + @Override + public List getUserTasks(User user) { + return store.values().stream().filter((task) -> task.getAssignee().equals(user)).toList(); + } + + @Override + public Optional getTaskById(String id) { + var uuid = UUID.fromString(id); + var task = Optional.ofNullable(store.get(uuid)); + return task; + } +} diff --git a/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java b/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java new file mode 100644 index 0000000..a499cf2 --- /dev/null +++ b/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java @@ -0,0 +1,16 @@ +package org.lab.repositories.TaskRepo; + +import java.util.List; +import java.util.Optional; + +import org.lab.dto.TaskDTO; +import org.lab.model.TaskModel.Task; +import org.lab.model.UserModel.User; + +public interface TaskRepo { + Task saveTask(TaskDTO taskDTO); + + List getUserTasks(User user); + + Optional getTaskById(String id); +} diff --git a/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java b/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java deleted file mode 100644 index 27c1ddf..0000000 --- a/src/main/java/org/lab/repositories/TicketRepo/InMemoryTicketRepo.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.lab.repositories.TicketRepo; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.lab.dto.BugReportDTO; -import org.lab.dto.TaskDTO; -import org.lab.model.BugReport.BugReport; -import org.lab.model.TaskModel.Task; -import org.lab.model.UserModel.User; - -public class InMemoryTicketRepo implements TicketRepo { - private final Map taskStore = new HashMap<>(); - private final Map bugReportStore = new HashMap<>(); - - @Override - public Task saveTask(TaskDTO taskDTO) { - var uuid = UUID.randomUUID(); - var task = new Task(uuid.toString(), taskDTO.name(), taskDTO.description()); - taskStore.put(uuid, task); - return task; - } - - @Override - public BugReport saveBugReport(BugReportDTO bugReportDTO) { - var uuid = UUID.randomUUID(); - var bugReport = new BugReport(uuid.toString(), bugReportDTO.name(), bugReportDTO.description()); - bugReportStore.put(uuid, bugReport); - return bugReport; - } - - @Override - public List getUserTasks(User user) { - return taskStore.values().stream().filter((task) -> task.getAssignee().equals(user)).toList(); - } - - @Override - public List getUserBugReports(User user) { - return bugReportStore.values().stream().filter((task) -> task.getAssignee().equals(user)).toList(); - } - -} diff --git a/src/main/java/org/lab/services/AccessControl.java b/src/main/java/org/lab/services/AccessControl.java index b2209c9..694da8b 100644 --- a/src/main/java/org/lab/services/AccessControl.java +++ b/src/main/java/org/lab/services/AccessControl.java @@ -2,41 +2,46 @@ import org.lab.model.MilestoneModel.Milestone; import org.lab.model.ProjectModel.Project; +import org.lab.model.ProjectModel.ProjectRole; +import org.lab.model.TaskModel.Task; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.TaskRepo.TaskRepo; import org.lab.repositories.UserRepo.UserRepo; public class AccessControl { private final UserRepo userRepo; private final ProjectRepo projectRepo; private final MilestoneRepo milestoneRepo; + private final TaskRepo taskRepo; - public AccessControl(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo) { + public AccessControl(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, TaskRepo taskRepo) { this.userRepo = userRepo; this.projectRepo = projectRepo; this.milestoneRepo = milestoneRepo; + this.taskRepo = taskRepo; } - public Project getProjectIfManager(String managerId, String projectId) { - var manager = userRepo.getUserById(managerId) + public Project getProjectIfHasAccess(String userId, String projectId) { + var manager = userRepo.getUserById(userId) .map((user) -> user) - .orElseThrow(() -> new IllegalArgumentException("no such user " + managerId)); + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); var managerProject = projectRepo.getProjectById(projectId) .map((project) -> project) .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); if (!managerProject.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + managerId + " is not manager of project " + projectId); + throw new IllegalArgumentException("user " + userId + " is not manager of project " + projectId); } return managerProject; } - public Milestone getMilestoneIfManager(String managerId, String milestoneId) { - var manager = userRepo.getUserById(managerId) + public Milestone getMilestoneIfHasAccess(String userId, String milestoneId) { + var manager = userRepo.getUserById(userId) .map((user) -> user) - .orElseThrow(() -> new IllegalArgumentException("no such user " + managerId)); + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); var projectMilestone = milestoneRepo.getMilestoneById(milestoneId) .map((milestone) -> milestone) @@ -45,9 +50,52 @@ public Milestone getMilestoneIfManager(String managerId, String milestoneId) { var project = projectMilestone.getProject(); if (!project.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + managerId + " is not manager of project " + project.getId()); + throw new IllegalArgumentException("user " + userId + " is not manager of project " + project.getId()); } return projectMilestone; } + + public Task getTaskForMembersUpdateIfHasAccess(String userId, String taskId) { + var updater = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var task = taskRepo.getTaskById(taskId).map((t) -> t) + .orElseThrow(() -> new IllegalArgumentException("no such task " + taskId)); + + var project = task.getMilestone().getProject(); + + if (!project.getManager().equals(updater) && !project.getLead().equals(updater)) { + throw new IllegalArgumentException( + "user " + userId + " is not manager or lead of project " + project.getId()); + } + + return task; + } + + public Task getTaskForStatusUpdateIfHasAccess(String userId, String taskId) { + var updater = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var task = taskRepo.getTaskById(taskId).map((t) -> t) + .orElseThrow(() -> new IllegalArgumentException("no such task " + taskId)); + + var project = task.getMilestone().getProject(); + + var updaterProjectMember = project.getMembers().stream() + .filter((projectMember) -> projectMember.user().equals(updater)).findFirst() + .map((projectMember) -> projectMember) + .orElseThrow( + () -> new IllegalArgumentException( + "no such user " + updater + " in project " + project.getId())); + + if (updaterProjectMember.role() != ProjectRole.DEV && updaterProjectMember.role() != ProjectRole.LEAD) { + throw new IllegalArgumentException( + "user " + userId + " is not dev of project " + project.getId()); + } + + return task; + } } diff --git a/src/main/java/org/lab/services/MilestoneService.java b/src/main/java/org/lab/services/MilestoneService.java index c3e3c31..5a54c94 100644 --- a/src/main/java/org/lab/services/MilestoneService.java +++ b/src/main/java/org/lab/services/MilestoneService.java @@ -3,10 +3,10 @@ import java.time.LocalDate; import org.lab.dto.MilestoneDTO; -import org.lab.model.MilestoneModel.Milestone; import org.lab.model.MilestoneModel.MilestoneStatus; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.TaskRepo.TaskRepo; import org.lab.repositories.UserRepo.UserRepo; public class MilestoneService { @@ -14,23 +14,23 @@ public class MilestoneService { private final AccessControl accessControl; - public MilestoneService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo) { + public MilestoneService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, + TaskRepo taskRepo) { this.milestoneRepo = milestoneRepo; - this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo); + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo); } - public Milestone createMilestone(String managerId, String projectId, String name, LocalDate start, LocalDate end) { - var project = accessControl.getProjectIfManager(managerId, projectId); + public String createMilestone(String managerId, String projectId, String name, LocalDate start, LocalDate end) { + var project = accessControl.getProjectIfHasAccess(managerId, projectId); var milestoneDTO = new MilestoneDTO(project, name, start, end); var milestone = milestoneRepo.save(milestoneDTO); project.addMilestone(milestone); - return milestone; + return milestone.getId(); } - public Milestone updateMilestoneStatus(String managerId, String milestoneId, MilestoneStatus status) { - var milestone = accessControl.getMilestoneIfManager(managerId, milestoneId); + public void updateMilestoneStatus(String managerId, String milestoneId, MilestoneStatus status) { + var milestone = accessControl.getMilestoneIfHasAccess(managerId, milestoneId); milestone.setStatus(status); - return milestone; } } diff --git a/src/main/java/org/lab/services/ProjectService.java b/src/main/java/org/lab/services/ProjectService.java index 9a44f2f..14fab7e 100644 --- a/src/main/java/org/lab/services/ProjectService.java +++ b/src/main/java/org/lab/services/ProjectService.java @@ -1,11 +1,11 @@ package org.lab.services; import org.lab.dto.ProjectDTO; -import org.lab.model.ProjectModel.Project; import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.ProjectModel.ProjectRole; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.TaskRepo.TaskRepo; import org.lab.repositories.UserRepo.UserRepo; public class ProjectService { @@ -14,25 +14,25 @@ public class ProjectService { private final AccessControl accessControl; - public ProjectService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo) { + public ProjectService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, TaskRepo taskRepo) { this.userRepo = userRepo; this.projectRepo = projectRepo; - this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo); + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo); } - public Project createProject(String name, String managerUserId) { + public String createProject(String name, String managerUserId) { return userRepo.getUserById(managerUserId) .map((user) -> { var projectManager = new ProjectMember(user, ProjectRole.MANAGER); var projectDTO = new ProjectDTO(name, projectManager); - return projectRepo.save(projectDTO); + return projectRepo.save(projectDTO).getId(); }) .orElseThrow(() -> new IllegalArgumentException("no such user " + managerUserId)); } - public Project updateLead(String managerId, String projectId, String leadId) { - var project = accessControl.getProjectIfManager(managerId, projectId); + public void updateLead(String managerId, String projectId, String leadId) { + var project = accessControl.getProjectIfHasAccess(managerId, projectId); var leadUser = userRepo.getUserById(leadId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + leadId)); @@ -40,17 +40,15 @@ public Project updateLead(String managerId, String projectId, String leadId) { var projectLead = new ProjectMember(leadUser, ProjectRole.LEAD); project.addMember(projectLead); project.setLead(projectLead); - return project; } - public Project addMember(String managerId, String projectId, String memberId, ProjectRole role) { - var project = accessControl.getProjectIfManager(managerId, projectId); + public void addMember(String managerId, String projectId, String memberId, ProjectRole role) { + var project = accessControl.getProjectIfHasAccess(managerId, projectId); var memberUser = userRepo.getUserById(memberId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + memberId)); var projectLead = new ProjectMember(memberUser, role); project.addMember(projectLead); - return project; } } diff --git a/src/main/java/org/lab/services/TaskService.java b/src/main/java/org/lab/services/TaskService.java new file mode 100644 index 0000000..2e294f5 --- /dev/null +++ b/src/main/java/org/lab/services/TaskService.java @@ -0,0 +1,59 @@ +package org.lab.services; + +import org.lab.dto.TaskDTO; +import org.lab.model.TaskModel.TaskStatus; +import org.lab.repositories.MilestoneRepo.MilestoneRepo; +import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.TaskRepo.TaskRepo; +import org.lab.repositories.UserRepo.UserRepo; + +public class TaskService { + private final UserRepo userRepo; + private final TaskRepo taskRepo; + + private final AccessControl accessControl; + + public TaskService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, + TaskRepo taskRepo) { + this.userRepo = userRepo; + this.taskRepo = taskRepo; + + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo); + } + + public String createTask(String creatorId, String milestoneId, String name, String description) { + var milestone = accessControl.getMilestoneIfHasAccess(creatorId, milestoneId); + var taskDTO = new TaskDTO(milestone, name, description); + var task = taskRepo.saveTask(taskDTO); + milestone.addTask(task); + return task.getId(); + } + + public void addDevToTask(String updaterId, String taskId, String devId) { + var devUser = userRepo.getUserById(devId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + devId)); + + var task = accessControl.getTaskForMembersUpdateIfHasAccess(updaterId, taskId); + var project = task.getMilestone().getProject(); + + var devProjectMember = project.getMembers().stream() + .filter((projectMember) -> projectMember.user().equals(devUser)).findFirst() + .map((projectMember) -> projectMember) + .orElseThrow( + () -> new IllegalArgumentException("no such user " + devId + " in project " + project.getId())); + + task.addDev(devProjectMember); + } + + public TaskStatus getTaskStatus(String taskId) { + return taskRepo.getTaskById(taskId) + .map((task) -> task.getStatus()) + .orElseThrow(() -> new IllegalArgumentException("no such task " + taskId)); + } + + public void updateTaskStatus(String updaterId, String taskId, TaskStatus status) { + var task = accessControl.getTaskForStatusUpdateIfHasAccess(updaterId, taskId); + task.setStatus(status); + } +} diff --git a/src/main/java/org/lab/services/UserService.java b/src/main/java/org/lab/services/UserService.java index 85a7bae..80ad580 100644 --- a/src/main/java/org/lab/services/UserService.java +++ b/src/main/java/org/lab/services/UserService.java @@ -6,23 +6,25 @@ import org.lab.model.BugReport.BugReport; import org.lab.model.ProjectModel.Project; import org.lab.model.TaskModel.Task; -import org.lab.model.UserModel.User; +import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; -import org.lab.repositories.TicketRepo.TicketRepo; +import org.lab.repositories.TaskRepo.TaskRepo; import org.lab.repositories.UserRepo.UserRepo; public class UserService { private final UserRepo userRepo; private final ProjectRepo projectRepo; - private final TicketRepo ticketRepo; + private final TaskRepo ticketRepo; + private final BugReportRepo bugReportRepo; - public UserService(UserRepo userRepo, ProjectRepo projectRepo, TicketRepo ticketRepo) { + public UserService(UserRepo userRepo, ProjectRepo projectRepo, TaskRepo taskRepo, BugReportRepo bugReportRepo) { this.userRepo = userRepo; this.projectRepo = projectRepo; - this.ticketRepo = ticketRepo; + this.ticketRepo = taskRepo; + this.bugReportRepo = bugReportRepo; } - public User registerUser(String name, String email) { + public String registerUser(String name, String email) { if (name == "") { throw new IllegalArgumentException("user name cannot be empty"); } @@ -32,7 +34,7 @@ public User registerUser(String name, String email) { } var userDTO = new UserDTO(email, name); - return userRepo.save(userDTO); + return userRepo.save(userDTO).id(); } public List getUserProjects(String userId) { @@ -49,7 +51,7 @@ List getUserTasks(String userId) { List getUserBugReports(String userId) { return userRepo.getUserById(userId) - .map((user) -> ticketRepo.getUserBugReports(user)) + .map((user) -> bugReportRepo.getUserBugReports(user)) .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); } } From d35e39d1e215602344f8063f9736f6b6ed1172f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Tue, 23 Dec 2025 21:14:22 +0300 Subject: [PATCH 08/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20BugReportService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/lab/dto/BugReportDTO.java | 4 +- .../org/lab/model/BugReport/BugReport.java | 14 ++- .../BugReportRepo/BugReportRepo.java | 2 +- .../BugReportRepo/InMemoryBugReportRepo.java | 5 +- .../TaskRepo/InMemoryTaskRepo.java | 2 +- .../lab/repositories/TaskRepo/TaskRepo.java | 2 +- .../java/org/lab/services/AccessControl.java | 107 +++++++++++++++++- .../org/lab/services/BugReportService.java | 61 ++++++++++ .../org/lab/services/MilestoneService.java | 7 +- .../java/org/lab/services/ProjectService.java | 10 +- .../java/org/lab/services/TaskService.java | 7 +- 11 files changed, 202 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/lab/services/BugReportService.java diff --git a/src/main/java/org/lab/dto/BugReportDTO.java b/src/main/java/org/lab/dto/BugReportDTO.java index a9bc67a..0ef68f1 100644 --- a/src/main/java/org/lab/dto/BugReportDTO.java +++ b/src/main/java/org/lab/dto/BugReportDTO.java @@ -1,4 +1,6 @@ package org.lab.dto; -public record BugReportDTO(String name, String description) { +import org.lab.model.ProjectModel.Project; + +public record BugReportDTO(Project project, String name, String description) { } diff --git a/src/main/java/org/lab/model/BugReport/BugReport.java b/src/main/java/org/lab/model/BugReport/BugReport.java index 790167c..43e40f4 100644 --- a/src/main/java/org/lab/model/BugReport/BugReport.java +++ b/src/main/java/org/lab/model/BugReport/BugReport.java @@ -1,11 +1,23 @@ package org.lab.model.BugReport; +import org.lab.model.ProjectModel.Project; +import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.TicketModel.Ticket; public final class BugReport extends Ticket { + private final Project project; - public BugReport(String id, String name, String description) { + public BugReport(String id, Project project, String name, String description) { super(id, name, description, BugReportStatus.OPEN); + + this.project = project; + } + + public Project getProject() { + return project; } + public void addTester(ProjectMember testerProjectMember) { + addToTicker(BugReportRole.TESTER, testerProjectMember); + } } diff --git a/src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java b/src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java index f6fd36d..5c23ef6 100644 --- a/src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java +++ b/src/main/java/org/lab/repositories/BugReportRepo/BugReportRepo.java @@ -8,7 +8,7 @@ import org.lab.model.UserModel.User; public interface BugReportRepo { - BugReport saveBugReport(BugReportDTO bugReportDTO); + BugReport save(BugReportDTO bugReportDTO); List getUserBugReports(User user); diff --git a/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java b/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java index 0f2d973..03a963e 100644 --- a/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java +++ b/src/main/java/org/lab/repositories/BugReportRepo/InMemoryBugReportRepo.java @@ -14,9 +14,10 @@ public class InMemoryBugReportRepo implements BugReportRepo { private final Map store = new HashMap<>(); @Override - public BugReport saveBugReport(BugReportDTO bugReportDTO) { + public BugReport save(BugReportDTO bugReportDTO) { var uuid = UUID.randomUUID(); - var bugReport = new BugReport(uuid.toString(), bugReportDTO.name(), bugReportDTO.description()); + var bugReport = new BugReport(uuid.toString(), bugReportDTO.project(), bugReportDTO.name(), + bugReportDTO.description()); store.put(uuid, bugReport); return bugReport; } diff --git a/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java b/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java index e116e18..7aac97c 100644 --- a/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java +++ b/src/main/java/org/lab/repositories/TaskRepo/InMemoryTaskRepo.java @@ -14,7 +14,7 @@ public class InMemoryTaskRepo implements TaskRepo { private final Map store = new HashMap<>(); @Override - public Task saveTask(TaskDTO taskDTO) { + public Task save(TaskDTO taskDTO) { var uuid = UUID.randomUUID(); var task = new Task(uuid.toString(), taskDTO.milestone(), taskDTO.name(), taskDTO.description()); store.put(uuid, task); diff --git a/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java b/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java index a499cf2..dad8a2f 100644 --- a/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java +++ b/src/main/java/org/lab/repositories/TaskRepo/TaskRepo.java @@ -8,7 +8,7 @@ import org.lab.model.UserModel.User; public interface TaskRepo { - Task saveTask(TaskDTO taskDTO); + Task save(TaskDTO taskDTO); List getUserTasks(User user); diff --git a/src/main/java/org/lab/services/AccessControl.java b/src/main/java/org/lab/services/AccessControl.java index 694da8b..79f91c1 100644 --- a/src/main/java/org/lab/services/AccessControl.java +++ b/src/main/java/org/lab/services/AccessControl.java @@ -1,9 +1,11 @@ package org.lab.services; +import org.lab.model.BugReport.BugReport; import org.lab.model.MilestoneModel.Milestone; import org.lab.model.ProjectModel.Project; import org.lab.model.ProjectModel.ProjectRole; import org.lab.model.TaskModel.Task; +import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; import org.lab.repositories.TaskRepo.TaskRepo; @@ -14,15 +16,73 @@ public class AccessControl { private final ProjectRepo projectRepo; private final MilestoneRepo milestoneRepo; private final TaskRepo taskRepo; + private final BugReportRepo bugReportRepo; - public AccessControl(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, TaskRepo taskRepo) { + public AccessControl(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, TaskRepo taskRepo, + BugReportRepo bugReportRepo) { this.userRepo = userRepo; this.projectRepo = projectRepo; this.milestoneRepo = milestoneRepo; this.taskRepo = taskRepo; + this.bugReportRepo = bugReportRepo; } - public Project getProjectIfHasAccess(String userId, String projectId) { + public Project getProjectForAddBugReportIfHasAccess(String userId, String projectId) { + var tester = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var projectToReport = projectRepo.getProjectById(projectId) + .map((project) -> project) + .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); + + var testerProjectMember = projectToReport.getMembers().stream() + .filter((projectMember) -> projectMember.user().equals(tester)).findFirst() + .map((projectMember) -> projectMember) + .orElseThrow( + () -> new IllegalArgumentException( + "no such user " + tester + " in project " + projectToReport.getId())); + + if (testerProjectMember.role() != ProjectRole.TESTER && testerProjectMember.role() != ProjectRole.DEV) { + throw new IllegalArgumentException("user " + userId + " is not tester or dev of project " + projectId); + } + + return projectToReport; + } + + public Project getProjectForUpdateLeadIfHasAccess(String userId, String projectId) { + var manager = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var managerProject = projectRepo.getProjectById(projectId) + .map((project) -> project) + .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); + + if (!managerProject.getManager().equals(manager)) { + throw new IllegalArgumentException("user " + userId + " is not manager of project " + projectId); + } + + return managerProject; + } + + public Project getProjectForAddMemberIfHasAccess(String userId, String projectId) { + var manager = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var managerProject = projectRepo.getProjectById(projectId) + .map((project) -> project) + .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); + + if (!managerProject.getManager().equals(manager)) { + throw new IllegalArgumentException("user " + userId + " is not manager of project " + projectId); + } + + return managerProject; + } + + public Project getProjectForCreateMilestoneIfHasAccess(String userId, String projectId) { var manager = userRepo.getUserById(userId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); @@ -74,6 +134,24 @@ public Task getTaskForMembersUpdateIfHasAccess(String userId, String taskId) { return task; } + public BugReport getBugReportForMembersUpdateIfHasAccess(String userId, String bugReportId) { + var updater = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var bugReport = bugReportRepo.getBugReportById(bugReportId).map((r) -> r) + .orElseThrow(() -> new IllegalArgumentException("no such task " + bugReportId)); + + var project = bugReport.getProject(); + + if (!project.getManager().equals(updater) && !project.getLead().equals(updater)) { + throw new IllegalArgumentException( + "user " + userId + " is not manager or lead of project " + project.getId()); + } + + return bugReport; + } + public Task getTaskForStatusUpdateIfHasAccess(String userId, String taskId) { var updater = userRepo.getUserById(userId) .map((user) -> user) @@ -98,4 +176,29 @@ public Task getTaskForStatusUpdateIfHasAccess(String userId, String taskId) { return task; } + + public BugReport getBugReportForStatusUpdateIfHasAccess(String userId, String bugReportId) { + var updater = userRepo.getUserById(userId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + userId)); + + var bugReport = bugReportRepo.getBugReportById(bugReportId).map((t) -> t) + .orElseThrow(() -> new IllegalArgumentException("no such bug report " + bugReportId)); + + var project = bugReport.getProject(); + + var updaterProjectMember = project.getMembers().stream() + .filter((projectMember) -> projectMember.user().equals(updater)).findFirst() + .map((projectMember) -> projectMember) + .orElseThrow( + () -> new IllegalArgumentException( + "no such user " + updater + " in project " + project.getId())); + + if (updaterProjectMember.role() != ProjectRole.DEV && updaterProjectMember.role() != ProjectRole.TESTER) { + throw new IllegalArgumentException( + "user " + userId + " is not dev or tester of project " + project.getId()); + } + + return bugReport; + } } diff --git a/src/main/java/org/lab/services/BugReportService.java b/src/main/java/org/lab/services/BugReportService.java new file mode 100644 index 0000000..ab80df0 --- /dev/null +++ b/src/main/java/org/lab/services/BugReportService.java @@ -0,0 +1,61 @@ +package org.lab.services; + +import org.lab.dto.BugReportDTO; +import org.lab.model.BugReport.BugReportStatus; +import org.lab.model.TaskModel.TaskStatus; +import org.lab.repositories.BugReportRepo.BugReportRepo; +import org.lab.repositories.MilestoneRepo.MilestoneRepo; +import org.lab.repositories.ProjectRepo.ProjectRepo; +import org.lab.repositories.TaskRepo.TaskRepo; +import org.lab.repositories.UserRepo.UserRepo; + +public class BugReportService { + private final UserRepo userRepo; + private final BugReportRepo bugReportRepo; + + private final AccessControl accessControl; + + public BugReportService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, + TaskRepo taskRepo, BugReportRepo bugReportRepo) { + this.userRepo = userRepo; + this.bugReportRepo = bugReportRepo; + + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); + } + + public String createBugReport(String creatorId, String projectId, String name, String description) { + var project = accessControl.getProjectForAddBugReportIfHasAccess(creatorId, projectId); + var bugReportDTO = new BugReportDTO(project, name, description); + var bugReport = bugReportRepo.save(bugReportDTO); + project.attachBugReport(bugReport); + return bugReport.getId(); + } + + public void addTesterToBugReport(String updaterId, String taskId, String testerId) { + var testerUser = userRepo.getUserById(testerId) + .map((user) -> user) + .orElseThrow(() -> new IllegalArgumentException("no such user " + testerId)); + + var bugReport = accessControl.getBugReportForMembersUpdateIfHasAccess(updaterId, taskId); + var project = bugReport.getProject(); + + var testerProjectMember = project.getMembers().stream() + .filter((projectMember) -> projectMember.user().equals(testerUser)).findFirst() + .map((projectMember) -> projectMember) + .orElseThrow( + () -> new IllegalArgumentException("no such user " + testerId + " in project " + project.getId())); + + bugReport.addTester(testerProjectMember); + } + + public BugReportStatus getBugReportStatus(String bugReportId) { + return bugReportRepo.getBugReportById(bugReportId) + .map((task) -> task.getStatus()) + .orElseThrow(() -> new IllegalArgumentException("no such bug report " + bugReportId)); + } + + public void updateBugReportStatus(String updaterId, String taskId, TaskStatus status) { + var task = accessControl.getTaskForStatusUpdateIfHasAccess(updaterId, taskId); + task.setStatus(status); + } +} diff --git a/src/main/java/org/lab/services/MilestoneService.java b/src/main/java/org/lab/services/MilestoneService.java index 5a54c94..869fde6 100644 --- a/src/main/java/org/lab/services/MilestoneService.java +++ b/src/main/java/org/lab/services/MilestoneService.java @@ -4,6 +4,7 @@ import org.lab.dto.MilestoneDTO; import org.lab.model.MilestoneModel.MilestoneStatus; +import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; import org.lab.repositories.TaskRepo.TaskRepo; @@ -15,14 +16,14 @@ public class MilestoneService { private final AccessControl accessControl; public MilestoneService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, - TaskRepo taskRepo) { + TaskRepo taskRepo, BugReportRepo bugReportRepo) { this.milestoneRepo = milestoneRepo; - this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo); + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); } public String createMilestone(String managerId, String projectId, String name, LocalDate start, LocalDate end) { - var project = accessControl.getProjectIfHasAccess(managerId, projectId); + var project = accessControl.getProjectForCreateMilestoneIfHasAccess(managerId, projectId); var milestoneDTO = new MilestoneDTO(project, name, start, end); var milestone = milestoneRepo.save(milestoneDTO); project.addMilestone(milestone); diff --git a/src/main/java/org/lab/services/ProjectService.java b/src/main/java/org/lab/services/ProjectService.java index 14fab7e..cacdafd 100644 --- a/src/main/java/org/lab/services/ProjectService.java +++ b/src/main/java/org/lab/services/ProjectService.java @@ -3,6 +3,7 @@ import org.lab.dto.ProjectDTO; import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.ProjectModel.ProjectRole; +import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; import org.lab.repositories.TaskRepo.TaskRepo; @@ -14,11 +15,12 @@ public class ProjectService { private final AccessControl accessControl; - public ProjectService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, TaskRepo taskRepo) { + public ProjectService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, TaskRepo taskRepo, + BugReportRepo bugReportRepo) { this.userRepo = userRepo; this.projectRepo = projectRepo; - this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo); + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); } public String createProject(String name, String managerUserId) { @@ -32,7 +34,7 @@ public String createProject(String name, String managerUserId) { } public void updateLead(String managerId, String projectId, String leadId) { - var project = accessControl.getProjectIfHasAccess(managerId, projectId); + var project = accessControl.getProjectForUpdateLeadIfHasAccess(managerId, projectId); var leadUser = userRepo.getUserById(leadId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + leadId)); @@ -43,7 +45,7 @@ public void updateLead(String managerId, String projectId, String leadId) { } public void addMember(String managerId, String projectId, String memberId, ProjectRole role) { - var project = accessControl.getProjectIfHasAccess(managerId, projectId); + var project = accessControl.getProjectForAddMemberIfHasAccess(managerId, projectId); var memberUser = userRepo.getUserById(memberId) .map((user) -> user) .orElseThrow(() -> new IllegalArgumentException("no such user " + memberId)); diff --git a/src/main/java/org/lab/services/TaskService.java b/src/main/java/org/lab/services/TaskService.java index 2e294f5..03f271b 100644 --- a/src/main/java/org/lab/services/TaskService.java +++ b/src/main/java/org/lab/services/TaskService.java @@ -2,6 +2,7 @@ import org.lab.dto.TaskDTO; import org.lab.model.TaskModel.TaskStatus; +import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; import org.lab.repositories.TaskRepo.TaskRepo; @@ -14,17 +15,17 @@ public class TaskService { private final AccessControl accessControl; public TaskService(UserRepo userRepo, ProjectRepo projectRepo, MilestoneRepo milestoneRepo, - TaskRepo taskRepo) { + TaskRepo taskRepo, BugReportRepo bugReportRepo) { this.userRepo = userRepo; this.taskRepo = taskRepo; - this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo); + this.accessControl = new AccessControl(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); } public String createTask(String creatorId, String milestoneId, String name, String description) { var milestone = accessControl.getMilestoneIfHasAccess(creatorId, milestoneId); var taskDTO = new TaskDTO(milestone, name, description); - var task = taskRepo.saveTask(taskDTO); + var task = taskRepo.save(taskDTO); milestone.addTask(task); return task.getId(); } From 6d69be8d64be5cf523936031b13c5e9bea7df36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Tue, 23 Dec 2025 21:18:31 +0300 Subject: [PATCH 09/11] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=83=D0=BD=D0=B8=D0=B2=D0=B5=D1=80=D1=81=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B2=20=D0=B2=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D1=83=20=D0=B8?= =?UTF-8?q?=20=D0=B1=D0=B0=D0=B3=D1=80=D0=B5=D0=BF=D0=BE=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/lab/model/BugReport/BugReport.java | 5 ----- .../java/org/lab/model/TaskModel/Task.java | 9 --------- .../java/org/lab/model/TicketModel/Ticket.java | 2 +- .../org/lab/services/BugReportService.java | 18 ++++++++++-------- .../java/org/lab/services/TaskService.java | 18 ++++++++++-------- 5 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/lab/model/BugReport/BugReport.java b/src/main/java/org/lab/model/BugReport/BugReport.java index 43e40f4..0f778f5 100644 --- a/src/main/java/org/lab/model/BugReport/BugReport.java +++ b/src/main/java/org/lab/model/BugReport/BugReport.java @@ -1,7 +1,6 @@ package org.lab.model.BugReport; import org.lab.model.ProjectModel.Project; -import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.TicketModel.Ticket; public final class BugReport extends Ticket { @@ -16,8 +15,4 @@ public BugReport(String id, Project project, String name, String description) { public Project getProject() { return project; } - - public void addTester(ProjectMember testerProjectMember) { - addToTicker(BugReportRole.TESTER, testerProjectMember); - } } diff --git a/src/main/java/org/lab/model/TaskModel/Task.java b/src/main/java/org/lab/model/TaskModel/Task.java index 97a5115..e22e9d5 100644 --- a/src/main/java/org/lab/model/TaskModel/Task.java +++ b/src/main/java/org/lab/model/TaskModel/Task.java @@ -1,7 +1,6 @@ package org.lab.model.TaskModel; import org.lab.model.MilestoneModel.Milestone; -import org.lab.model.ProjectModel.ProjectMember; import org.lab.model.TicketModel.Ticket; public final class Task extends Ticket { @@ -16,12 +15,4 @@ public Task(String id, Milestone milestone, String name, String description) { public Milestone getMilestone() { return milestone; } - - public void addDev(ProjectMember dev) { - addToTicker(TaskRole.DEV, dev); - } - - public void addTester(ProjectMember tester) { - addToTicker(TaskRole.TESTER, tester); - } } diff --git a/src/main/java/org/lab/model/TicketModel/Ticket.java b/src/main/java/org/lab/model/TicketModel/Ticket.java index 577268a..b8cd69a 100644 --- a/src/main/java/org/lab/model/TicketModel/Ticket.java +++ b/src/main/java/org/lab/model/TicketModel/Ticket.java @@ -47,7 +47,7 @@ public void setDescription(String description) { this.description = Objects.requireNonNull(description); } - protected void addToTicker(TRole role, ProjectMember member) { + public void addToTicker(TRole role, ProjectMember member) { members.putIfAbsent(role, new ArrayList<>()); members.get(role).add(member); } diff --git a/src/main/java/org/lab/services/BugReportService.java b/src/main/java/org/lab/services/BugReportService.java index ab80df0..3bf2361 100644 --- a/src/main/java/org/lab/services/BugReportService.java +++ b/src/main/java/org/lab/services/BugReportService.java @@ -1,6 +1,7 @@ package org.lab.services; import org.lab.dto.BugReportDTO; +import org.lab.model.BugReport.BugReportRole; import org.lab.model.BugReport.BugReportStatus; import org.lab.model.TaskModel.TaskStatus; import org.lab.repositories.BugReportRepo.BugReportRepo; @@ -31,21 +32,22 @@ public String createBugReport(String creatorId, String projectId, String name, S return bugReport.getId(); } - public void addTesterToBugReport(String updaterId, String taskId, String testerId) { - var testerUser = userRepo.getUserById(testerId) + public void addMemberToBugReport(String updaterId, String taskId, String memberId, BugReportRole role) { + var testerUser = userRepo.getUserById(memberId) .map((user) -> user) - .orElseThrow(() -> new IllegalArgumentException("no such user " + testerId)); + .orElseThrow(() -> new IllegalArgumentException("no such user " + memberId)); var bugReport = accessControl.getBugReportForMembersUpdateIfHasAccess(updaterId, taskId); var project = bugReport.getProject(); - var testerProjectMember = project.getMembers().stream() - .filter((projectMember) -> projectMember.user().equals(testerUser)).findFirst() - .map((projectMember) -> projectMember) + var projectMember = project.getMembers().stream() + .filter((p) -> p.user().equals(testerUser)).findFirst() + .map((p) -> p) .orElseThrow( - () -> new IllegalArgumentException("no such user " + testerId + " in project " + project.getId())); + () -> new IllegalArgumentException( + "no such user " + memberId + " in project " + project.getId())); - bugReport.addTester(testerProjectMember); + bugReport.addToTicker(role, projectMember); } public BugReportStatus getBugReportStatus(String bugReportId) { diff --git a/src/main/java/org/lab/services/TaskService.java b/src/main/java/org/lab/services/TaskService.java index 03f271b..9465145 100644 --- a/src/main/java/org/lab/services/TaskService.java +++ b/src/main/java/org/lab/services/TaskService.java @@ -1,6 +1,7 @@ package org.lab.services; import org.lab.dto.TaskDTO; +import org.lab.model.TaskModel.TaskRole; import org.lab.model.TaskModel.TaskStatus; import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.MilestoneRepo.MilestoneRepo; @@ -30,21 +31,22 @@ public String createTask(String creatorId, String milestoneId, String name, Stri return task.getId(); } - public void addDevToTask(String updaterId, String taskId, String devId) { - var devUser = userRepo.getUserById(devId) + public void addMemberToTask(String updaterId, String taskId, String memberId, TaskRole role) { + var devUser = userRepo.getUserById(memberId) .map((user) -> user) - .orElseThrow(() -> new IllegalArgumentException("no such user " + devId)); + .orElseThrow(() -> new IllegalArgumentException("no such user " + memberId)); var task = accessControl.getTaskForMembersUpdateIfHasAccess(updaterId, taskId); var project = task.getMilestone().getProject(); - var devProjectMember = project.getMembers().stream() - .filter((projectMember) -> projectMember.user().equals(devUser)).findFirst() - .map((projectMember) -> projectMember) + var projectMember = project.getMembers().stream() + .filter((p) -> p.user().equals(devUser)).findFirst() + .map((p) -> p) .orElseThrow( - () -> new IllegalArgumentException("no such user " + devId + " in project " + project.getId())); + () -> new IllegalArgumentException( + "no such user " + memberId + " in project " + project.getId())); - task.addDev(devProjectMember); + task.addToTicker(role, projectMember); } public TaskStatus getTaskStatus(String taskId) { From 2049dc703d0c7ef6f35129e9a66e1f13a257ef68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Thu, 25 Dec 2025 16:38:52 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=9F=D0=BE=D0=BA=D1=80=D1=8B=D0=BB=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/lab/Main.java | 142 +++++++++++++++++- .../java/org/lab/services/AccessControl.java | 39 +++-- .../org/lab/services/BugReportService.java | 7 +- 3 files changed, 168 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/lab/Main.java b/src/main/java/org/lab/Main.java index 00fdd8f..2b7f2bc 100644 --- a/src/main/java/org/lab/Main.java +++ b/src/main/java/org/lab/Main.java @@ -1,8 +1,148 @@ package org.lab; +import java.time.LocalDate; +import java.util.stream.Collectors; + +import org.lab.model.BugReport.BugReportRole; +import org.lab.model.BugReport.BugReportStatus; +import org.lab.model.MilestoneModel.MilestoneStatus; +import org.lab.model.ProjectModel.ProjectRole; +import org.lab.model.TaskModel.TaskRole; +import org.lab.model.TaskModel.TaskStatus; +import org.lab.repositories.BugReportRepo.InMemoryBugReportRepo; +import org.lab.repositories.MilestoneRepo.InMemoryMilestoneRepo; +import org.lab.repositories.ProjectRepo.InMemoryProjectRepo; +import org.lab.repositories.TaskRepo.InMemoryTaskRepo; +import org.lab.repositories.UserRepo.InMemoryUserRepo; +import org.lab.services.BugReportService; +import org.lab.services.MilestoneService; +import org.lab.services.ProjectService; +import org.lab.services.TaskService; +import org.lab.services.UserService; public class Main { void main() { - IO.println("Hello and welcome!"); + var userRepo = new InMemoryUserRepo(); + var projectRepo = new InMemoryProjectRepo(); + var milestoneRepo = new InMemoryMilestoneRepo(); + var taskRepo = new InMemoryTaskRepo(); + var bugReportRepo = new InMemoryBugReportRepo(); + + var userService = new UserService(userRepo, projectRepo, taskRepo, bugReportRepo); + var projectService = new ProjectService(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); + var milestoneService = new MilestoneService(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); + var taskService = new TaskService(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); + var bugReportService = new BugReportService(userRepo, projectRepo, milestoneRepo, taskRepo, bugReportRepo); + + var aliceManagerId = userService.registerUser("Alice Manager", "alice@example.com"); + var bobDevId = userService.registerUser("Bob Dev", "bob@example.com"); + var grokTesterId = userService.registerUser("Grok Tester", "grok@example.com"); + var zigLeadId = userService.registerUser("Zig Lead", "zig@example.com"); + + var projectId = projectService.createProject("Project", aliceManagerId); + projectService.updateLead(aliceManagerId, projectId, zigLeadId); + projectService.addMember(aliceManagerId, projectId, bobDevId, ProjectRole.DEV); + projectService.addMember(aliceManagerId, projectId, grokTesterId, ProjectRole.TESTER); + + projectRepo.getProjectById(projectId).ifPresent((project) -> { + IO.println("Project " + project.getId() + " team"); + project.getMembers().stream().forEach((member) -> { + IO.println(member.user().name() + " " + member.role().name()); + }); + IO.println(); + }); + + var milestoneStart = LocalDate.of(2025, 10, 1); + var milestoneEnd = LocalDate.of(2025, 11, 1); + var milestoneId = milestoneService.createMilestone(aliceManagerId, projectId, "MVP Release", milestoneStart, + milestoneEnd); + + milestoneRepo.getMilestoneById(milestoneId).ifPresent((milestone) -> { + IO.println("Milestone " + milestoneId + " data"); + IO.println(milestone.getName() + " " + milestone.getStatus().name()); + IO.println(); + }); + milestoneService.updateMilestoneStatus(aliceManagerId, milestoneId, MilestoneStatus.ACTIVE); + milestoneRepo.getMilestoneById(milestoneId).ifPresent((milestone) -> { + IO.println("Milestone " + milestoneId + " data"); + IO.println(milestone.getName() + " " + milestone.getStatus().name()); + IO.println(); + }); + + var taskId = taskService.createTask(aliceManagerId, milestoneId, "task", "task desc"); + taskRepo.getTaskById(taskId).ifPresent((task) -> { + IO.println("Task " + taskId + " data"); + IO.println(task.getName() + " " + task.getDescription() + " " + task.getStatus().name()); + IO.println(); + }); + + var taskStatus = taskService.getTaskStatus(taskId); + IO.println("Task status " + taskStatus.name()); + IO.println(); + + taskRepo.getTaskById(taskId).ifPresent((task) -> { + IO.println("Task " + taskId + " members"); + task.getTicketMembers().entrySet().stream().forEach((memberEntry) -> { + var membersString = memberEntry.getValue().stream().map((member) -> member.user().name()) + .collect(Collectors.joining(", ")); + IO.print("Role " + memberEntry.getKey().name() + ": " + membersString); + }); + IO.println(); + }); + taskService.addMemberToTask(zigLeadId, taskId, bobDevId, TaskRole.DEV); + taskRepo.getTaskById(taskId).ifPresent((task) -> { + IO.println("Task " + taskId + " members"); + task.getTicketMembers().entrySet().stream().forEach((memberEntry) -> { + var membersString = memberEntry.getValue().stream().map((member) -> member.user().name()) + .collect(Collectors.joining(", ")); + IO.print("Role " + memberEntry.getKey().name() + ": " + membersString); + }); + IO.println(); + }); + + taskService.updateTaskStatus(bobDevId, taskId, TaskStatus.IN_PROGESS); + taskRepo.getTaskById(taskId).ifPresent((task) -> { + IO.println("Task " + taskId + " data"); + IO.println(task.getName() + " " + task.getDescription() + " " + task.getStatus().name()); + IO.println(); + }); + + var reportId = bugReportService.createBugReport(grokTesterId, projectId, "report", "report desc"); + bugReportRepo.getBugReportById(reportId).ifPresent((report) -> { + IO.println("Report " + reportId + " data"); + IO.println(report.getName() + " " + report.getDescription() + " " + report.getStatus().name()); + IO.println(); + }); + + var bugReportStatus = bugReportService.getBugReportStatus(reportId); + IO.println("Report status " + bugReportStatus.name()); + IO.println(); + + bugReportRepo.getBugReportById(reportId).ifPresent((report) -> { + IO.println("Report " + reportId + " members"); + report.getTicketMembers().entrySet().stream().forEach((memberEntry) -> { + var membersString = memberEntry.getValue().stream().map((member) -> member.user().name()) + .collect(Collectors.joining(", ")); + IO.print("Role " + memberEntry.getKey().name() + ": " + membersString); + }); + IO.println(); + }); + bugReportService.addMemberToBugReport(zigLeadId, reportId, bobDevId, BugReportRole.DEV); + bugReportRepo.getBugReportById(reportId).ifPresent((task) -> { + IO.println("Report " + reportId + " members"); + task.getTicketMembers().entrySet().stream().forEach((memberEntry) -> { + var membersString = memberEntry.getValue().stream().map((member) -> member.user().name()) + .collect(Collectors.joining(", ")); + IO.print("Role " + memberEntry.getKey().name() + ": " + membersString); + }); + IO.println(); + }); + + bugReportService.updateBugReportStatus(bobDevId, reportId, BugReportStatus.FIXED); + bugReportRepo.getBugReportById(reportId).ifPresent((task) -> { + IO.println("Report " + reportId + " data"); + IO.println(task.getName() + " " + task.getDescription() + " " + task.getStatus().name()); + IO.println(); + }); } } diff --git a/src/main/java/org/lab/services/AccessControl.java b/src/main/java/org/lab/services/AccessControl.java index 79f91c1..7b40d8e 100644 --- a/src/main/java/org/lab/services/AccessControl.java +++ b/src/main/java/org/lab/services/AccessControl.java @@ -41,10 +41,12 @@ public Project getProjectForAddBugReportIfHasAccess(String userId, String projec .map((projectMember) -> projectMember) .orElseThrow( () -> new IllegalArgumentException( - "no such user " + tester + " in project " + projectToReport.getId())); + "no such user " + tester + " in project " + + projectToReport.getId())); if (testerProjectMember.role() != ProjectRole.TESTER && testerProjectMember.role() != ProjectRole.DEV) { - throw new IllegalArgumentException("user " + userId + " is not tester or dev of project " + projectId); + throw new IllegalArgumentException( + "user " + userId + " is not tester or dev of project " + projectId); } return projectToReport; @@ -59,8 +61,9 @@ public Project getProjectForUpdateLeadIfHasAccess(String userId, String projectI .map((project) -> project) .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); - if (!managerProject.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + userId + " is not manager of project " + projectId); + if (!managerProject.getManager().user().equals(manager)) { + throw new IllegalArgumentException( + "user " + userId + " is not manager of project " + projectId); } return managerProject; @@ -75,8 +78,9 @@ public Project getProjectForAddMemberIfHasAccess(String userId, String projectId .map((project) -> project) .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); - if (!managerProject.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + userId + " is not manager of project " + projectId); + if (!managerProject.getManager().user().equals(manager)) { + throw new IllegalArgumentException( + "user " + userId + " is not manager of project " + projectId); } return managerProject; @@ -91,8 +95,9 @@ public Project getProjectForCreateMilestoneIfHasAccess(String userId, String pro .map((project) -> project) .orElseThrow(() -> new IllegalArgumentException("no such project " + projectId)); - if (!managerProject.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + userId + " is not manager of project " + projectId); + if (!managerProject.getManager().user().equals(manager)) { + throw new IllegalArgumentException( + "user " + userId + " is not manager of project " + projectId); } return managerProject; @@ -109,8 +114,9 @@ public Milestone getMilestoneIfHasAccess(String userId, String milestoneId) { var project = projectMilestone.getProject(); - if (!project.getManager().equals(manager)) { - throw new IllegalArgumentException("user " + userId + " is not manager of project " + project.getId()); + if (!project.getManager().user().equals(manager)) { + throw new IllegalArgumentException( + "user " + userId + " is not manager of project " + project.getId()); } return projectMilestone; @@ -126,7 +132,7 @@ public Task getTaskForMembersUpdateIfHasAccess(String userId, String taskId) { var project = task.getMilestone().getProject(); - if (!project.getManager().equals(updater) && !project.getLead().equals(updater)) { + if (!project.getManager().user().equals(updater) && !project.getLead().user().equals(updater)) { throw new IllegalArgumentException( "user " + userId + " is not manager or lead of project " + project.getId()); } @@ -144,7 +150,7 @@ public BugReport getBugReportForMembersUpdateIfHasAccess(String userId, String b var project = bugReport.getProject(); - if (!project.getManager().equals(updater) && !project.getLead().equals(updater)) { + if (!project.getManager().user().equals(updater) && !project.getLead().user().equals(updater)) { throw new IllegalArgumentException( "user " + userId + " is not manager or lead of project " + project.getId()); } @@ -167,7 +173,8 @@ public Task getTaskForStatusUpdateIfHasAccess(String userId, String taskId) { .map((projectMember) -> projectMember) .orElseThrow( () -> new IllegalArgumentException( - "no such user " + updater + " in project " + project.getId())); + "no such user " + updater + " in project " + + project.getId())); if (updaterProjectMember.role() != ProjectRole.DEV && updaterProjectMember.role() != ProjectRole.LEAD) { throw new IllegalArgumentException( @@ -192,9 +199,11 @@ public BugReport getBugReportForStatusUpdateIfHasAccess(String userId, String bu .map((projectMember) -> projectMember) .orElseThrow( () -> new IllegalArgumentException( - "no such user " + updater + " in project " + project.getId())); + "no such user " + updater + " in project " + + project.getId())); - if (updaterProjectMember.role() != ProjectRole.DEV && updaterProjectMember.role() != ProjectRole.TESTER) { + if (updaterProjectMember.role() != ProjectRole.DEV + && updaterProjectMember.role() != ProjectRole.TESTER) { throw new IllegalArgumentException( "user " + userId + " is not dev or tester of project " + project.getId()); } diff --git a/src/main/java/org/lab/services/BugReportService.java b/src/main/java/org/lab/services/BugReportService.java index 3bf2361..f08892f 100644 --- a/src/main/java/org/lab/services/BugReportService.java +++ b/src/main/java/org/lab/services/BugReportService.java @@ -3,7 +3,6 @@ import org.lab.dto.BugReportDTO; import org.lab.model.BugReport.BugReportRole; import org.lab.model.BugReport.BugReportStatus; -import org.lab.model.TaskModel.TaskStatus; import org.lab.repositories.BugReportRepo.BugReportRepo; import org.lab.repositories.MilestoneRepo.MilestoneRepo; import org.lab.repositories.ProjectRepo.ProjectRepo; @@ -56,8 +55,8 @@ public BugReportStatus getBugReportStatus(String bugReportId) { .orElseThrow(() -> new IllegalArgumentException("no such bug report " + bugReportId)); } - public void updateBugReportStatus(String updaterId, String taskId, TaskStatus status) { - var task = accessControl.getTaskForStatusUpdateIfHasAccess(updaterId, taskId); - task.setStatus(status); + public void updateBugReportStatus(String updaterId, String taskId, BugReportStatus status) { + var bugReport = accessControl.getBugReportForStatusUpdateIfHasAccess(updaterId, taskId); + bugReport.setStatus(status); } } From 61573dec8d928dead5fab9cdf42432edcce3f36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=94=D0=B0=D0=B2?= =?UTF-8?q?=D1=8B=D0=B4=D0=BE=D0=B2?= Date: Thu, 25 Dec 2025 17:30:37 +0300 Subject: [PATCH 11/11] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=BD=D1=83=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/lab/services/BugReportService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/lab/services/BugReportService.java b/src/main/java/org/lab/services/BugReportService.java index f08892f..33a4d4e 100644 --- a/src/main/java/org/lab/services/BugReportService.java +++ b/src/main/java/org/lab/services/BugReportService.java @@ -51,7 +51,7 @@ public void addMemberToBugReport(String updaterId, String taskId, String memberI public BugReportStatus getBugReportStatus(String bugReportId) { return bugReportRepo.getBugReportById(bugReportId) - .map((task) -> task.getStatus()) + .map((report) -> report.getStatus()) .orElseThrow(() -> new IllegalArgumentException("no such bug report " + bugReportId)); }