feat(sprint-3): Phase 2 — club settings controller

This commit is contained in:
Patrick Plate
2026-06-11 16:56:44 +02:00
parent 55d8434f35
commit 36deb72cf0
15 changed files with 700 additions and 0 deletions
@@ -0,0 +1,94 @@
package de.cannamanage.api.controller;
import de.cannamanage.api.dto.club.ClubResponse;
import de.cannamanage.api.dto.club.ClubStatsResponse;
import de.cannamanage.api.dto.club.UpdateClubRequest;
import de.cannamanage.domain.entity.Club;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.service.ClubService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
@RestController
@RequestMapping("/api/v1/clubs")
@RequiredArgsConstructor
@Tag(name = "Club Settings", description = "Club configuration and statistics")
public class ClubController {
private final ClubService clubService;
@GetMapping("/me")
@Operation(summary = "Get current club", description = "Returns the club for the current tenant")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<ClubResponse> getMyClub() {
UUID tenantId = TenantContext.getCurrentTenant();
Club club = clubService.getClubByTenantId(tenantId);
return ResponseEntity.ok(toResponse(club));
}
@PutMapping("/me")
@Operation(summary = "Update club settings", description = "Updates the club configuration for the current tenant")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<ClubResponse> updateMyClub(@Valid @RequestBody UpdateClubRequest request) {
UUID tenantId = TenantContext.getCurrentTenant();
Club updated = clubService.updateClub(
tenantId,
request.name(),
request.registrationNumber(),
request.contactEmail(),
request.contactPhone(),
request.addressStreet(),
request.addressCity(),
request.addressPostalCode(),
request.addressState(),
request.foundedDate(),
request.maxPreventionOfficers(),
request.allowedEmailPattern()
);
return ResponseEntity.ok(toResponse(updated));
}
@GetMapping("/me/stats")
@Operation(summary = "Get club statistics", description = "Returns aggregated club statistics")
@PreAuthorize("hasRole('ADMIN') or @staffPermissions.has(authentication, T(de.cannamanage.domain.enums.StaffPermission).VIEW_COMPLIANCE_REPORT)")
public ResponseEntity<ClubStatsResponse> getMyClubStats() {
UUID tenantId = TenantContext.getCurrentTenant();
ClubService.ClubStats stats = clubService.getClubStats(tenantId);
return ResponseEntity.ok(new ClubStatsResponse(
stats.totalMembers(),
stats.activeMembers(),
stats.totalStaff(),
stats.activeStaff(),
stats.totalDistributionsThisMonth(),
stats.totalGramsDistributedThisMonth(),
stats.activeBatches(),
stats.preventionOfficerCount()
));
}
private ClubResponse toResponse(Club club) {
return new ClubResponse(
club.getId(),
club.getName(),
club.getRegistrationNumber(),
club.getContactEmail(),
club.getContactPhone(),
club.getAddressStreet(),
club.getAddressCity(),
club.getAddressPostalCode(),
club.getAddressState(),
club.getFoundedDate(),
club.getMaxPreventionOfficers(),
club.getAllowedEmailPattern(),
club.getStatus(),
club.getCreatedAt()
);
}
}
@@ -0,0 +1,24 @@
package de.cannamanage.api.dto.club;
import de.cannamanage.domain.enums.ClubStatus;
import java.time.Instant;
import java.time.LocalDate;
import java.util.UUID;
public record ClubResponse(
UUID id,
String name,
String registrationNumber,
String contactEmail,
String contactPhone,
String addressStreet,
String addressCity,
String addressPostalCode,
String addressState,
LocalDate foundedDate,
Integer maxPreventionOfficers,
String allowedEmailPattern,
ClubStatus status,
Instant createdAt
) {}
@@ -0,0 +1,14 @@
package de.cannamanage.api.dto.club;
import java.math.BigDecimal;
public record ClubStatsResponse(
long totalMembers,
long activeMembers,
long totalStaff,
long activeStaff,
long totalDistributionsThisMonth,
BigDecimal totalGramsDistributedThisMonth,
long activeBatches,
long preventionOfficerCount
) {}
@@ -0,0 +1,34 @@
package de.cannamanage.api.dto.club;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import java.time.LocalDate;
public record UpdateClubRequest(
@NotBlank(message = "Club name is required")
String name,
String registrationNumber,
@Email(message = "Must be a valid email address")
String contactEmail,
String contactPhone,
String addressStreet,
String addressCity,
String addressPostalCode,
String addressState,
LocalDate foundedDate,
@Min(value = 1, message = "Must have at least 1 prevention officer slot")
Integer maxPreventionOfficers,
String allowedEmailPattern
) {}