Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
af31a35
kluczowe zmiany
May 8, 2026
de39ee0
styles
May 8, 2026
8f1880c
cleanup
May 9, 2026
0ee875f
fixed build
rrogalski May 9, 2026
326f755
Merge branch 'develop' into wnioskowanie-o-pracownika
May 13, 2026
86b9070
review changes
May 13, 2026
dbf5981
Merge pull request #50 from FAZ110/wnioskowanie-o-pracownika
rrogalski May 13, 2026
0b0e7d3
Add first implementation of project registry
mistermotopl May 16, 2026
784724b
Feature/ip 99 integracja UI powiadomien (#56)
mtrznadel24 May 16, 2026
73cae40
feat(auth): adjust authority roles and optimize navigation layout (#58)
mtrznadel24 May 16, 2026
19f8b80
More correction in code
mistermotopl May 17, 2026
0b3217c
Merge branch 'develop', remote-tracking branch 'origin' into IP-43-Mo…
mistermotopl May 17, 2026
43ea7e2
Corrections after merging develop
mistermotopl May 17, 2026
eaedd9c
Fix lint problem
mistermotopl May 17, 2026
0afa5fa
Fix backend test
mistermotopl May 17, 2026
319a9fa
Add new filters and data to display, correct things from review
mistermotopl May 18, 2026
4226536
Add changes for backend
mistermotopl May 18, 2026
596eacc
nowe funkcjonalnosci api
rrogalski May 19, 2026
2ed575e
some changes
rrogalski May 19, 2026
d4517b2
Correct name of column and casting
mistermotopl May 19, 2026
0a394d5
Merge pull request #59 from FAZ110/IP-43-Możliwość-filtrowania-i-wysz…
mistermotopl May 19, 2026
796ddd6
some cleanup
rrogalski May 19, 2026
e457fa8
Merge branch 'develop' into poprawki-strona-projektu
rrogalski May 19, 2026
d1c0431
fixy
rrogalski May 20, 2026
e556dd0
Merge pull request #60 from FAZ110/poprawki-strona-projektu
rrogalski May 20, 2026
3096f1c
employee registry added
FAZ110 May 21, 2026
b186b10
poprawki po review
FAZ110 May 22, 2026
a651189
hot-fix
FAZ110 May 22, 2026
eb42f5f
Ip 106 wysiwetlanie struktury programow i portfeli (#57)
PatrykBlacha May 22, 2026
7a1a7e6
fixing employees registry
FAZ110 May 23, 2026
776bd7e
Merge remote-tracking branch 'origin/develop' into IP-124-rejestr-pra…
FAZ110 May 23, 2026
967aff3
poprawki z review
FAZ110 May 23, 2026
4bbe8d8
feat(risks): implement 5x5 risk matrix and fix persistence bug (#62)
mtrznadel24 May 23, 2026
cea7e8d
Merge pull request #61 from FAZ110/IP-124-rejestr-pracownikow
FAZ110 May 24, 2026
7cb1163
backend: add endpoints exposing user profile data
sbarczyk May 25, 2026
d18add9
backend: expand dev seeder with roles, projects and assignments
sbarczyk May 25, 2026
841663b
frontend: add types, services and hooks for new profile endpoints
sbarczyk May 25, 2026
d84f1ab
frontend: redesign role badge with color and icon per role
sbarczyk May 25, 2026
4538355
frontend: add shared section header for profile cards
sbarczyk May 25, 2026
5313c30
frontend: add read-only mode to qualifications card
sbarczyk May 25, 2026
0c4bc98
frontend: redesign profile header with stats bar and clickable superv…
sbarczyk May 25, 2026
027b74f
frontend: add profile section cards (subordinates, projects, membersh…
sbarczyk May 25, 2026
08445a5
frontend: render profile sections dynamically based on user role
sbarczyk May 25, 2026
af77afe
Ip 3 eksport danych
PatrykBlacha May 25, 2026
44504fc
refactor komponentu do tworzenia projektów (#64)
FAZ110 May 26, 2026
cc86731
Merge branch 'develop' into profile-uzytkownikow
mtrznadel24 May 26, 2026
3ab96fa
feat(projectFrom): fix paths to employee details
mtrznadel24 May 26, 2026
48fbe23
feat(projectFrom): fix test
mtrznadel24 May 26, 2026
76a803c
Merge pull request #65 from FAZ110/profile-uzytkownikow
sbarczyk May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ logs/
# =========================
coverage/

# Claude Code local settings
.claude/settings.local.json

8 changes: 7 additions & 1 deletion backend/project-manager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.2'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

// JSON Web Token (JWT)
implementation 'io.jsonwebtoken:jjwt-api:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5'

// CSV & PDF
implementation 'com.opencsv:opencsv:5.9'
implementation 'com.openhtmltopdf:openhtmltopdf-core:1.0.10'
implementation 'com.openhtmltopdf:openhtmltopdf-pdfbox:1.0.10'

// TOOLS
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
Expand All @@ -68,4 +74,4 @@ tasks.named('test') {

jar {
enabled = false
}
}
1 change: 1 addition & 0 deletions backend/project-manager/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.gradle.java.installations.auto-download=true
4 changes: 4 additions & 0 deletions backend/project-manager/settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
}

rootProject.name = 'project-manager'

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import pl.edu.agh.project_manager.domain.exception.ApiErrorCode;
import pl.edu.agh.project_manager.domain.exception.ApplicationException;

import java.util.HashMap;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
Expand Down Expand Up @@ -63,4 +67,19 @@ public ResponseEntity<ApiErrorResponse> handleGeneralException(Exception ex) {
.status(error.getHttpStatus())
.body(body);
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
String message = ex.getBindingResult().getFieldErrors().stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining(", "));

var error = ApiErrorCode.VALIDATION_FAILED;

var body = new ApiErrorResponse(error.getCode(), message);

return ResponseEntity
.status(error.getHttpStatus())
.body(body);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class ApprovalsController {
private final QualificationManagementService qualificationService;

@GetMapping("/assignments/pending")
@PreAuthorize("hasRole('LINEAR_MANAGER')")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY')")
public ResponseEntity<List<AssignmentResponse>> getPendingAssignments(
@AuthenticationPrincipal UserPrincipal principal
) {
Expand All @@ -38,7 +38,7 @@ public ResponseEntity<List<AssignmentResponse>> getPendingAssignments(
}

@PostMapping("/assignments/{assignmentId}/accept")
@PreAuthorize("hasRole('LINEAR_MANAGER') and @assignmentAccess.canManageAssignment(#assignmentId, authentication.principal)")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY') and @assignmentAccess.canManageAssignment(#assignmentId, authentication.principal)")
public ResponseEntity<Void> acceptAssignment(
@PathVariable UUID assignmentId,
@AuthenticationPrincipal UserPrincipal principal
Expand All @@ -48,7 +48,7 @@ public ResponseEntity<Void> acceptAssignment(
}

@PostMapping("/assignments/{assignmentId}/reject")
@PreAuthorize("hasRole('LINEAR_MANAGER') and @assignmentAccess.canManageAssignment(#assignmentId, authentication.principal)")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY') and @assignmentAccess.canManageAssignment(#assignmentId, authentication.principal)")
public ResponseEntity<Void> rejectAssignment(
@PathVariable UUID assignmentId,
@AuthenticationPrincipal UserPrincipal principal
Expand All @@ -58,7 +58,7 @@ public ResponseEntity<Void> rejectAssignment(
}

@GetMapping("/assignments/{assignmentId}/details")
@PreAuthorize("hasRole('LINEAR_MANAGER') and @assignmentAccess.canManageAssignment(#assignmentId, authentication.principal)")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY') and @assignmentAccess.canManageAssignment(#assignmentId, authentication.principal)")
public ResponseEntity<EmployeeAssignmentDetailsResponse> getAssignmentDetails(
@PathVariable UUID assignmentId,
@AuthenticationPrincipal UserPrincipal principal
Expand All @@ -68,19 +68,19 @@ public ResponseEntity<EmployeeAssignmentDetailsResponse> getAssignmentDetails(
}

@GetMapping("/qualifications")
@PreAuthorize("hasRole('LINEAR_MANAGER')")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY')")
public ResponseEntity<List<QualificationRequestResponse>> getUsersWithWaitingQualifications(@AuthenticationPrincipal UserPrincipal principal) {
return ResponseEntity.ok(qualificationService.getRecordsForManager(principal.userId()));
}

@GetMapping("/qualifications/details")
@PreAuthorize("hasRole('LINEAR_MANAGER') and @qualificationSecurity.isManagerForUser(principal.userId(), #userId)")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY') and @qualificationSecurity.isManagerForUser(principal.userId(), #userId)")
public ResponseEntity<List<QualificationDetailsResponse>> getQualificationRequestDetails(@RequestParam UUID userId) {
return ResponseEntity.ok(qualificationService.getPendingForUser(userId));
}

@PostMapping("/qualifications/bulk-update")
@PreAuthorize("hasRole('LINEAR_MANAGER')")
@PreAuthorize("hasAnyRole('LINEAR_MANAGER', 'AUTHORITY')")
public ResponseEntity<Void> updateQualificationRequests(
@Valid @RequestBody List<QualificationUpdateRequest> requests,
@AuthenticationPrincipal UserPrincipal principal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.edu.agh.project_manager.controller.dto.employee_requests;
package pl.edu.agh.project_manager.controller.dto.common;

import java.time.LocalDate;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package pl.edu.agh.project_manager.controller.dto.employee_requests;

import pl.edu.agh.project_manager.controller.dto.common.ChartIntervalResponse;

import java.util.List;

public record EmployeeAssignmentDetailsResponse(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@

public record MilestoneResponse (
UUID id,

String name,

String description,

LocalDate date
) {
public static MilestoneResponse from(ProjectMilestone milestone) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,22 @@
public record AssignmentResponse(
UUID id,
UUID projectId,
UUID userId,
String projectName,
String roleName,
LocalDate startDate,
LocalDate endDate,
Integer utilizationPercentage,
AssignmentStatus status,
String employeeName,
String employeeSurname,
AssignmentStatusResponse status,
LocalDateTime createdAt
) {
public static AssignmentResponse from(ProjectAssignment assignment) {
return new AssignmentResponse(
assignment.getId(),
assignment.getProject().getId(),
assignment.getUser().getId(),
assignment.getProject().getTitle(),
assignment.getRoleName(),
assignment.getStartDate(),
assignment.getEndDate(),
assignment.getUtilizationPercentage(),
assignment.getStatus(),
assignment.getUser().getName(),
assignment.getUser().getSurname(),
AssignmentStatusResponse.from(assignment.getStatus()),
assignment.getCreatedAt()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package pl.edu.agh.project_manager.controller.dto.project;

import pl.edu.agh.project_manager.domain.enums.AssignmentStatus;

public enum AssignmentStatusResponse {
PENDING,
ACCEPTED,
REJECTED;

public static AssignmentStatusResponse from(AssignmentStatus status) {
return switch (status) {
case PENDING -> PENDING;
case ACCEPTED -> ACCEPTED;
case REJECTED -> REJECTED;
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package pl.edu.agh.project_manager.controller.dto.project;

import pl.edu.agh.project_manager.domain.entity.project.ProjectAssignment;
import pl.edu.agh.project_manager.domain.entity.user.User;

import java.util.List;
import java.util.UUID;

public record AssignmentsByEmployeeResponse(
UUID userId,
String name,
String surname,
String email,
List<ProjectAssignmentResponse> assignments
) {
public static AssignmentsByEmployeeResponse from(User user, List<ProjectAssignment> userAssignments) {
return new AssignmentsByEmployeeResponse(
user.getId(),
user.getName(),
user.getSurname(),
user.getEmail(),
userAssignments.stream()
.map(ProjectAssignmentResponse::from)
.toList()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package pl.edu.agh.project_manager.controller.dto.project;

import pl.edu.agh.project_manager.domain.entity.project.ProjectAssignment;

import java.time.LocalDate;
import java.util.UUID;

public record ProjectAssignmentResponse(
UUID id,
LocalDate startDate,
LocalDate endDate,
AssignmentStatusResponse status,
String roleName,
int utilizationPercentage
) {
public static ProjectAssignmentResponse from(ProjectAssignment assignment) {
return new ProjectAssignmentResponse(
assignment.getId(),
assignment.getStartDate(),
assignment.getEndDate(),
AssignmentStatusResponse.from(assignment.getStatus()),
assignment.getRoleName(),
assignment.getUtilizationPercentage()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package pl.edu.agh.project_manager.controller.dto.project;

import pl.edu.agh.project_manager.controller.dto.common.ChartIntervalResponse;

import java.util.List;

public record ProjectAssignmentUserWorkloadResponse(
List<ChartIntervalResponse> workload
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import pl.edu.agh.project_manager.controller.dto.milestone.MilestoneRequest;
import pl.edu.agh.project_manager.controller.dto.project_risk.ProjectRiskRequest;
import pl.edu.agh.project_manager.service.command.project.ProjectCreationCommand;

import java.time.LocalDate;
Expand All @@ -26,20 +26,20 @@ public record ProjectCreationRequest(

UUID projectGroupId,

@NotEmpty(message = "Lista sponsorów nie może być pusta")
List<UUID> sponsors,

@NotEmpty(message = "Lista członków komitetu sterującego nie może być pusta")
List<UUID> committee,

@Valid
List<RiskRequest> risks,
List<ProjectRiskRequest> risks,

@Valid
List<MilestoneRequest> milestones
) {
public ProjectCreationRequest {
if (risks == null || risks.isEmpty()) risks = List.of();
if (sponsors == null) sponsors = List.of();
if (committee == null) committee = List.of();
}

public ProjectCreationCommand toCommand(UUID creatorId) {
Expand All @@ -50,7 +50,7 @@ public ProjectCreationCommand toCommand(UUID creatorId) {
this.startDate,
this.endDate,
this.projectGroupId,
this.risks.stream().map(RiskRequest::toCommand).toList(),
this.risks.stream().map(ProjectRiskRequest::toCommand).toList(),
this.milestones.stream().map(MilestoneRequest::toCommand).toList(),
this.sponsors,
this.committee
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pl.edu.agh.project_manager.controller.dto.user.UserResponse;
import pl.edu.agh.project_manager.domain.entity.project.Project;
import pl.edu.agh.project_manager.controller.dto.project_group.GroupBasicResponse;

import java.time.LocalDate;
import java.util.UUID;
Expand All @@ -13,7 +14,8 @@ public record ProjectResponse(
LocalDate startDate,
LocalDate endDate,
Boolean isActive,
UserResponse manager
UserResponse manager,
GroupBasicResponse group
) {
public static ProjectResponse from(Project project) {
return new ProjectResponse(
Expand All @@ -23,7 +25,8 @@ public static ProjectResponse from(Project project) {
project.getStartDate(),
project.getEndDate(),
project.getIsActive(),
UserResponse.from(project.getProjectManager())
UserResponse.from(project.getProjectManager()),
GroupBasicResponse.from(project.getProjectGroup())
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package pl.edu.agh.project_manager.controller.dto.project;

import pl.edu.agh.project_manager.controller.dto.milestone.MilestoneResponse;

import java.util.List;

public record ProjectTimelineResponse(
List<MilestoneResponse> milestones,
List<AssignmentsByEmployeeResponse> assignments
) {
}

This file was deleted.

Loading
Loading