mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2026-01-20 16:51:03 -05:00
added support for a new builds/detials page and endpoints
This commit is contained in:
@@ -37,19 +37,29 @@ public class SecurityConfig {
|
|||||||
.cors(c -> c.configurationSource(corsConfigurationSource()))
|
.cors(c -> c.configurationSource(corsConfigurationSource()))
|
||||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
// public
|
|
||||||
|
// ----------------------------
|
||||||
|
// Public
|
||||||
|
// ----------------------------
|
||||||
.requestMatchers("/api/auth/**").permitAll()
|
.requestMatchers("/api/auth/**").permitAll()
|
||||||
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||||
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
|
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
|
||||||
.requestMatchers("/api/products/gunbuilder/**").permitAll()
|
.requestMatchers("/api/products/gunbuilder/**").permitAll()
|
||||||
.requestMatchers(HttpMethod.GET, "/api/v1/builds").permitAll()
|
|
||||||
|
|
||||||
// protected
|
// Public builds feed + public build detail (1 path segment only)
|
||||||
|
.requestMatchers(HttpMethod.GET, "/api/v1/builds").permitAll()
|
||||||
|
.requestMatchers(HttpMethod.GET, "/api/v1/builds/*").permitAll()
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Protected
|
||||||
|
// ----------------------------
|
||||||
.requestMatchers("/api/v1/builds/me/**").authenticated()
|
.requestMatchers("/api/v1/builds/me/**").authenticated()
|
||||||
.requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
|
.requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
|
||||||
// everything else (adjust later as you lock down)
|
|
||||||
|
// Everything else (adjust later as you lock down)
|
||||||
.anyRequest().permitAll()
|
.anyRequest().permitAll()
|
||||||
)
|
)
|
||||||
|
|
||||||
// run JWT before AnonymousAuth sets principal="anonymousUser"
|
// run JWT before AnonymousAuth sets principal="anonymousUser"
|
||||||
.addFilterBefore(jwtAuthenticationFilter, AnonymousAuthenticationFilter.class);
|
.addFilterBefore(jwtAuthenticationFilter, AnonymousAuthenticationFilter.class);
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import group.goforward.battlbuilder.web.dto.BuildDto;
|
|||||||
import group.goforward.battlbuilder.web.dto.BuildFeedCardDto;
|
import group.goforward.battlbuilder.web.dto.BuildFeedCardDto;
|
||||||
import group.goforward.battlbuilder.web.dto.BuildSummaryDto;
|
import group.goforward.battlbuilder.web.dto.BuildSummaryDto;
|
||||||
import group.goforward.battlbuilder.web.dto.UpdateBuildRequest;
|
import group.goforward.battlbuilder.web.dto.UpdateBuildRequest;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -34,6 +34,15 @@ public class BuildV1Controller {
|
|||||||
return ResponseEntity.ok(buildService.listPublicBuilds(limit == null ? 50 : limit));
|
return ResponseEntity.ok(buildService.listPublicBuilds(limit == null ? 50 : limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public build detail for /builds/{uuid}
|
||||||
|
* GET /api/v1/builds/{uuid}
|
||||||
|
*/
|
||||||
|
@GetMapping("/{uuid}")
|
||||||
|
public ResponseEntity<BuildDto> getPublicBuild(@PathVariable("uuid") UUID uuid) {
|
||||||
|
return ResponseEntity.ok(buildService.getPublicBuild(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vault builds (authenticated user).
|
* Vault builds (authenticated user).
|
||||||
* GET /api/v1/builds/me?limit=100
|
* GET /api/v1/builds/me?limit=100
|
||||||
@@ -75,7 +84,6 @@ public class BuildV1Controller {
|
|||||||
return ResponseEntity.ok(buildService.updateMyBuild(uuid, req));
|
return ResponseEntity.ok(buildService.updateMyBuild(uuid, req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a build (authenticated user; must own build).
|
* Delete a build (authenticated user; must own build).
|
||||||
* DELETE /api/v1/builds/me/{uuid}
|
* DELETE /api/v1/builds/me/{uuid}
|
||||||
|
|||||||
@@ -17,5 +17,8 @@ public interface BuildRepository extends JpaRepository<Build, Integer> {
|
|||||||
|
|
||||||
Page<Build> findByUserIdAndDeletedAtIsNullOrderByUpdatedAtDesc(Integer userId, Pageable pageable);
|
Page<Build> findByUserIdAndDeletedAtIsNullOrderByUpdatedAtDesc(Integer userId, Pageable pageable);
|
||||||
|
|
||||||
|
Optional<Build> findByUuidAndIsPublicTrueAndDeletedAtIsNull(UUID uuid);
|
||||||
|
|
||||||
Optional<Build> findByUuidAndDeletedAtIsNull(UUID uuid);
|
Optional<Build> findByUuidAndDeletedAtIsNull(UUID uuid);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -20,5 +20,7 @@ public interface BuildService {
|
|||||||
|
|
||||||
BuildDto updateMyBuild(UUID uuid, UpdateBuildRequest req);
|
BuildDto updateMyBuild(UUID uuid, UpdateBuildRequest req);
|
||||||
|
|
||||||
|
BuildDto getPublicBuild(UUID uuid);
|
||||||
|
|
||||||
void deleteMyBuild(UUID uuid);
|
void deleteMyBuild(UUID uuid);
|
||||||
}
|
}
|
||||||
@@ -112,6 +112,31 @@ public class BuildServiceImpl implements BuildService {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// Public build detail (/builds/{uuid})
|
||||||
|
// GET /api/v1/builds/public/{uuid}
|
||||||
|
// ---------------------------
|
||||||
|
@Override
|
||||||
|
public BuildDto getPublicBuild(UUID uuid) {
|
||||||
|
if (uuid == null) throw new IllegalArgumentException("uuid is required");
|
||||||
|
|
||||||
|
Build build = buildRepository.findByUuidAndDeletedAtIsNull(uuid)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Build not found"));
|
||||||
|
|
||||||
|
// Only allow public builds here (and not deleted)
|
||||||
|
if (!Boolean.TRUE.equals(build.getIsPublic())) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Build not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BuildItem> items = buildItemRepository.findByBuild_Id(build.getId());
|
||||||
|
|
||||||
|
BuildDto dto = toBuildDto(build, items);
|
||||||
|
hydrateBuildDtoItems(dto); // keep consistent with getMyBuild
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// Vault list (/builds/me)
|
// Vault list (/builds/me)
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
|
|||||||
@@ -7,7 +7,18 @@ public interface EmailService {
|
|||||||
|
|
||||||
EmailRequest sendEmailHtml(String recipient, String subject, String htmlBody, String textBody);
|
EmailRequest sendEmailHtml(String recipient, String subject, String htmlBody, String textBody);
|
||||||
|
|
||||||
EmailRequest sendEmailHtml(String recipient, String subject, String htmlBody, String textBody, String templateKey);
|
// ✅ convenience overload for templates
|
||||||
|
default EmailRequest sendEmailHtml(
|
||||||
|
String recipient,
|
||||||
|
String subject,
|
||||||
|
String htmlBody,
|
||||||
|
String textBody,
|
||||||
|
String templateKey
|
||||||
|
) {
|
||||||
|
EmailRequest req = sendEmailHtml(recipient, subject, htmlBody, textBody);
|
||||||
|
req.setTemplateKey(templateKey);
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
void deleteById(Integer id);
|
void deleteById(Integer id);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user