Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions api/calendar-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ components:
properties:
title:
type: string
pattern: '.*\S.*'
maxLength: 255
description:
type: string
startTime:
Expand Down
13 changes: 13 additions & 0 deletions api/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

components:
parameters:
id:

Check warning on line 17 in api/common.yaml

View workflow job for this annotation

GitHub Actions / Lint OpenAPI Specs

no-unused-components

Component: "id" is never used. Reference: https://redocly.com/docs/cli/rules/oas/no-unused-components
name: id
in: path
required: true
schema:
$ref: '#/components/schemas/Identifier/properties/id'
schemas:
Identifier:

Check warning on line 24 in api/common.yaml

View workflow job for this annotation

GitHub Actions / Lint OpenAPI Specs

no-unused-components

Component: "Identifier" is never used. Reference: https://redocly.com/docs/cli/rules/oas/no-unused-components
type: object
additionalProperties: true
properties:
Expand All @@ -30,6 +30,19 @@
format: int64
required:
- id
Timestamped:

Check warning on line 33 in api/common.yaml

View workflow job for this annotation

GitHub Actions / Lint OpenAPI Specs

no-unused-components

Component: "Timestamped" is never used. Reference: https://redocly.com/docs/cli/rules/oas/no-unused-components
type: object
additionalProperties: true
properties:
createdAt:
type: string
format: date-time
lastUpdatedAt:
type: string
format: date-time
required:
- createdAt
- lastUpdatedAt
securitySchemes:
# Only intended to be used for loginUser, as every other authorized endpoint should require a JWT
BasicAuth:
Expand Down
117 changes: 92 additions & 25 deletions api/note-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,56 @@ servers:
- url: /

paths:

/api/v1/notes:
get:
tags: [Notes]
summary: Get all notes for a user
operationId: getNotes
parameters:
- name: userId
in: query
required: true
schema:
type: integer
format: int64
security:
- JWTAuth: []
responses:
'200':
description: List of notes
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Note'
$ref: '#/components/schemas/ListNotesResponse'
'401':
description: Token either does not exist or is already expired
'500':
description: Unhandled error occurred

post:
tags: [Notes]
summary: Create a new note
operationId: createNote
security:
- JWTAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
$ref: '#/components/schemas/CreateNoteRequest'
responses:
'201':
description: Note created
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
$ref: '#/components/schemas/CreateNoteResponse'
'401':
description: Token either does not exist or is already expired
'500':
description: Unhandled error occurred

/api/v1/notes/{id}:
get:
tags: [Notes]
summary: Get a note by ID
operationId: getNoteById
security:
- JWTAuth: []
parameters:
- $ref: '#/components/parameters/id'
responses:
Expand All @@ -65,14 +69,22 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
$ref: '#/components/schemas/GetNoteResponse'
'401':
description: Token either does not exist or is already expired
'403':
description: Accessing note of someone else
'404':
description: Note not found
'500':
description: Unhandled error occurred

put:
tags: [Notes]
summary: Update a note's title and content
operationId: updateNote
security:
- JWTAuth: []
parameters:
- $ref: '#/components/parameters/id'
requestBody:
Expand All @@ -87,24 +99,40 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
$ref: '#/components/schemas/UpdateNoteResponse'
'401':
description: Token either does not exist or is already expired
'403':
description: Accessing note of someone else
'404':
description: Note not found
'500':
description: Unhandled error occurred

delete:
tags: [Notes]
summary: Delete a note by ID
operationId: deleteNote
security:
- JWTAuth: []
parameters:
- $ref: '#/components/parameters/id'
responses:
'204':
description: Note deleted
'401':
description: Token either does not exist or is already expired
'403':
description: Accessing note of someone else
'404':
description: Note not found
'500':
description: Unhandled error occurred

components:

securitySchemes:
JWTAuth:
$ref: './common.yaml#/components/securitySchemes/JWTAuth'
parameters:
id:
name: id
Expand All @@ -117,17 +145,56 @@ components:
schemas:
Note:
type: object
additionalProperties: true
properties:
id:
type: integer
format: int64
title:
type: string
pattern: '.*\S.*'
maxLength: 255
content:
type: string
createdAt:
type: string
format: date-time
lastUpdatedAt:
type: string
format: date-time
ListNotesResponse:
type: object
properties:
notes:
type: array
items:
$ref: "#/components/schemas/IdentifiedTimestampedNote"
required:
- notes
CreateNoteRequest:
allOf:
- $ref: '#/components/schemas/Note'
- type: object
required:
- title
- content
CreateNoteResponse:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateNoteResponse, GetNoteResponse, and UpdateNoteResponse wrap IdentifiedTimestampedNote in allOf with an empty type: object that adds no constraints.

