From 2927dbdbc5c996ad95984a53fe653c5ea257aeb1 Mon Sep 17 00:00:00 2001 From: lVentus Date: Fri, 29 Aug 2025 02:12:59 +0200 Subject: [PATCH 01/13] Dapr event processing --- api.md | 355 ++++++++++++++++++ build.gradle | 6 +- package-lock.json | 116 ++++++ package.json | 5 + .../controller/NotificationController.java | 4 +- .../controller/SubscriptionController.java | 33 ++ .../entity/NotificationEntity.java | 35 ++ .../entity/NotificationRecipientEntity.java | 40 ++ .../persistence/entity/RecipientStatus.java | 8 + .../persistence/entity/TemplateEntity.java | 22 -- .../mapper/NotificationMapper.java | 20 + .../persistence/mapper/TemplateMapper.java | 24 -- .../NotificationRecipientRepository.java | 30 ++ ...itory.java => NotificationRepository.java} | 9 +- .../service/CourseServiceClient.java | 32 ++ .../service/NotificationService.java | 185 +++++++++ .../service/TemplateService.java | 24 -- .../service/UserServiceClient.java | 57 +++ ...{schema.graphqls => notification.graphqls} | 16 +- .../NotificationServiceTest.java | 213 +++++++++++ ...plateForMicroservicesApplicationTests.java | 12 - 21 files changed, 1146 insertions(+), 100 deletions(-) create mode 100644 api.md create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/controller/SubscriptionController.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/entity/NotificationEntity.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/entity/NotificationRecipientEntity.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/entity/RecipientStatus.java delete mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/entity/TemplateEntity.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/mapper/NotificationMapper.java delete mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/mapper/TemplateMapper.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/repository/NotificationRecipientRepository.java rename src/main/java/de/unistuttgart/iste/meitrex/notification_service/persistence/repository/{TemplateRepository.java => NotificationRepository.java} (59%) create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/service/CourseServiceClient.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/service/NotificationService.java delete mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/service/TemplateService.java create mode 100644 src/main/java/de/unistuttgart/iste/meitrex/notification_service/service/UserServiceClient.java rename src/main/resources/graphql/service/{schema.graphqls => notification.graphqls} (58%) create mode 100644 src/test/java/de/unistuttgart/iste/meitrex/notification_service/NotificationServiceTest.java delete mode 100644 src/test/java/de/unistuttgart/iste/meitrex/template/TemplateForMicroservicesApplicationTests.java diff --git a/api.md b/api.md new file mode 100644 index 0000000..e79b1e8 --- /dev/null +++ b/api.md @@ -0,0 +1,355 @@ +# Notification Service API + +
+ Table of Contents + + * [Query](#query) + * [Objects](#objects) + * [PaginationInfo](#paginationinfo) + * [Template](#template) + * [Inputs](#inputs) + * [DateTimeFilter](#datetimefilter) + * [IntFilter](#intfilter) + * [Pagination](#pagination) + * [StringFilter](#stringfilter) + * [Enums](#enums) + * [SortDirection](#sortdirection) + * [Scalars](#scalars) + * [Boolean](#boolean) + * [Date](#date) + * [DateTime](#datetime) + * [ID](#id) + * [Int](#int) + * [LocalTime](#localtime) + * [String](#string) + * [Time](#time) + * [UUID](#uuid) + * [Url](#url) + +
+ +## Query + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
templates[Template]
+ +## Objects + +### PaginationInfo + +Return type for information about paginated results. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
pageInt! + +The current page number. + +
sizeInt! + +The number of elements per page. + +
totalElementsInt! + +The total number of elements across all pages. + +
totalPagesInt! + +The total number of pages. + +
hasNextBoolean! + +Whether there is a next page. + +
+ +### Template + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
idID!
nameString!
+ +## Inputs + +### DateTimeFilter + +Filter for date values. +If multiple filters are specified, they are combined with AND. + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
afterDateTime + +If specified, filters for dates after the specified value. + +
beforeDateTime + +If specified, filters for dates before the specified value. + +
+ +### IntFilter + +Filter for integer values. +If multiple filters are specified, they are combined with AND. + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
equalsInt + +An integer value to match exactly. + +
greaterThanInt + +If specified, filters for values greater than to the specified value. + +
lessThanInt + +If specified, filters for values less than to the specified value. + +
+ +### Pagination + +Specifies the page size and page number for paginated results. + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
pageInt! + +The page number, starting at 0. +If not specified, the default value is 0. +For values greater than 0, the page size must be specified. +If this value is larger than the number of pages, an empty page is returned. + +
sizeInt! + +The number of elements per page. + +
+ +### StringFilter + +Filter for string values. +If multiple filters are specified, they are combined with AND. + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
equalsString + +A string value to match exactly. + +
containsString + +A string value that must be contained in the field that is being filtered. + +
ignoreCaseBoolean! + +If true, the filter is case-insensitive. + +
+ +## Enums + +### SortDirection + +Specifies the sort direction, either ascending or descending. + + + + + + + + + + + + + + + + + + +
ValueDescription
ASC
DESC
+ +## Scalars + +### Boolean + +The `Boolean` scalar type represents `true` or `false`. + +### Date + +### DateTime + +### ID + +The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID. + +### Int + +The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. + +### LocalTime + +### String + +The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text. + +### Time + +### UUID + +### Url + diff --git a/build.gradle b/build.gradle index 7144f4a..7393f99 100644 --- a/build.gradle +++ b/build.gradle @@ -108,7 +108,7 @@ repositories { } dependencies { - implementation 'de.unistuttgart.iste.meitrex:meitrex-common:1.0.2' + implementation 'de.unistuttgart.iste.meitrex:meitrex-common:1.2.6' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-graphql' implementation 'org.springframework.boot:spring-boot-starter-validation' @@ -118,12 +118,14 @@ dependencies { implementation 'org.modelmapper:modelmapper:3.+' implementation 'com.graphql-java:graphql-java-extended-scalars:22.0' implementation 'com.graphql-java:graphql-java-extended-validation:22.0' + implementation 'io.dapr:dapr-sdk:1.9.0' // Dapr's core SDK with all features, except Actors. + implementation 'io.dapr:dapr-sdk-springboot:1.9.0' // Dapr's SDK integration with SpringBoot compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' annotationProcessor 'org.projectlombok:lombok' - testImplementation 'de.unistuttgart.iste.meitrex:meitrex-common-test:1.0.2' + testImplementation 'de.unistuttgart.iste.meitrex:meitrex-common-test:1.2.6' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework:spring-webflux' testImplementation 'org.springframework.graphql:spring-graphql-test' diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..48521e4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,116 @@ +{ + "name": "notification_service", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "graphql-markdown": "^7.3.0" + } + }, + "node_modules/deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==", + "license": "MIT" + }, + "node_modules/graphql": { + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", + "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-markdown": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/graphql-markdown/-/graphql-markdown-7.3.0.tgz", + "integrity": "sha512-xTgP+W156DD3k55KpwvNUtV7RTJmGKQhvCzseUXSnJf7KrZozhyyxhq4bv1IiOJgGeRjt5zwHBbEcAEEWCacrg==", + "license": "MIT", + "dependencies": { + "deep-diff": "^1.0.2", + "lodash.isplainobject": "^4.0.6", + "minimist": "^1.2.6", + "node-fetch": "^2.0.0", + "resolve-from": "^5.0.0" + }, + "bin": { + "graphql-markdown": "src/index.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.2 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..421e172 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "graphql-markdown": "^7.3.0" + } +} diff --git a/src/main/java/de/unistuttgart/iste/meitrex/notification_service/controller/NotificationController.java b/src/main/java/de/unistuttgart/iste/meitrex/notification_service/controller/NotificationController.java index 3f9f304..1d9b33b 100644 --- a/src/main/java/de/unistuttgart/iste/meitrex/notification_service/controller/NotificationController.java +++ b/src/main/java/de/unistuttgart/iste/meitrex/notification_service/controller/NotificationController.java @@ -1,7 +1,7 @@ package de.unistuttgart.iste.meitrex.notification_service.controller; import de.unistuttgart.iste.meitrex.generated.dto.Template; -import de.unistuttgart.iste.meitrex.notification_service.service.TemplateService; +import de.unistuttgart.iste.meitrex.notification_service.service.NotificationService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.graphql.data.method.annotation.QueryMapping; @@ -14,7 +14,7 @@ @RequiredArgsConstructor public class NotificationController { - private final TemplateService notificationService; + private final NotificationService notificationService; @QueryMapping public List