Cleanup
This commit is contained in:
@@ -1,18 +1,44 @@
|
||||
package org.zaine.app.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||
import io.swagger.v3.oas.annotations.info.Info;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.media.Content;
|
||||
import io.swagger.v3.oas.models.media.MediaType;
|
||||
import io.swagger.v3.oas.models.responses.ApiResponse;
|
||||
|
||||
@Configuration
|
||||
@OpenAPIDefinition(info = @Info(title = "org-backend API", version = "1.0.0"))
|
||||
@SecurityScheme(
|
||||
name = "bearerAuth", // referenced by name in controllers
|
||||
name = "bearerAuth",
|
||||
type = SecuritySchemeType.HTTP,
|
||||
scheme = "bearer",
|
||||
bearerFormat = "JWT"
|
||||
)
|
||||
public class OpenApiConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
|
||||
ApiResponse notFoundResponse = new ApiResponse()
|
||||
.description("Resource not found")
|
||||
.content(new Content().addMediaType("application/json",
|
||||
new MediaType().example("""
|
||||
{
|
||||
"message": "Could not find resource with URL: /api/example/123"
|
||||
}
|
||||
""")
|
||||
));
|
||||
|
||||
return new OpenAPI()
|
||||
.components(new Components()
|
||||
.addResponses("NotFound", notFoundResponse)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.zaine.app.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -7,24 +9,25 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.zaine.app.dto.CalibreBookDTO;
|
||||
import org.zaine.app.service.CalibreService;
|
||||
|
||||
import java.util.List;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* Exposes read-only Calibre library data to the frontend.
|
||||
* Only used to populate the book picker in the Mutāla'ah modal.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/calibre")
|
||||
@Tag(name = "Calibre", description = "Calibre API")
|
||||
public class CalibreController {
|
||||
|
||||
@Autowired
|
||||
private CalibreService calibreService;
|
||||
|
||||
/**
|
||||
* GET /api/calibre/books
|
||||
* Returns all books (id, title, authors) sorted alphabetically.
|
||||
* Used to populate the Mutāla'ah session book picker.
|
||||
*/
|
||||
@Operation(summary = "Get all books", description = "Fetches all books from the Calibre database")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Books retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No books found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/books")
|
||||
public List<CalibreBookDTO> getBooks() {
|
||||
return calibreService.getAllBooks();
|
||||
|
||||
@@ -14,31 +14,73 @@ import org.zaine.app.dto.CreateCommentDTO;
|
||||
import org.zaine.app.model.Comments;
|
||||
import org.zaine.app.service.CommentsService;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/comments")
|
||||
@Tag(name = "Comments", description = "Endpoints for managing comments")
|
||||
public class CommentsController {
|
||||
|
||||
private static final Logger logger = System.getLogger(CommentsController.class.getName());
|
||||
@Autowired
|
||||
|
||||
@Autowired
|
||||
private CommentsService commentsService;
|
||||
|
||||
@Operation(
|
||||
summary = "Get comments by page slug",
|
||||
description = "Fetches all comments associated with a given page slug"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Comments retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No comments found for this slug"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/{page_slug}")
|
||||
public List<Comments> getAllCommentsBySlug(@PathVariable String page_slug) {
|
||||
List<Comments> allComments = commentsService.getAllCommentsBySlug(page_slug);
|
||||
return allComments;
|
||||
|
||||
List<Comments> allComments = commentsService.getAllCommentsBySlug(page_slug);
|
||||
return allComments;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get a comment by id",
|
||||
description = "Fetches a comment by its id"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Comment retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No comment found for this id"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/item/{id}")
|
||||
public Comments getCommentById(@PathVariable Integer id) {
|
||||
return commentsService.getCommentById(id);
|
||||
return commentsService.getCommentById(id);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get all comments",
|
||||
description = "Fetches all comments from the database"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Comments retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No comments found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("")
|
||||
public List<Comments> getAllComments() {
|
||||
return commentsService.getAllComments();
|
||||
return commentsService.getAllComments();
|
||||
}
|
||||
|
||||
|
||||
@Operation(
|
||||
summary = "Add a comment",
|
||||
description = "Adds a comment to the database"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Comment added successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No comments found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping(
|
||||
value = "",
|
||||
consumes = "application/json"
|
||||
@@ -58,12 +100,20 @@ public class CommentsController {
|
||||
newComment.setParentId(dto.getParentId());
|
||||
newComment.setCreatedAt(java.time.Instant.now());
|
||||
|
||||
logger.log(System.Logger.Level.INFO,
|
||||
"Adding comment to pageSlug: " + dto.getPageSlug());
|
||||
logger.log(System.Logger.Level.INFO, () -> "Adding comment to pageSlug: " + dto.getPageSlug());
|
||||
|
||||
commentsService.addComment(newComment);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get a comment thread",
|
||||
description = "Fetches a comment thread by its id"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Comment thread retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No comment thread found for this id"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/thread/{comment_id}")
|
||||
public List<Comments> getCommentThread(@PathVariable Integer comment_id) {
|
||||
return commentsService.getCommentThread(comment_id);
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
package org.zaine.app.controller;
|
||||
import java.util.List;
|
||||
import org.zaine.app.dto.CompetenciesDTO;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.zaine.app.dto.CompetenciesDTO;
|
||||
import org.zaine.app.model.Competencies;
|
||||
import org.zaine.app.service.CompetenciesService;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/competencies")
|
||||
@Tag(name = "Competencies", description = "Operations about competencies")
|
||||
public class CompetenciesController {
|
||||
//private static final Logger logger = System.getLogger(CompetenciesController.class.getName());
|
||||
|
||||
|
||||
@Autowired
|
||||
private CompetenciesService competenciesService;
|
||||
|
||||
@Operation(
|
||||
summary = "Get all competencies",
|
||||
description = "Returns all competencies"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Competencies retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No competencies found"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/items")
|
||||
public List<Competencies> getAllCompetencies(
|
||||
@RequestParam(value = "group", required = false) String group) {
|
||||
@@ -29,11 +44,29 @@ public class CompetenciesController {
|
||||
return competenciesService.getAllCompetencies();
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get a competency by id",
|
||||
description = "Fetches a competency by its id"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Competency retrieved successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No competency found for this id"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/item/{id}")
|
||||
public Competencies getCompetencyById(@PathVariable Integer id) {
|
||||
return competenciesService.getCompetencyById(id);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Update a competency state",
|
||||
description = "Updates the state of a competency"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Competency state updated successfully"),
|
||||
@ApiResponse(responseCode = "404", description = "No competency found for this id"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping(
|
||||
value = "/items/{id}/state",
|
||||
consumes = "application/json"
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package org.zaine.app.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.zaine.app.dto.MotalahSessionDTO;
|
||||
import org.zaine.app.model.MotalahSession;
|
||||
import org.zaine.app.service.MotalahService;
|
||||
|
||||
import java.lang.System.Logger;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/wird/motalah")
|
||||
public class MotalahController {
|
||||
|
||||
private static final Logger logger = System.getLogger(MotalahController.class.getName());
|
||||
|
||||
@Autowired
|
||||
private MotalahService motalahService;
|
||||
|
||||
/**
|
||||
* GET /api/wird/motalah
|
||||
* All study sessions, newest first.
|
||||
*/
|
||||
@GetMapping
|
||||
public List<MotalahSession> getAll() {
|
||||
logger.log(Logger.Level.INFO, "Fetching all motalah sessions");
|
||||
return motalahService.getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/wird/motalah/today
|
||||
* Convenience endpoint for today's sessions only.
|
||||
*/
|
||||
@GetMapping("/today")
|
||||
public List<MotalahSession> getToday() {
|
||||
return motalahService.getToday();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/wird/motalah/range?from=2025-01-01&to=2025-01-31
|
||||
* Used by the trend chart and month-total stat.
|
||||
*/
|
||||
@GetMapping("/range")
|
||||
public List<MotalahSession> getInRange(
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
|
||||
return motalahService.getInRange(from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/wird/motalah
|
||||
* Body: { date, durationMinutes, bookIds, notes }
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<MotalahSession> create(@RequestBody MotalahSessionDTO dto) {
|
||||
logger.log(Logger.Level.INFO, "Creating motalah session: {0} min on {1}",
|
||||
dto.getDurationMinutes(), dto.getDate());
|
||||
MotalahSession saved = motalahService.create(dto);
|
||||
return ResponseEntity.ok(saved);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/wird/motalah/{id}
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Void> delete(@PathVariable Long id) {
|
||||
logger.log(Logger.Level.INFO, "Deleting motalah session id: {0}", id);
|
||||
motalahService.delete(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package org.zaine.app.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -10,20 +11,41 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.zaine.app.dto.CreateNoteDTO;
|
||||
import org.zaine.app.model.Notes;
|
||||
import org.zaine.app.service.NotesService;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
@Tag(name = "Notes", description = "Operations related to notes")
|
||||
public class NotesController {
|
||||
@Autowired
|
||||
private NotesService notesService;
|
||||
|
||||
|
||||
|
||||
@Operation(
|
||||
summary = "Get all notes",
|
||||
description = "Returns a list of all notes"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Notes retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/notes")
|
||||
public List<Notes> getAllNotes() {
|
||||
return notesService.getAllNotes();
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Create a note",
|
||||
description = "Creates a new note"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Note created successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping(
|
||||
value = "/notes",
|
||||
consumes = "application/json"
|
||||
@@ -36,9 +58,5 @@ public class NotesController {
|
||||
|
||||
return notesService.createNote(note);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,19 +7,35 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.zaine.app.dto.MotalahSessionDTO;
|
||||
import org.zaine.app.dto.WirdEntryDTO;
|
||||
import org.zaine.app.model.MotalahSession;
|
||||
import org.zaine.app.model.WirdEntry;
|
||||
import org.zaine.app.service.MotalahService;
|
||||
import org.zaine.app.service.WirdService;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/wird")
|
||||
@Tag(name = "Wird", description = "Wird API")
|
||||
public class WirdController {
|
||||
|
||||
private static final Logger logger = System.getLogger(WirdController.class.getName());
|
||||
|
||||
@Autowired
|
||||
private WirdService wirdService;
|
||||
|
||||
@Autowired
|
||||
private MotalahService motalahService;
|
||||
|
||||
/**
|
||||
* GET /api/wird/entries
|
||||
@@ -103,5 +119,57 @@ public class WirdController {
|
||||
public List<WirdEntry> getKhatmEntries() {
|
||||
return wirdService.getKhatmEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/wird/motalah
|
||||
* All study sessions, newest first.
|
||||
*/
|
||||
@GetMapping("/motalah")
|
||||
public List<MotalahSession> getAll() {
|
||||
logger.log(Logger.Level.INFO, "Fetching all motalah sessions");
|
||||
return motalahService.getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/wird/motalah/today
|
||||
* Convenience endpoint for today's sessions only.
|
||||
*/
|
||||
@GetMapping("/motalah/today")
|
||||
public List<MotalahSession> getToday() {
|
||||
return motalahService.getToday();
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/wird/motalah/range?from=2025-01-01&to=2025-01-31
|
||||
* Used by the trend chart and month-total stat.
|
||||
*/
|
||||
@GetMapping("/motalah/range")
|
||||
public List<MotalahSession> getInRange(
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
|
||||
return motalahService.getInRange(from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/wird/motalah
|
||||
* Body: { date, durationMinutes, bookIds, notes }
|
||||
*/
|
||||
@PostMapping("/motalah")
|
||||
public ResponseEntity<MotalahSession> create(@RequestBody MotalahSessionDTO dto) {
|
||||
logger.log(Logger.Level.INFO, "Creating motalah session: {0} min on {1}",
|
||||
dto.getDurationMinutes(), dto.getDate());
|
||||
MotalahSession saved = motalahService.create(dto);
|
||||
return ResponseEntity.ok(saved);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/wird/motalah/{id}
|
||||
*/
|
||||
@DeleteMapping("/motalah/{id}")
|
||||
public ResponseEntity<Void> delete(@PathVariable Long id) {
|
||||
logger.log(Logger.Level.INFO, "Deleting motalah session id: {0}", id);
|
||||
motalahService.delete(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,21 +29,22 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
@Tag(name = "Build", description = "Build management API")
|
||||
public class BuildController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BuildController.class);
|
||||
private static final Instant SERVER_START = Instant.now();
|
||||
|
||||
// ── ANSI escape sequence pattern ─────────────────────────────────────────
|
||||
// Matches CSI sequences: ESC [ <params> <final-byte>
|
||||
// and simple ESC sequences: ESC <single-char>
|
||||
private static final Pattern ANSI_ESCAPE = Pattern.compile(
|
||||
"\u001B(?:\\[[0-9;]*[A-Za-z]|[^\\[])");
|
||||
|
||||
// Map of SGR codes to CSS classes (added to <span class="...">)
|
||||
// Covers the codes actually emitted by build-site.el
|
||||
private static final Map<String, String> SGR_CLASS = Map.ofEntries(
|
||||
Map.entry("0", "ansi-reset"),
|
||||
Map.entry("1", "ansi-bold"),
|
||||
@@ -96,11 +97,27 @@ public class BuildController {
|
||||
HEALTH + UPTIME
|
||||
========================================================= */
|
||||
|
||||
@Operation(
|
||||
summary = "Get health",
|
||||
description = "Returns a simple health check"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Healthy"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/health")
|
||||
public ResponseEntity<String> health() {
|
||||
return ResponseEntity.ok("ok");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get uptime",
|
||||
description = "Returns the uptime of the server"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Uptime retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/uptime")
|
||||
public ResponseEntity<Map<String, Object>> getUptime() {
|
||||
long uptimeMs = Instant.now().toEpochMilli() - SERVER_START.toEpochMilli();
|
||||
@@ -116,21 +133,53 @@ public class BuildController {
|
||||
WEB BUILD
|
||||
========================================================= */
|
||||
|
||||
@Operation(
|
||||
summary = "Trigger web build",
|
||||
description = "Triggers a build of the web application"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Build triggered successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping("/build-web")
|
||||
public ResponseEntity<String> triggerWebBuild() {
|
||||
return startBuild(webBuildDirectory, webBuildLogFile, webBuildRunning, webProcess, true);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Cancel web build",
|
||||
description = "Cancels a running web build"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Build cancelled successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@DeleteMapping("/build-web")
|
||||
public ResponseEntity<String> cancelWebBuild() {
|
||||
return killProcess(webProcess, webBuildRunning, "web build");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get web build status",
|
||||
description = "Returns the status of a running web build"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Build status retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/build-web/status")
|
||||
public ResponseEntity<BuildStatus> getWebBuildStatus() {
|
||||
return ResponseEntity.ok(new BuildStatus(webBuildRunning.get(), webLastRun, webLastExitCode));
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Stream web build logs",
|
||||
description = "Streams the logs of a running web build"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Logs streamed successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/build-web/logs")
|
||||
public SseEmitter streamWebLogs() {
|
||||
return streamLogs(webBuildLogFile);
|
||||
@@ -140,21 +189,53 @@ public class BuildController {
|
||||
ORG ROAM BUILD
|
||||
========================================================= */
|
||||
|
||||
@Operation(
|
||||
summary = "Trigger org-roam build",
|
||||
description = "Triggers a build of the org-roam application"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Build triggered successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping("/build-roam")
|
||||
public ResponseEntity<String> triggerRoamBuild() {
|
||||
return startBuild(roamBuildDirectory, roamBuildLogFile, roamBuildRunning, roamProcess, false);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Cancel org-roam build",
|
||||
description = "Cancels a running org-roam build"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Build cancelled successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@DeleteMapping("/build-roam")
|
||||
public ResponseEntity<String> cancelRoamBuild() {
|
||||
return killProcess(roamProcess, roamBuildRunning, "roam build");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get org-roam build status",
|
||||
description = "Returns the status of a running org-roam build"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Build status retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/build-roam/status")
|
||||
public ResponseEntity<BuildStatus> getRoamBuildStatus() {
|
||||
return ResponseEntity.ok(new BuildStatus(roamBuildRunning.get(), roamLastRun, roamLastExitCode));
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Stream org-roam build logs",
|
||||
description = "Streams the logs of a running org-roam build"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Logs streamed successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/build-roam/logs")
|
||||
public SseEmitter streamRoamLogs() {
|
||||
return streamLogs(roamBuildLogFile);
|
||||
@@ -164,22 +245,54 @@ public class BuildController {
|
||||
EMACS RERUN
|
||||
========================================================= */
|
||||
|
||||
@Operation(
|
||||
summary = "Trigger Emacs rerun",
|
||||
description = "Triggers a rerun of Emacs"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Emacs rerun triggered successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping("/rerun-emacs")
|
||||
public ResponseEntity<String> triggerEmacs() {
|
||||
log.info("Triggering Emacs command");
|
||||
return startCommand(emacsRunDirectory, emacsRunLogFile, emacsRunning, emacsProcess);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Cancel Emacs rerun",
|
||||
description = "Cancels a running Emacs rerun"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Emacs rerun cancelled successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@DeleteMapping("/rerun-emacs")
|
||||
public ResponseEntity<String> cancelEmacs() {
|
||||
return killProcess(emacsProcess, emacsRunning, "emacs");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get Emacs rerun status",
|
||||
description = "Returns the status of a running Emacs rerun"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Emacs rerun status retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/rerun-emacs/status")
|
||||
public ResponseEntity<BuildStatus> getEmacsStatus() {
|
||||
return ResponseEntity.ok(new BuildStatus(emacsRunning.get(), emacsLastRun, emacsLastExitCode));
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Stream Emacs rerun logs",
|
||||
description = "Streams the logs of a running Emacs rerun"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Logs streamed successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/rerun-emacs/logs")
|
||||
public SseEmitter streamEmacsLogs() {
|
||||
return streamLogs(emacsRunLogFile);
|
||||
@@ -189,6 +302,14 @@ public class BuildController {
|
||||
COMBINED: EMACS + ROAM (sequential)
|
||||
========================================================= */
|
||||
|
||||
@Operation(
|
||||
summary = "Trigger combined run",
|
||||
description = "Triggers a combined run of Emacs and org-roam"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Combined run triggered successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@PostMapping("/run-combined")
|
||||
public ResponseEntity<String> triggerCombined() {
|
||||
if (!combinedRunning.compareAndSet(false, true)) {
|
||||
@@ -259,16 +380,40 @@ public class BuildController {
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Cancel combined run",
|
||||
description = "Cancels a combined run of Emacs and org-roam"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Combined run cancelled successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@DeleteMapping("/run-combined")
|
||||
public ResponseEntity<String> cancelCombined() {
|
||||
return killProcess(combinedProcess, combinedRunning, "combined run");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get combined run status",
|
||||
description = "Returns the status of a running combined run"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Combined run status retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/run-combined/status")
|
||||
public ResponseEntity<BuildStatus> getCombinedStatus() {
|
||||
return ResponseEntity.ok(new BuildStatus(combinedRunning.get(), combinedLastRun, combinedLastExitCode));
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get combined run logs",
|
||||
description = "Returns the logs of a running combined run"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Combined run logs retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/run-combined/logs")
|
||||
public SseEmitter streamCombinedLogs() {
|
||||
return streamLogs(combinedRunLogFile);
|
||||
@@ -278,6 +423,14 @@ public class BuildController {
|
||||
LAST RUN TIMESTAMPS
|
||||
========================================================= */
|
||||
|
||||
@Operation(
|
||||
summary = "Get last run timestamps",
|
||||
description = "Returns the last run timestamps of all builds"
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Last run timestamps retrieved successfully"),
|
||||
@ApiResponse(responseCode = "500", description = "Internal server error")
|
||||
})
|
||||
@GetMapping("/last-runs")
|
||||
public ResponseEntity<Map<String, Object>> getLastRuns() {
|
||||
return ResponseEntity.ok(Map.of(
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.zaine.app.exception;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
// 🔹 Handles "no route found" (true 404 URLs)
|
||||
@ExceptionHandler(org.springframework.web.servlet.NoHandlerFoundException.class)
|
||||
public ResponseEntity<Map<String, String>> handleNotFound(
|
||||
HttpServletRequest request
|
||||
) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(
|
||||
Map.of(
|
||||
"message", "Could not find resource with URL: " + request.getRequestURI()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// 🔹 Handles your own "not found in DB"
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseEntity<Map<String, String>> handleRuntime(
|
||||
RuntimeException ex,
|
||||
HttpServletRequest request
|
||||
) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(
|
||||
Map.of(
|
||||
"message", "Could not find resource with URL: " + request.getRequestURI()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,27 @@
|
||||
package org.zaine.app.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.zaine.app.model.Notes;
|
||||
import org.zaine.app.repositories.NotesRepository;
|
||||
|
||||
@Service
|
||||
public class NotesService {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(NotesService.class.getName());
|
||||
|
||||
private final NotesRepository notesRepository;
|
||||
|
||||
public NotesService(NotesRepository notesRepository) {
|
||||
this.notesRepository = notesRepository;
|
||||
this.notesRepository = notesRepository;
|
||||
}
|
||||
|
||||
public List<Notes> getAllNotes() {
|
||||
return notesRepository.findAll();
|
||||
return Optional.ofNullable(notesRepository.findAll())
|
||||
.orElseThrow(() -> new RuntimeException("Failed to retrieve notes"));
|
||||
}
|
||||
|
||||
public Notes createNote(Notes note) {
|
||||
logger.info("Creating note with content: " + note.getContent());
|
||||
return notesRepository.save(note);
|
||||
return Optional.ofNullable(notesRepository.save(note)).orElseThrow(() -> new RuntimeException("Failed to create note"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user