allOf:
- $ref: '#/components/schemas/IdentifiedTimestampedNote'
GetNoteResponse:
allOf:
- $ref: "#/components/schemas/IdentifiedTimestampedNote"
UpdateNoteResponse:
allOf:
- $ref: "#/components/schemas/IdentifiedTimestampedNote"
IdentifiedNote:
type: object
allOf:
- $ref: './common.yaml#/components/schemas/Identifier'
- $ref: "#/components/schemas/Note"
required:
- id
- title
- content
IdentifiedTimestampedNote:
type: object
allOf:
- $ref: './common.yaml#/components/schemas/Timestamped'
- $ref: "#/components/schemas/IdentifiedNote"
required:
- id
- title
- content
- createdAt
- lastUpdatedAt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -30,6 +32,8 @@ public class CalendarEvent {
@Column(name = "user_id", nullable = false)
private Long userId;

@NotBlank
@Size(max = 255)
@Column(nullable = false)
private String title;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package de.tum.devopss26.calendarservice.exception;

import de.tum.devopss26.shared.exception.ForbiddenException;
import org.jspecify.annotations.NonNull;

public class IllegalCalendarEventAccessException extends ForbiddenException {

public IllegalCalendarEventAccessException(long accessorId, IllegalAccessPair pair) {
super(accessorId + " tried to illegally access calendar event " + pair.eventId + " of owner " + pair.ownerId);
}
public IllegalCalendarEventAccessException(long accessorId, IllegalAccessPair pair) {
super(accessorId + " tried to illegally access calendar event " + pair.eventId + " of owner " + pair.ownerId);
}

public record IllegalAccessPair(long ownerId, long eventId) {

@Override
public @NonNull String toString() {
return "(" + ownerId + ", " + eventId + ")";
}
}
public record IllegalAccessPair(long ownerId, long eventId) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import de.tum.devopss26.calendarservice.entity.CalendarEvent;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.openapitools.model.*;

import java.util.List;
Expand All @@ -16,6 +17,7 @@ public interface CalendarEventMapper {

// Specific mappers

@Mapping(target = "userId", source = "userId")
CalendarEvent toCalendarEvent(CreateCalendarEventRequest request, long userId);

CreateCalendarEventResponse toCreateResponse(CalendarEvent event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Optional;

import static de.tum.devopss26.calendarservice.exception.IllegalCalendarEventAccessException.IllegalAccessPair;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
Expand All @@ -22,13 +23,15 @@ class CalendarEventServiceImpl implements CalendarEventService {
private final CalendarEventRepository repository;
private final CalendarEventMapper mapper;

@Transactional
@Override
public CreateCalendarEventResponse createEvent(CreateCalendarEventRequest request, long userId) {
CalendarEvent event = mapper.toCalendarEvent(request, userId);
event = repository.save(event);
return mapper.toCreateResponse(event);
}

@Transactional(readOnly = true)
@Override
public ListCalendarEventResponse getEvents(long userId) {
List<CalendarEvent> eventEntities = repository.findAllByUserId(userId);
Expand All @@ -54,13 +57,15 @@ public ListCalendarEventResponse getEvents(long userId) {
return event;
}

@Transactional(readOnly = true)
@Override
public GetCalendarEventResponse getEvent(long userId, long eventId) {
CalendarEvent event = getEventEntity(userId, eventId);

return mapper.toGetResponse(event);
}

@Transactional
@Override
public UpdateCalendarEventResponse updateEvent(long userId, long eventId,
org.openapitools.model.CalendarEvent diff) {
Expand Down Expand Up @@ -92,6 +97,7 @@ public UpdateCalendarEventResponse updateEvent(long userId, long eventId,
return mapper.toUpdateResponse(event);
}

@Transactional
@Override
public void deleteEvent(long userId, long eventId) {
CalendarEvent event = getEventEntity(userId, eventId);
Expand Down
22 changes: 22 additions & 0 deletions services/note-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
<artifactId>micrometer-registry-prometheus</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa-test</artifactId>
Expand All @@ -91,6 +96,12 @@
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.oai</groupId>
<artifactId>openapi-request-validator-mockmvc</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
Expand All @@ -116,6 +127,7 @@
<directory>${project.basedir}/../../api</directory>
<includes>
<include>note-service.yaml</include>
<include>common.yaml</include>
</includes>
</testResource>
</testResources>
Expand Down Expand Up @@ -145,6 +157,16 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Expand Down
Loading
Loading