diff --git a/libs/core/readme.md b/libs/core/readme.md
index dc7e55a5..e72e09e4 100644
--- a/libs/core/readme.md
+++ b/libs/core/readme.md
@@ -1,55 +1,196 @@
-# Core Library
+# @jArc/core
-Core library contains following Models, entity listeners and repositories
-### Models
-* SoftDeleteEntity - has fields such as (deleted, deletedBy, deletedOn) related to soft delete functionality
-* BaseEntity - extends SoftDeleteEntity
-* UserModifiableEntity - extends BaseEntity
+## Overview
-## Installation
+`jarc-core` is the [application core](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/) for the `sourceloop`. It contains
-## Usage
-```
-// YourApplication.java
-package your.package;
-
-....
-
-@SpringBootApplication
-// to include core library and your package
-@ComponentScan({ "your.package", "com.sourcefuse.jarc.core" })
-// to change base repository class to core library softDeletesRepository from core
-@EnableJpaRepositories(repositoryBaseClass = SoftDeletesRepositoryImpl.class)
-public class AuthenticationAuditApplication {
- ...
-}
-```
+- adapters
+- awares
+- constants
+- dtos
+- entitylisteners
+- exeption
+- filters
+- models
+- repositories
+- utils
-```
-// YourRepository.java
-package your.package.repositories;
+that are used throughout the service catalog.
-...
+### Usage
+- Add the `jarc-core` in dependencies (in `pom.xml`).
+ ```xml
+
+ ...
+
+ com.sourcefuse.jarc
+ jarc-core
+ 0.0.1-SNAPSHOT
+
+
+ ```
+- Add `jarc-core` pacakge in component scan in your application
+ ```java
+ package com.example;
-public interface YourRepository extends SoftDeletesRepository {
+ import org.springframework.boot.SpringApplication;
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
+ import org.springframework.context.annotation.ComponentScan;
-}
+ @SpringBootApplication
+ @ComponentScan(
+ {
+ "com.example",
+ "com.sourcefuse.jarc.core"
+ }
+ )
+ public class ExampleApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+
+ }
+ ```
+
+### Adapters
+- refer [this](https://github.com/sourcefuse/j-arc/tree/master/libs/core/src/main/java/com/sourcefuse/jarc/core/adapters) to check all the adapters provided in here.
+#### LocalDateTimeTypeAdapter
+- The `LocalDateTimeTypeAdapter` class is a custom implementation of the `TypeAdapter` class from the `Gson library`. It is specifically designed to handle `serialization` and `deserialization` of `LocalDateTime` objects.
+- Usage
+```java
+ Gson gson = new GsonBuilder()
+ .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter())
+ .create();
```
+### Constants
+- refer [this](https://github.com/sourcefuse/j-arc/tree/master/libs/core/src/main/java/com/sourcefuse/jarc/core/constants) to check all the constants provided in here.
+
+### DTO's
+- DTO stands for data transfer object. As the name suggests, a DTO is an object made to transfer data
+- The `jarc-core` DTO's includes
+ - `CountResponse`
+ - This DTO has only one field which is count.
+ - You can use this DTO when you have to send total count of some thing in response.
+ - Usage
+ ```java
+ @RestController
+ public class YourController{
+ @Autowire
+ YourRepository yourRepository;
+ ...
+ @GetMapping("/count")
+ @PreAuthorize("isAuthenticated()")
+ public ResponseEntity count() {
+ Long count = yourRepository.count();
+ return new ResponseEntity<>(
+ new CountResponse(count),
+ HttpStatus.OK
+ );
+ }
+ }
+ ```
+ - `ErrorDetails`
+ - This DTO has three fields which are timestamp, message and details.
+ - You can use this DTO when you have to send response containing error message and description.
+ - Usage
+ ```java
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ exception.getMessage(),
+ webRequest.getDescription(false)
+ );
+ return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+ ```
+- refer [this](https://github.com/sourcefuse/j-arc/tree/master/libs/core/src/main/java/com/sourcefuse/jarc/core/dtos) to check all the dtos provided in here.
+
+### Entity Listners
+- There Following entity listeners are there in `jarc-core`.
+ - AuditLogEntityListener
+ - You can use this entity listener for auditing the entity, when actions like insert, update and delete on entity it will insert the log in database
+ - Usage
+ ```java
+ @Entity
+ @EntityListeners(SoftDeleteEntityListener.class)
+ public class YourModel{
+ // properties
+ }
+ ```
+ - SoftDeleteEntityListener
+ - This entity listener is being used in `SoftDeleteEntity`, This entity listener is responsible for adding the `deletedOn` timestamp and `deletedBy` user id when the entity gets soft deleted.
+ - refer [this](https://github.com/sourcefuse/j-arc/blob/master/libs/core/src/main/java/com/sourcefuse/jarc/core/models/base/SoftDeleteEntity.java) to check how `SoftDeleteEntityListener` is being used.
+### Enums
+
+- Enums helps in defining a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases for both numeric and string-based enums.
+
+- refer [this](https://github.com/sourcefuse/j-arc/tree/master/libs/core/src/main/java/com/sourcefuse/jarc/core/enums) to check all the dtos provided in here.
+
+### Exeption
+- The `jarc-core` exception contains custom exception class and global exception handler.
+- `CommonRuntimeException` and `ResourceNotFoundException` these are custom exception class. You can use this exception class to throw the exception
+- `GlobalExceptionHandler`: this class catch the various exceptions and send the appropriate response with ErrorDetails as response body and Http Status code to the user.
+
+### Filter
+- You can use `QueryService` for filtering the query result.
+- `QueryService` has two methods
+ ```java
+ public List executeQuery(String filterJson, Class entityClass) {
+ ...
+ }
+ public List executeQuery(Filter filter, Class entityClass) {
+ ...
+ }
+ ```
+- Usage
+```java
+ @Autowired
+ QueryService queryService;
+
+ /**
+ * String query = "{\"where\":{\"name\":{\"eq\":\"User\"}}}"
+ */
+ public List getUsersByQuery(String query){
+ return this.queryService.executeQuery(query, User.class);
+ }
+
+ /**
+ *
+ * Filter filter = new Filter();
+ * Map fieldsOperation = new HashMap();
+ * fieldsOperation.put("eq", "User");
+ * filter.getWhere().put("name", fieldsOperation);
+ *
+ */
+ public List getUsersByQuery(Filter filter){
+ return this.queryService.executeQuery(filter, User.class);
+ }
```
-// YourModel.java
-package your.package.models;
+For more example of executeQuery refer QueryService Test cases [here](https://github.com/sourcefuse/j-arc/blob/master/libs/core/src/test/java/com/sourcefuse/jarc/core/QueryServiceTests.java)
+
+### Models
+- Base
+ - `UserModifiableEntity`, `BaseEntity`, `SoftDeletedEntity`, `BaseAuthUser`
+ - In order to use models provided, in your application:
+ - Extend your model class with `UserModifiableEntity` class provided in `jarc-core` that will add following attributes to the model Class
+ - createdBy
+ - modifiedBy
+ - createdOn
+ - modifiedOn
+ - deleted
+ - deletedBy
+ - deletedOn
+ - Extend your model class with `SoftDeletedEntity` class provided in `jarc-core` that will add following attributes to the model Class
+ - deleted
+ - deletedBy
+ - deletedOn
-...
+### Repository
+- A `SoftDeleteRepository` is a custom repository implementation that provides soft delete functionality using JPA (Java Persistence API) and the JpaRepository interface. Soft delete refers to the concept of marking records as deleted instead of physically removing them from the database.
+- refer [this](https://github.com/sourcefuse/j-arc/blob/master/libs/core/src/main/java/com/sourcefuse/jarc/core/repositories/SoftDeletesRepository.java) for provided methods accessing soft deleted entities or hard deleting.
-// add entity listner if you want to log all activities such as
-// update/save/delete for YourModel log will be saved in audit_logs table
-// which resides in schema logs
-@EntityListeners(AuditLogEntityListener.class)
+### Utils
+- The CommonUtils class is a utility class that provides common helper methods for various tasks. One of the methods in the CommonUtils class is `getNullProperties(Object source)`.
-public class YourModel extends UserModifiableEntity {
- ...
-}
-```
\ No newline at end of file
+- The `getNullProperties(Object source)` method is used to retrieve a list of property names that have null values from a given object (source). This method is typically used when you want to identify which properties of an object are currently null.
\ No newline at end of file
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/constants/AuditPermissions.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/constants/AuditPermissions.java
new file mode 100644
index 00000000..d41d0b4b
--- /dev/null
+++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/constants/AuditPermissions.java
@@ -0,0 +1,11 @@
+package com.sourcefuse.jarc.core.constants;
+
+public final class AuditPermissions {
+
+ public static final String VIEW_AUDIT = "VIEW_AUDIT";
+ public static final String CREATE_AUDIT = "CREATE_AUDIT";
+ public static final String UPDATE_AUDIT = "UPDATE_AUDIT";
+ public static final String DELETE_AUDIT = "DELETE_AUDIT";
+
+ private AuditPermissions() {}
+}
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/constants/NotificationPermissions.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/constants/NotificationPermissions.java
new file mode 100644
index 00000000..59bd7f41
--- /dev/null
+++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/constants/NotificationPermissions.java
@@ -0,0 +1,13 @@
+package com.sourcefuse.jarc.core.constants;
+
+public final class NotificationPermissions {
+
+ public static final String VIEW_NOTIFICATION = "VIEW_NOTIFICATION";
+ public static final String CREATE_NOTIFICATION = "CREATE_NOTIFICATION";
+ public static final String UPDATE_NOTIFICATION = "UPDATE_NOTIFICATION";
+ public static final String DELETE_NOTIFICATION = "DELETE_NOTIFICATION";
+ public static final String CAN_GET_NOTIFICATION_ACCESS =
+ "CAN_GET_NOTIFICATION_ACCESS";
+
+ private NotificationPermissions() {}
+}
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/dtos/CountResponse.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/dtos/CountResponse.java
index cee9d894..47702ac0 100644
--- a/libs/core/src/main/java/com/sourcefuse/jarc/core/dtos/CountResponse.java
+++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/dtos/CountResponse.java
@@ -1,18 +1,17 @@
package com.sourcefuse.jarc.core.dtos;
+
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CountResponse {
+
private Long count;
}
-
-
-
-
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/enums/ContentTypes.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/enums/ContentTypes.java
deleted file mode 100644
index 669f078a..00000000
--- a/libs/core/src/main/java/com/sourcefuse/jarc/core/enums/ContentTypes.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.sourcefuse.jarc.core.enums;
-
-public enum ContentTypes {
- APPLICATION_JSON("application/json");
-
- private final String name;
-
- ContentTypes(String value) {
- this.name = value;
- }
-
- public String value() {
- return this.name;
- }
-
- @Override
- public String toString() {
- return name;
- }
-}
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/models/audit/AuditLog.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/models/audit/AuditLog.java
index de404bc8..1ef34ce5 100644
--- a/libs/core/src/main/java/com/sourcefuse/jarc/core/models/audit/AuditLog.java
+++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/models/audit/AuditLog.java
@@ -1,6 +1,10 @@
package com.sourcefuse.jarc.core.models.audit;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.sourcefuse.jarc.core.enums.AuditActions;
+import com.sourcefuse.jarc.core.serializers.JsonBDeserializer;
+import com.sourcefuse.jarc.core.serializers.JsonBSerializer;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
@@ -55,9 +59,13 @@ public class AuditLog {
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb")
+ @JsonSerialize(using = JsonBSerializer.class)
+ @JsonDeserialize(using = JsonBDeserializer.class)
private Object before;
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb")
+ @JsonSerialize(using = JsonBSerializer.class)
+ @JsonDeserialize(using = JsonBDeserializer.class)
private Object after;
}
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/serializers/JsonBDeserializer.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/serializers/JsonBDeserializer.java
new file mode 100644
index 00000000..c65c4391
--- /dev/null
+++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/serializers/JsonBDeserializer.java
@@ -0,0 +1,25 @@
+package com.sourcefuse.jarc.core.serializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import java.io.IOException;
+
+public class JsonBDeserializer extends StdDeserializer {
+
+ private static final long serialVersionUID = 8558133505323154005L;
+
+ public JsonBDeserializer() {
+ super(Object.class);
+ }
+
+ @Override
+ public Object deserialize(JsonParser p, DeserializationContext ctxt)
+ throws IOException {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode node = p.getCodec().readTree(p);
+ return mapper.writeValueAsString(node);
+ }
+}
diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/serializers/JsonBSerializer.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/serializers/JsonBSerializer.java
new file mode 100644
index 00000000..ebeddfd8
--- /dev/null
+++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/serializers/JsonBSerializer.java
@@ -0,0 +1,24 @@
+package com.sourcefuse.jarc.core.serializers;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import java.io.IOException;
+
+public class JsonBSerializer extends JsonSerializer {
+
+ @Override
+ public void serialize(
+ Object value,
+ JsonGenerator gen,
+ SerializerProvider serializers
+ ) throws IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Object jsonObject = value;
+ if (value instanceof String) {
+ jsonObject = objectMapper.readValue(value.toString(), Object.class);
+ }
+ objectMapper.writeValue(gen, jsonObject);
+ }
+}
diff --git a/libs/core/src/test/java/com/sourcefuse/jarc/core/constants/TestConstants.java b/libs/core/src/test/java/com/sourcefuse/jarc/core/constants/TestConstants.java
index fb328119..d93596a7 100644
--- a/libs/core/src/test/java/com/sourcefuse/jarc/core/constants/TestConstants.java
+++ b/libs/core/src/test/java/com/sourcefuse/jarc/core/constants/TestConstants.java
@@ -33,6 +33,15 @@ public static EntityManager clearTables(EntityManager entityManager) {
}
public static void setCurrentLoggedInUser() {
+ CurrentUser currentUser = createMockCurrentUser();
+ // Create an authentication object with the dummy user and set it in the
+ // SecurityContext
+ UsernamePasswordAuthenticationToken auth =
+ new UsernamePasswordAuthenticationToken(currentUser, null, null);
+ SecurityContextHolder.getContext().setAuthentication(auth);
+ }
+
+ public static CurrentUser createMockCurrentUser() {
// Create a dummy user object
CurrentUser currentUser = new CurrentUser();
currentUser.setId(mockUserId);
@@ -41,10 +50,6 @@ public static void setCurrentLoggedInUser() {
currentUser.setEmail("dummy.user@example.com");
currentUser.setUsername("dummy.user@example.com");
- // Create an authentication object with the dummy user and set it in the
- // SecurityContext
- UsernamePasswordAuthenticationToken auth =
- new UsernamePasswordAuthenticationToken(currentUser, null, null);
- SecurityContextHolder.getContext().setAuthentication(auth);
+ return currentUser;
}
}
diff --git a/libs/jarc-auth-lib/pom.xml b/libs/jarc-auth-lib/pom.xml
index 6f3bb11c..2cb4123c 100644
--- a/libs/jarc-auth-lib/pom.xml
+++ b/libs/jarc-auth-lib/pom.xml
@@ -35,6 +35,22 @@
org.springframework.boot
spring-boot-starter-security
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.5
+ runtime
com.sourcefuse.jarc
diff --git a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/config/SecurityConfig.java b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/config/SecurityConfig.java
index 41f9f67a..b2114d8f 100644
--- a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/config/SecurityConfig.java
+++ b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/config/SecurityConfig.java
@@ -1,30 +1,84 @@
package com.sourcefuse.jarc.authlib.config;
import com.sourcefuse.jarc.authlib.security.JwtAuthenticationFilter;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableMethodSecurity
-@AllArgsConstructor
+@RequiredArgsConstructor
public class SecurityConfig {
+ private static final String SWAGGER_ROLE = "SWAGGER";
+
+ @Value("${springdoc.swagger-ui.path:/swagger-ui}")
+ String swaggerUiPath;
+
+ @Value("${springdoc.api-docs.path:/v3/api-docs}")
+ String swaggerDocsPath;
+
+ @Value("${swagger.auth.username:#{null}}")
+ String swaggerUsername;
+
+ @Value("${swagger.auth.password:#{null}}")
+ String swaggerPassword;
+
private final JwtAuthenticationFilter authenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http.csrf().disable();
-
- http.addFilterBefore(
- authenticationFilter,
- UsernamePasswordAuthenticationFilter.class
- );
+ http
+ .authorizeHttpRequests()
+ .requestMatchers(
+ swaggerDocsPath + "/**",
+ swaggerUiPath + "/**",
+ "/swagger-ui/**"
+ )
+ .hasAnyRole(SWAGGER_ROLE)
+ .and()
+ .authenticationManager(authManager(http));
+ http
+ .authorizeHttpRequests()
+ .anyRequest()
+ .permitAll()
+ .and()
+ .formLogin()
+ .and()
+ .addFilterBefore(
+ authenticationFilter,
+ UsernamePasswordAuthenticationFilter.class
+ );
return http.build();
}
+
+ public AuthenticationManager authManager(HttpSecurity http) throws Exception {
+ AuthenticationManagerBuilder authenticationManagerBuilder =
+ http.getSharedObject(AuthenticationManagerBuilder.class);
+ if (
+ swaggerUsername != null &&
+ !swaggerUsername.isBlank() &&
+ swaggerPassword != null &&
+ !swaggerPassword.isBlank()
+ ) {
+ authenticationManagerBuilder
+ .inMemoryAuthentication()
+ .withUser(swaggerUsername)
+ .password(new BCryptPasswordEncoder().encode(swaggerPassword))
+ .roles(SWAGGER_ROLE)
+ .and()
+ .passwordEncoder(new BCryptPasswordEncoder());
+ }
+ return authenticationManagerBuilder.build();
+ }
}
diff --git a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/providers/JwtTokenDecryptProvider.java b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/providers/JwtTokenDecryptProvider.java
index 654b1abb..eab52959 100644
--- a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/providers/JwtTokenDecryptProvider.java
+++ b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/providers/JwtTokenDecryptProvider.java
@@ -1,13 +1,7 @@
package com.sourcefuse.jarc.authlib.providers;
-import java.security.Key;
-import com.sourcefuse.jarc.authlib.Utils;
-import io.jsonwebtoken.io.Decoders;
-import io.jsonwebtoken.security.Keys;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Component;
-
+import com.sourcefuse.jarc.authlib.utils.JwtUtils;
+import com.sourcefuse.jarc.authlib.utils.Utils;
import com.sourcefuse.jarc.core.constants.AuthConstants;
import com.sourcefuse.jarc.core.exception.CommonRuntimeException;
import com.sourcefuse.jarc.core.models.session.CurrentUser;
@@ -16,9 +10,11 @@
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
-
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
@RequiredArgsConstructor
@Component
@@ -27,15 +23,12 @@ public class JwtTokenDecryptProvider {
@Value("${app.jwt-secret}")
private String jwtSecret;
- private Key key() {
- return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
- }
public CurrentUser getUserDetails(String token) {
try {
Claims claims = Jwts
.parserBuilder()
- .setSigningKey(key())
+ .setSigningKey(JwtUtils.key(jwtSecret))
.build()
.parseClaimsJws(token)
.getBody();
diff --git a/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/security/CustomJwtBuilder.java b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/CustomJwtBuilder.java
similarity index 73%
rename from services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/security/CustomJwtBuilder.java
rename to libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/CustomJwtBuilder.java
index faed2004..0fc7f37b 100644
--- a/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/security/CustomJwtBuilder.java
+++ b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/CustomJwtBuilder.java
@@ -1,15 +1,15 @@
-package com.sourcefuse.jarc.services.authservice.security;
-
-import com.sourcefuse.jarc.services.authservice.Utils;
+package com.sourcefuse.jarc.authlib.security;
+import com.sourcefuse.jarc.authlib.utils.Utils;
import io.jsonwebtoken.impl.DefaultJwtBuilder;
import io.jsonwebtoken.io.SerializationException;
import lombok.SneakyThrows;
public class CustomJwtBuilder extends DefaultJwtBuilder {
- /**
- * @deprecated
- */
+
+ /**
+ * @deprecated
+ */
@SneakyThrows
@Override
@Deprecated(since = "1.11.0", forRemoval = true)
diff --git a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/JwtAuthenticationFilter.java b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/JwtAuthenticationFilter.java
index db076796..9e54a9dc 100644
--- a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/JwtAuthenticationFilter.java
+++ b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/security/JwtAuthenticationFilter.java
@@ -1,10 +1,15 @@
-
package com.sourcefuse.jarc.authlib.security;
+
+import com.sourcefuse.jarc.authlib.providers.JwtTokenDecryptProvider;
+import com.sourcefuse.jarc.core.models.session.CurrentUser;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-
-import com.sourcefuse.jarc.authlib.providers.JwtTokenDecryptProvider;
+import lombok.AllArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -14,14 +19,6 @@
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
-import com.sourcefuse.jarc.core.models.session.CurrentUser;
-
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.AllArgsConstructor;
-
@AllArgsConstructor
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@@ -42,12 +39,8 @@ protected void doFilterInternal(
for (String permission : user.getPermissions()) {
listAuthorities.add(new SimpleGrantedAuthority(permission));
}
- UsernamePasswordAuthenticationToken authenticationToken =
- new UsernamePasswordAuthenticationToken(
- user,
- null,
- listAuthorities
- );
+ UsernamePasswordAuthenticationToken authenticationToken =
+ new UsernamePasswordAuthenticationToken(user, null, listAuthorities);
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
diff --git a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/utils/JwtUtils.java b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/utils/JwtUtils.java
new file mode 100644
index 00000000..805dc5f5
--- /dev/null
+++ b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/utils/JwtUtils.java
@@ -0,0 +1,38 @@
+package com.sourcefuse.jarc.authlib.utils;
+
+import com.sourcefuse.jarc.authlib.security.CustomJwtBuilder;
+import com.sourcefuse.jarc.core.constants.AuthConstants;
+import com.sourcefuse.jarc.core.models.session.CurrentUser;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import java.security.Key;
+import java.util.Date;
+
+public final class JwtUtils {
+
+ private JwtUtils() {}
+
+ public static String generateAccessToken(
+ String jwtSecret,
+ Long jwtExpirationDate,
+ CurrentUser currentUser
+ ) {
+ Date currentDate = new Date();
+ Date expireDate = new Date();
+ expireDate.setTime(currentDate.getTime() + jwtExpirationDate);
+ Claims claims = Jwts.claims().setSubject(currentUser.getUsername());
+ claims.put(AuthConstants.CURRENT_USER_KEY, currentUser);
+ return new CustomJwtBuilder()
+ .setClaims(claims)
+ .setIssuedAt(currentDate)
+ .setExpiration(expireDate)
+ .signWith(key(jwtSecret))
+ .compact();
+ }
+
+ public static Key key(String jwtSecret) {
+ return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
+ }
+}
diff --git a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/Utils.java b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/utils/Utils.java
similarity index 92%
rename from libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/Utils.java
rename to libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/utils/Utils.java
index 461c7ecb..a7d17a2a 100644
--- a/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/Utils.java
+++ b/libs/jarc-auth-lib/src/main/java/com/sourcefuse/jarc/authlib/utils/Utils.java
@@ -1,4 +1,4 @@
-package com.sourcefuse.jarc.authlib;
+package com.sourcefuse.jarc.authlib.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@@ -6,6 +6,7 @@
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
public final class Utils {
+
private Utils() {}
public static ObjectMapper getObjectMapperInstance() {
diff --git a/libs/jarc-auth-lib/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/libs/jarc-auth-lib/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 00000000..f4a0dc51
--- /dev/null
+++ b/libs/jarc-auth-lib/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,12 @@
+{"properties": [
+ {
+ "name": "swagger.auth.username",
+ "type": "java.lang.String",
+ "description": "Username to access Swagger UI"
+ },
+ {
+ "name": "swagger.auth.password",
+ "type": "java.lang.String",
+ "description": "Password to access Swagger UI"
+ }
+]}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 14731371..56a08744 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,11 @@
services/feature-toggle-service
services/notification-service
services/user-tenant-service
+
+ sandbox/notification-javamailer-example
+ sandbox/notification-pubnub-example
+ sandbox/notification-twilio-example
+ sandbox/audit-service-example
diff --git a/sandbox/audit-service-example/.gitignore b/sandbox/audit-service-example/.gitignore
new file mode 100644
index 00000000..549e00a2
--- /dev/null
+++ b/sandbox/audit-service-example/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/sandbox/audit-service-example/.mvn/wrapper/maven-wrapper.jar b/sandbox/audit-service-example/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 00000000..cb28b0e3
Binary files /dev/null and b/sandbox/audit-service-example/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/sandbox/audit-service-example/.mvn/wrapper/maven-wrapper.properties b/sandbox/audit-service-example/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..b27a13f1
--- /dev/null
+++ b/sandbox/audit-service-example/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
diff --git a/sandbox/audit-service-example/mvnw b/sandbox/audit-service-example/mvnw
new file mode 100755
index 00000000..66df2854
--- /dev/null
+++ b/sandbox/audit-service-example/mvnw
@@ -0,0 +1,308 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "$(uname)" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+ else
+ JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+ JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+ if $darwin ; then
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f "\"$javaExecutable\"")"
+ fi
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(cd "$wdir/.." || exit 1; pwd)
+ fi
+ # end of workaround
+ done
+ printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ # Remove \r in case we run on Windows within Git Bash
+ # and check out the repository with auto CRLF management
+ # enabled. Otherwise, we may read lines that are delimited with
+ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+ # splitting rules.
+ tr -s '\r\n' ' ' < "$1"
+ fi
+}
+
+log() {
+ if [ "$MVNW_VERBOSE" = true ]; then
+ printf '%s\n' "$1"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+ log "Found $wrapperJarPath"
+else
+ log "Couldn't find $wrapperJarPath, downloading it ..."
+
+ if [ -n "$MVNW_REPOURL" ]; then
+ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ else
+ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ fi
+ while IFS="=" read -r key value; do
+ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+ safeValue=$(echo "$value" | tr -d '\r')
+ case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+ esac
+ done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+ log "Downloading from: $wrapperUrl"
+
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget > /dev/null; then
+ log "Found wget ... using wget"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ log "Found curl ... using curl"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ else
+ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ fi
+ else
+ log "Falling back to using Java to download"
+ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaSource=$(cygpath --path --windows "$javaSource")
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaSource" ]; then
+ if [ ! -e "$javaClass" ]; then
+ log " - Compiling MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/javac" "$javaSource")
+ fi
+ if [ -e "$javaClass" ]; then
+ log " - Running MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+ case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+ esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+ wrapperSha256Result=false
+ if command -v sha256sum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ elif command -v shasum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+ exit 1
+ fi
+ if [ $wrapperSha256Result = false ]; then
+ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/sandbox/audit-service-example/mvnw.cmd b/sandbox/audit-service-example/mvnw.cmd
new file mode 100644
index 00000000..95ba6f54
--- /dev/null
+++ b/sandbox/audit-service-example/mvnw.cmd
@@ -0,0 +1,205 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %WRAPPER_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+ powershell -Command "&{"^
+ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+ " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+ " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+ " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+ " exit 1;"^
+ "}"^
+ "}"
+ if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/sandbox/audit-service-example/pom.xml b/sandbox/audit-service-example/pom.xml
new file mode 100644
index 00000000..40f1bd19
--- /dev/null
+++ b/sandbox/audit-service-example/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.5
+
+
+ com.example
+ audit-service-example
+ 0.0.1-SNAPSHOT
+ audit-service-example
+ Audit Service example
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.sourcefuse.jarc.services
+ audit-service
+ 0.0.1-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/sandbox/audit-service-example/src/main/java/com/example/auditserviceexample/AuditServiceExampleApplication.java b/sandbox/audit-service-example/src/main/java/com/example/auditserviceexample/AuditServiceExampleApplication.java
new file mode 100644
index 00000000..2282a7b6
--- /dev/null
+++ b/sandbox/audit-service-example/src/main/java/com/example/auditserviceexample/AuditServiceExampleApplication.java
@@ -0,0 +1,19 @@
+package com.example.auditserviceexample;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(
+ {
+ "com.example.auditserviceexample",
+ "com.sourcefuse.jarc.services.auditservice"
+ }
+)
+public class AuditServiceExampleApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AuditServiceExampleApplication.class, args);
+ }
+}
diff --git a/sandbox/audit-service-example/src/main/resources/application.properties b/sandbox/audit-service-example/src/main/resources/application.properties
new file mode 100644
index 00000000..5322db5f
--- /dev/null
+++ b/sandbox/audit-service-example/src/main/resources/application.properties
@@ -0,0 +1,22 @@
+
+### datasource config (required)
+spring.datasource.url=jdbc:postgresql://localhost:5432/
+spring.datasource.username=
+spring.datasource.password=
+spring.jpa.show-sql=true
+
+### to auto migrate the db as per models
+spring.jpa.hibernate.ddl-auto = update
+
+### Optimization for POSTGRES queries
+#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect
+
+spring.liquibase.enabled=false
+
+server.port=8004
+
+app.jwt-secret= daf66e01593f61a15b857cf433aae03a005812b31234e149036bcc8dee755dbb
+app-jwt-expiration-milliseconds= 21600000
+
+swagger.auth.username= swagger
+swagger.auth.password= swagger
diff --git a/sandbox/audit-service-example/src/test/java/com/example/auditserviceexample/AuditServiceExampleApplicationTests.java b/sandbox/audit-service-example/src/test/java/com/example/auditserviceexample/AuditServiceExampleApplicationTests.java
new file mode 100644
index 00000000..8d078418
--- /dev/null
+++ b/sandbox/audit-service-example/src/test/java/com/example/auditserviceexample/AuditServiceExampleApplicationTests.java
@@ -0,0 +1,15 @@
+package com.example.auditserviceexample;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class AuditServiceExampleApplicationTests {
+
+ @Test
+ void contextLoads() {
+ assertTrue(true);
+ }
+}
diff --git a/sandbox/notification-javamailer-example/.gitignore b/sandbox/notification-javamailer-example/.gitignore
new file mode 100644
index 00000000..549e00a2
--- /dev/null
+++ b/sandbox/notification-javamailer-example/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/sandbox/notification-javamailer-example/.mvn/wrapper/maven-wrapper.jar b/sandbox/notification-javamailer-example/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 00000000..cb28b0e3
Binary files /dev/null and b/sandbox/notification-javamailer-example/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/sandbox/notification-javamailer-example/.mvn/wrapper/maven-wrapper.properties b/sandbox/notification-javamailer-example/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..b27a13f1
--- /dev/null
+++ b/sandbox/notification-javamailer-example/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
diff --git a/sandbox/notification-javamailer-example/mvnw b/sandbox/notification-javamailer-example/mvnw
new file mode 100755
index 00000000..66df2854
--- /dev/null
+++ b/sandbox/notification-javamailer-example/mvnw
@@ -0,0 +1,308 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "$(uname)" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+ else
+ JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+ JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+ if $darwin ; then
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f "\"$javaExecutable\"")"
+ fi
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(cd "$wdir/.." || exit 1; pwd)
+ fi
+ # end of workaround
+ done
+ printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ # Remove \r in case we run on Windows within Git Bash
+ # and check out the repository with auto CRLF management
+ # enabled. Otherwise, we may read lines that are delimited with
+ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+ # splitting rules.
+ tr -s '\r\n' ' ' < "$1"
+ fi
+}
+
+log() {
+ if [ "$MVNW_VERBOSE" = true ]; then
+ printf '%s\n' "$1"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+ log "Found $wrapperJarPath"
+else
+ log "Couldn't find $wrapperJarPath, downloading it ..."
+
+ if [ -n "$MVNW_REPOURL" ]; then
+ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ else
+ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ fi
+ while IFS="=" read -r key value; do
+ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+ safeValue=$(echo "$value" | tr -d '\r')
+ case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+ esac
+ done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+ log "Downloading from: $wrapperUrl"
+
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget > /dev/null; then
+ log "Found wget ... using wget"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ log "Found curl ... using curl"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ else
+ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ fi
+ else
+ log "Falling back to using Java to download"
+ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaSource=$(cygpath --path --windows "$javaSource")
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaSource" ]; then
+ if [ ! -e "$javaClass" ]; then
+ log " - Compiling MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/javac" "$javaSource")
+ fi
+ if [ -e "$javaClass" ]; then
+ log " - Running MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+ case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+ esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+ wrapperSha256Result=false
+ if command -v sha256sum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ elif command -v shasum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+ exit 1
+ fi
+ if [ $wrapperSha256Result = false ]; then
+ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/sandbox/notification-javamailer-example/mvnw.cmd b/sandbox/notification-javamailer-example/mvnw.cmd
new file mode 100644
index 00000000..95ba6f54
--- /dev/null
+++ b/sandbox/notification-javamailer-example/mvnw.cmd
@@ -0,0 +1,205 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %WRAPPER_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+ powershell -Command "&{"^
+ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+ " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+ " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+ " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+ " exit 1;"^
+ "}"^
+ "}"
+ if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/sandbox/notification-javamailer-example/pom.xml b/sandbox/notification-javamailer-example/pom.xml
new file mode 100644
index 00000000..d67584cd
--- /dev/null
+++ b/sandbox/notification-javamailer-example/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.5
+
+
+ com.notification.example
+ javamailer
+ 0.0.1-SNAPSHOT
+ javamailer
+ Notification Service example of javamailer
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.sourcefuse.jarc.services
+ notification-service
+ 0.0.1-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/sandbox/notification-javamailer-example/src/main/java/com/notification/example/javamailer/JavamailerApplication.java b/sandbox/notification-javamailer-example/src/main/java/com/notification/example/javamailer/JavamailerApplication.java
new file mode 100644
index 00000000..b14b4458
--- /dev/null
+++ b/sandbox/notification-javamailer-example/src/main/java/com/notification/example/javamailer/JavamailerApplication.java
@@ -0,0 +1,19 @@
+package com.notification.example.javamailer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(
+ {
+ "com.notification.example.javamailer",
+ "com.sourcefuse.jarc.services.notificationservice"
+ }
+)
+public class JavamailerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(JavamailerApplication.class, args);
+ }
+}
diff --git a/sandbox/notification-javamailer-example/src/main/java/com/notification/example/javamailer/configs/JavaMailerConfig.java b/sandbox/notification-javamailer-example/src/main/java/com/notification/example/javamailer/configs/JavaMailerConfig.java
new file mode 100644
index 00000000..1854d30d
--- /dev/null
+++ b/sandbox/notification-javamailer-example/src/main/java/com/notification/example/javamailer/configs/JavaMailerConfig.java
@@ -0,0 +1,65 @@
+package com.notification.example.javamailer.configs;
+
+import com.sourcefuse.jarc.services.notificationservice.providers.email.types.MailConnectionConfig;
+import java.util.Properties;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.stereotype.Service;
+
+@Service
+public class JavaMailerConfig implements MailConnectionConfig {
+
+ @Value("${spring.mail.host}")
+ private String host;
+
+ @Value("${spring.mail.port}")
+ private int port;
+
+ @Value("${spring.mail.username}")
+ private String username;
+
+ @Value("${spring.mail.password}")
+ private String password;
+
+ @Value("${notification.config.sender-mail:#{null}}")
+ private String senderMail;
+
+ @Value("${notification.config.send-to-multiple-receivers:#{false}}")
+ private Boolean sendToMultipleReceivers;
+
+ public JavaMailerConfig() {
+ // for sonar
+ }
+
+ private JavaMailSender javaMailSender() {
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setHost(host);
+ mailSender.setPort(port);
+ mailSender.setUsername(username);
+ mailSender.setPassword(password);
+
+ Properties properties = new Properties();
+ properties.put("mail.smtp.auth", "true");
+ properties.put("mail.smtp.starttls.enable", "true");
+ properties.put("mail.smtp.ssl.trust", "smtp.gmail.com");
+
+ mailSender.setJavaMailProperties(properties);
+ return mailSender;
+ }
+
+ @Override
+ public JavaMailSender getJavaMailSender() {
+ return javaMailSender();
+ }
+
+ @Override
+ public String getSenderMail() {
+ return senderMail;
+ }
+
+ @Override
+ public boolean shouldSendToMultipleReceivers() {
+ return sendToMultipleReceivers;
+ }
+}
diff --git a/sandbox/notification-javamailer-example/src/main/resources/application.properties b/sandbox/notification-javamailer-example/src/main/resources/application.properties
new file mode 100644
index 00000000..c4002e0a
--- /dev/null
+++ b/sandbox/notification-javamailer-example/src/main/resources/application.properties
@@ -0,0 +1,33 @@
+spring.mail.host=
+spring.mail.port=
+spring.mail.username=
+spring.mail.password=
+notification.config.send-to-multiple-receivers = true
+
+notification.provider.email = JavaMailerProvider
+
+server.port= 8001
+
+### datasource config (required)
+
+spring.datasource.url=jdbc:postgresql://localhost:5432/
+spring.datasource.username=
+spring.datasource.password=
+
+spring.jpa.show-sql= true
+
+spring.jpa.hibernate.ddl-auto= update
+spring.jpa.properties.hibernat.dialect= org.hibernate.dialect.PostgreSQLDialect
+spring.liquibase.enabled=false
+
+spring.data.redis.host= localhost
+spring.data.redis.port= 6379
+spring.data.redis.password=
+
+app.jwt-secret=daf66e01593f61a15b857cf433aae03a005812b31234e149036bcc8dee755dbb
+app-jwt-expiration-milliseconds=21600000
+
+swagger.auth.username= swagger
+swagger.auth.password= swagger
\ No newline at end of file
diff --git a/sandbox/notification-javamailer-example/src/test/java/com/notification/example/javamailer/JavamailerApplicationTests.java b/sandbox/notification-javamailer-example/src/test/java/com/notification/example/javamailer/JavamailerApplicationTests.java
new file mode 100644
index 00000000..6c5700ba
--- /dev/null
+++ b/sandbox/notification-javamailer-example/src/test/java/com/notification/example/javamailer/JavamailerApplicationTests.java
@@ -0,0 +1,15 @@
+package com.notification.example.javamailer;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class JavamailerApplicationTests {
+
+ @Test
+ void contextLoads() {
+ assertTrue(true);
+ }
+}
diff --git a/sandbox/notification-pubnub-example/.gitignore b/sandbox/notification-pubnub-example/.gitignore
new file mode 100644
index 00000000..549e00a2
--- /dev/null
+++ b/sandbox/notification-pubnub-example/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/sandbox/notification-pubnub-example/.mvn/wrapper/maven-wrapper.jar b/sandbox/notification-pubnub-example/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 00000000..cb28b0e3
Binary files /dev/null and b/sandbox/notification-pubnub-example/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/sandbox/notification-pubnub-example/.mvn/wrapper/maven-wrapper.properties b/sandbox/notification-pubnub-example/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..b27a13f1
--- /dev/null
+++ b/sandbox/notification-pubnub-example/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
diff --git a/sandbox/notification-pubnub-example/mvnw b/sandbox/notification-pubnub-example/mvnw
new file mode 100755
index 00000000..66df2854
--- /dev/null
+++ b/sandbox/notification-pubnub-example/mvnw
@@ -0,0 +1,308 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "$(uname)" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+ else
+ JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+ JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+ if $darwin ; then
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f "\"$javaExecutable\"")"
+ fi
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(cd "$wdir/.." || exit 1; pwd)
+ fi
+ # end of workaround
+ done
+ printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ # Remove \r in case we run on Windows within Git Bash
+ # and check out the repository with auto CRLF management
+ # enabled. Otherwise, we may read lines that are delimited with
+ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+ # splitting rules.
+ tr -s '\r\n' ' ' < "$1"
+ fi
+}
+
+log() {
+ if [ "$MVNW_VERBOSE" = true ]; then
+ printf '%s\n' "$1"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+ log "Found $wrapperJarPath"
+else
+ log "Couldn't find $wrapperJarPath, downloading it ..."
+
+ if [ -n "$MVNW_REPOURL" ]; then
+ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ else
+ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ fi
+ while IFS="=" read -r key value; do
+ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+ safeValue=$(echo "$value" | tr -d '\r')
+ case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+ esac
+ done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+ log "Downloading from: $wrapperUrl"
+
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget > /dev/null; then
+ log "Found wget ... using wget"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ log "Found curl ... using curl"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ else
+ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ fi
+ else
+ log "Falling back to using Java to download"
+ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaSource=$(cygpath --path --windows "$javaSource")
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaSource" ]; then
+ if [ ! -e "$javaClass" ]; then
+ log " - Compiling MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/javac" "$javaSource")
+ fi
+ if [ -e "$javaClass" ]; then
+ log " - Running MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+ case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+ esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+ wrapperSha256Result=false
+ if command -v sha256sum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ elif command -v shasum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+ exit 1
+ fi
+ if [ $wrapperSha256Result = false ]; then
+ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/sandbox/notification-pubnub-example/mvnw.cmd b/sandbox/notification-pubnub-example/mvnw.cmd
new file mode 100644
index 00000000..95ba6f54
--- /dev/null
+++ b/sandbox/notification-pubnub-example/mvnw.cmd
@@ -0,0 +1,205 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %WRAPPER_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+ powershell -Command "&{"^
+ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+ " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+ " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+ " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+ " exit 1;"^
+ "}"^
+ "}"
+ if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/sandbox/notification-pubnub-example/pom.xml b/sandbox/notification-pubnub-example/pom.xml
new file mode 100644
index 00000000..f8ea3967
--- /dev/null
+++ b/sandbox/notification-pubnub-example/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.5
+
+
+ com.notification.example
+ pubnub
+ 0.0.1-SNAPSHOT
+ pubnub
+ Notification Service example of pubnub
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.sourcefuse.jarc.services
+ notification-service
+ 0.0.1-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/sandbox/notification-pubnub-example/src/main/java/com/notification/example/pubnub/PubnubApplication.java b/sandbox/notification-pubnub-example/src/main/java/com/notification/example/pubnub/PubnubApplication.java
new file mode 100644
index 00000000..e2349f37
--- /dev/null
+++ b/sandbox/notification-pubnub-example/src/main/java/com/notification/example/pubnub/PubnubApplication.java
@@ -0,0 +1,19 @@
+package com.notification.example.pubnub;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(
+ {
+ "com.notification.example.pubnub",
+ "com.sourcefuse.jarc.services.notificationservice"
+ }
+)
+public class PubnubApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(PubnubApplication.class, args);
+ }
+}
diff --git a/sandbox/notification-pubnub-example/src/main/java/com/notification/example/pubnub/config/PubNubConfig.java b/sandbox/notification-pubnub-example/src/main/java/com/notification/example/pubnub/config/PubNubConfig.java
new file mode 100644
index 00000000..389b1b06
--- /dev/null
+++ b/sandbox/notification-pubnub-example/src/main/java/com/notification/example/pubnub/config/PubNubConfig.java
@@ -0,0 +1,48 @@
+package com.notification.example.pubnub.config;
+
+import com.pubnub.api.PNConfiguration;
+import com.pubnub.api.PubNub;
+import com.sourcefuse.jarc.services.notificationservice.providers.push.pubnub.types.PubNubConnectionConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PubNubConfig implements PubNubConnectionConfig {
+
+ private final PubNub pubNub;
+
+ @Value("${pubnub.apns2.env:}")
+ String pubnunApns2Env;
+
+ @Value("${pubnub.apns2.bundle-id:}")
+ String pubnunApns2BundleId;
+
+ public PubNubConfig(
+ @Value("${pubnub.publish-key}") String publishKey,
+ @Value("${pubnub.subscribe-key}") String subscribeKey,
+ @Value("${pubnub.secrete-key}") String secreteKey,
+ @Value("${pubnub.app-uuid}") String appUuid
+ ) {
+ PNConfiguration pnConfiguration = new PNConfiguration();
+ pnConfiguration.setPublishKey(publishKey);
+ pnConfiguration.setSubscribeKey(subscribeKey);
+ pnConfiguration.setUuid(appUuid);
+ pnConfiguration.setSecretKey(secreteKey);
+ this.pubNub = new PubNub(pnConfiguration);
+ }
+
+ @Override
+ public PubNub getPubNub() {
+ return pubNub;
+ }
+
+ @Override
+ public String getPubNubApns2Env() {
+ return this.pubnunApns2Env;
+ }
+
+ @Override
+ public String getPubNubApns2BundleId() {
+ return this.pubnunApns2BundleId;
+ }
+}
diff --git a/sandbox/notification-pubnub-example/src/main/resources/application.properties b/sandbox/notification-pubnub-example/src/main/resources/application.properties
new file mode 100644
index 00000000..33ab6e18
--- /dev/null
+++ b/sandbox/notification-pubnub-example/src/main/resources/application.properties
@@ -0,0 +1,35 @@
+pubnub.apns2.env=
+pubnub.apns2.bundle-id=
+
+pubnub.publish-key=
+pubnub.subscribe-key=
+pubnub.secrete-key=
+pubnub.app-uuid=
+
+
+notification.provider.push = PubNubProvider
+
+
+server.port= 8002
+
+### datasource config (required)
+
+spring.datasource.url=jdbc:postgresql://localhost:5432/
+spring.datasource.username=
+spring.datasource.password=
+
+spring.jpa.show-sql= true
+
+spring.jpa.hibernate.ddl-auto= update
+spring.jpa.properties.hibernat.dialect= org.hibernate.dialect.PostgreSQLDialect
+spring.liquibase.enabled=false
+
+spring.data.redis.host= localhost
+spring.data.redis.port= 6379
+spring.data.redis.password=
+
+app.jwt-secret=daf66e01593f61a15b857cf433aae03a005812b31234e149036bcc8dee755dbb
+app-jwt-expiration-milliseconds=21600000
+
+swagger.auth.username= swagger
+swagger.auth.password= swagger
\ No newline at end of file
diff --git a/sandbox/notification-pubnub-example/src/test/java/com/notification/example/pubnub/PubnubApplicationTests.java b/sandbox/notification-pubnub-example/src/test/java/com/notification/example/pubnub/PubnubApplicationTests.java
new file mode 100644
index 00000000..afa4401a
--- /dev/null
+++ b/sandbox/notification-pubnub-example/src/test/java/com/notification/example/pubnub/PubnubApplicationTests.java
@@ -0,0 +1,15 @@
+package com.notification.example.pubnub;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class PubnubApplicationTests {
+
+ @Test
+ void contextLoads() {
+ assertTrue(true);
+ }
+}
diff --git a/sandbox/notification-twilio-example/.gitignore b/sandbox/notification-twilio-example/.gitignore
new file mode 100644
index 00000000..549e00a2
--- /dev/null
+++ b/sandbox/notification-twilio-example/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/sandbox/notification-twilio-example/.mvn/wrapper/maven-wrapper.jar b/sandbox/notification-twilio-example/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 00000000..cb28b0e3
Binary files /dev/null and b/sandbox/notification-twilio-example/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/sandbox/notification-twilio-example/.mvn/wrapper/maven-wrapper.properties b/sandbox/notification-twilio-example/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..b27a13f1
--- /dev/null
+++ b/sandbox/notification-twilio-example/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
diff --git a/sandbox/notification-twilio-example/mvnw b/sandbox/notification-twilio-example/mvnw
new file mode 100755
index 00000000..66df2854
--- /dev/null
+++ b/sandbox/notification-twilio-example/mvnw
@@ -0,0 +1,308 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "$(uname)" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+ else
+ JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+ JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+ if $darwin ; then
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f "\"$javaExecutable\"")"
+ fi
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(cd "$wdir/.." || exit 1; pwd)
+ fi
+ # end of workaround
+ done
+ printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ # Remove \r in case we run on Windows within Git Bash
+ # and check out the repository with auto CRLF management
+ # enabled. Otherwise, we may read lines that are delimited with
+ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+ # splitting rules.
+ tr -s '\r\n' ' ' < "$1"
+ fi
+}
+
+log() {
+ if [ "$MVNW_VERBOSE" = true ]; then
+ printf '%s\n' "$1"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+ log "Found $wrapperJarPath"
+else
+ log "Couldn't find $wrapperJarPath, downloading it ..."
+
+ if [ -n "$MVNW_REPOURL" ]; then
+ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ else
+ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ fi
+ while IFS="=" read -r key value; do
+ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+ safeValue=$(echo "$value" | tr -d '\r')
+ case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+ esac
+ done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+ log "Downloading from: $wrapperUrl"
+
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget > /dev/null; then
+ log "Found wget ... using wget"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ log "Found curl ... using curl"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ else
+ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ fi
+ else
+ log "Falling back to using Java to download"
+ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaSource=$(cygpath --path --windows "$javaSource")
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaSource" ]; then
+ if [ ! -e "$javaClass" ]; then
+ log " - Compiling MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/javac" "$javaSource")
+ fi
+ if [ -e "$javaClass" ]; then
+ log " - Running MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+ case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+ esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+ wrapperSha256Result=false
+ if command -v sha256sum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ elif command -v shasum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+ exit 1
+ fi
+ if [ $wrapperSha256Result = false ]; then
+ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/sandbox/notification-twilio-example/mvnw.cmd b/sandbox/notification-twilio-example/mvnw.cmd
new file mode 100644
index 00000000..95ba6f54
--- /dev/null
+++ b/sandbox/notification-twilio-example/mvnw.cmd
@@ -0,0 +1,205 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Apache Maven Wrapper startup batch script, version 3.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %WRAPPER_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+ powershell -Command "&{"^
+ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+ " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+ " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+ " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+ " exit 1;"^
+ "}"^
+ "}"
+ if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/sandbox/notification-twilio-example/pom.xml b/sandbox/notification-twilio-example/pom.xml
new file mode 100644
index 00000000..c2360ed3
--- /dev/null
+++ b/sandbox/notification-twilio-example/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.5
+
+
+ com.notification.example
+ twilio
+ 0.0.1-SNAPSHOT
+ twilio
+ Notification Service example of twilio
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.sourcefuse.jarc.services
+ notification-service
+ 0.0.1-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/sandbox/notification-twilio-example/src/main/java/com/notification/example/twilio/TwilioApplication.java b/sandbox/notification-twilio-example/src/main/java/com/notification/example/twilio/TwilioApplication.java
new file mode 100644
index 00000000..e0a12edc
--- /dev/null
+++ b/sandbox/notification-twilio-example/src/main/java/com/notification/example/twilio/TwilioApplication.java
@@ -0,0 +1,19 @@
+package com.notification.example.twilio;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+@ComponentScan(
+ {
+ "com.notification.example.twilio",
+ "com.sourcefuse.jarc.services.notificationservice"
+ }
+)
+public class TwilioApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TwilioApplication.class, args);
+ }
+}
diff --git a/sandbox/notification-twilio-example/src/main/java/com/notification/example/twilio/config/TwilioConfig.java b/sandbox/notification-twilio-example/src/main/java/com/notification/example/twilio/config/TwilioConfig.java
new file mode 100644
index 00000000..6b336baa
--- /dev/null
+++ b/sandbox/notification-twilio-example/src/main/java/com/notification/example/twilio/config/TwilioConfig.java
@@ -0,0 +1,43 @@
+package com.notification.example.twilio.config;
+
+import com.sourcefuse.jarc.services.notificationservice.providers.sms.twilio.types.TwilioConnectionConfig;
+import com.twilio.Twilio;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TwilioConfig implements TwilioConnectionConfig {
+
+ @Value("${twilio.sms-from}")
+ String smsFrom;
+
+ @Value("${twilio.whatsapp-from}")
+ String whatsappFrom;
+
+ public TwilioConfig(
+ @Value("${twilio.account-sid}") String accountSid,
+ @Value("${twilio.auth-token}") String authToken
+ ) {
+ Twilio.init(accountSid, authToken);
+ }
+
+ @Override
+ public String getSmsFrom() {
+ return this.smsFrom;
+ }
+
+ @Override
+ public String getWhatsappFrom() {
+ return this.whatsappFrom;
+ }
+
+ @Override
+ public String getSmsStatusCallback() {
+ return null;
+ }
+
+ @Override
+ public String getWhatsappStatusCallback() {
+ return null;
+ }
+}
diff --git a/sandbox/notification-twilio-example/src/main/resources/application.properties b/sandbox/notification-twilio-example/src/main/resources/application.properties
new file mode 100644
index 00000000..7c54f5e2
--- /dev/null
+++ b/sandbox/notification-twilio-example/src/main/resources/application.properties
@@ -0,0 +1,30 @@
+twilio.account-sid=
+twilio.auth-token=
+twilio.sms-from=
+twilio.whatsapp-from=
+
+notification.provider.sms = TwilioProvider
+
+server.port= 8003
+
+### datasource config (required)
+
+spring.datasource.url=jdbc:postgresql://localhost:5432/
+spring.datasource.username=
+spring.datasource.password=
+
+spring.jpa.show-sql= true
+
+spring.jpa.hibernate.ddl-auto= update
+spring.jpa.properties.hibernat.dialect= org.hibernate.dialect.PostgreSQLDialect
+spring.liquibase.enabled=false
+
+spring.data.redis.host= localhost
+spring.data.redis.port= 6379
+spring.data.redis.password=
+
+app.jwt-secret=daf66e01593f61a15b857cf433aae03a005812b31234e149036bcc8dee755dbb
+app-jwt-expiration-milliseconds=21600000
+
+swagger.auth.username= swagger
+swagger.auth.password= swagger
\ No newline at end of file
diff --git a/sandbox/notification-twilio-example/src/test/java/com/notification/example/twilio/TwilioApplicationTests.java b/sandbox/notification-twilio-example/src/test/java/com/notification/example/twilio/TwilioApplicationTests.java
new file mode 100644
index 00000000..6d748d39
--- /dev/null
+++ b/sandbox/notification-twilio-example/src/test/java/com/notification/example/twilio/TwilioApplicationTests.java
@@ -0,0 +1,15 @@
+package com.notification.example.twilio;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class TwilioApplicationTests {
+
+ @Test
+ void contextLoads() {
+ assertTrue(true);
+ }
+}
diff --git a/services/audit-service/README.md b/services/audit-service/README.md
new file mode 100644
index 00000000..ed3a573e
--- /dev/null
+++ b/services/audit-service/README.md
@@ -0,0 +1,123 @@
+# @jArc/audit-service
+
+## Overview
+
+A LoopBack microservice used for auditing user actions. All the user actions like insert, update and delete can be audited.
+
+## Usage
+
+- Add the `audit-service` in dependencies (in `pom.xml`).
+ ```xml
+
+ ...
+
+ com.sourcefuse.jarc.services
+ audit-service
+ 0.0.1-SNAPSHOT
+
+
+ ```
+- Add `audit-service` pacakge in component scan in your application
+ ```java
+ package com.example;
+
+ import org.springframework.boot.SpringApplication;
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
+ import org.springframework.context.annotation.ComponentScan;
+
+ @SpringBootApplication
+ @ComponentScan(
+ {
+ "com.example",
+ "com.sourcefuse.jarc.services.auditservice"
+ }
+ )
+ public class ExampleApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ExampleApplication.class, args);
+ }
+
+ }
+ ```
+ - Start the application
+
+### Creating Logs
+
+The logs in this service can either be created through the REST endpoint.
+
+All the different types of action that are logged are
+
+```java
+public enum AuditActions {
+ SAVE("SAVE"),
+ UPDATE("UPDATE"),
+ DELETE("DELETE");
+ private final String name;
+
+ AuditActions(String value) {
+ this.name = value;
+ }
+
+ public String value() {
+ return this.name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
+```
+
+### Application properties
+
+Do not forget to set Application properties. The examples below show a common configuration for a PostgreSQL Database running locally. (in `src/main/resources/application.properties`).
+```properties
+ spring.datasource.username=pg_service_user
+ spring.datasource.password=pg_service_user_password
+ spring.datasource.url=jdbc:postgresql://localhost:5432/notification_db
+ spring.jpa.show-sql= false
+
+ spring.jpa.hibernate.ddl-auto= update
+ spring.jpa.properties.hibernat.dialect= org.hibernate.dialect.PostgreSQLDialect
+ spring.liquibase.enabled= false
+
+```
+| Name | Required | Default Value | Description |
+| ------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| spring.datasource.username | Y | | Login username of the database. |
+| spring.datasource.password | Y | | Login password of the database. |
+| spring.datasource.url | Y | | JDBC URL of the database. |
+| spring.jpa.show-sql | N | false | Whether to enable logging of SQL statements. |
+| spring.jpa.hibernate.ddl-auto | N | | DDL mode |
+| spring.jpa.properties.hibernat.dialect | Y | | Dialect in Hibernate class. |
+| spring.liquibase.enabled | N | true | Whether to enable Liquibase support. |
+| app.jwt-secret | Y | | JWT Secrete should be in Base64 Format |
+| app-jwt-expiration-milliseconds | Y | | JWT token expiration in milliseconds |
+| swagger.auth.username | Y | | Username for accessing swagger URL's |
+| swagger.auth.password | Y | | Password for accessing swagger URL's |
+
+### API Documentation
+
+#### Common Headers
+
+Authorization: Bearer where is a JWT token signed using JWT issuer and secret.
+`Content-Type: application/json` in the response and in request if the API method is NOT GET
+
+#### Common Request path Parameters
+
+{version}: Defines the API Version
+
+### Common Responses
+
+200: Successful Response. Response body varies w.r.t API
+401: Unauthorized: The JWT token is missing or invalid
+403: Forbidden : Not allowed to execute the concerned API
+404: Entity Not Found
+400: Bad Request (Error message varies w.r.t API)
+201: No content: Empty Response
+
+#### API Details
+
+Visit the [OpenAPI spec docs](./openapi.md)
diff --git a/services/audit-service/pom.xml b/services/audit-service/pom.xml
index e5f9651d..be8f41f8 100644
--- a/services/audit-service/pom.xml
+++ b/services/audit-service/pom.xml
@@ -31,10 +31,6 @@
org.springframework.boot
spring-boot-starter-data-redis
-
- org.springframework.boot
- spring-boot-starter-data-rest
-
org.springframework.boot
spring-boot-starter-hateoas
@@ -110,6 +106,17 @@
jarc-core
0.0.1-SNAPSHOT
+
+
+ com.sourcefuse.jarc
+ jarc-auth-lib
+ 0.0.1-SNAPSHOT
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.1.0
+
@@ -151,6 +158,24 @@
+
+ org.springdoc
+ springdoc-openapi-maven-plugin
+ 1.4
+
+
+ integration-test
+
+ generate
+
+
+
+
+ http://localhost:8080/v3/api-docs
+ audit-service-openapi.json
+ ../../openapi
+
+
diff --git a/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/AuditServiceApplication.java b/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/AuditServiceApplication.java
index 0041c174..1d9fb3f8 100644
--- a/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/AuditServiceApplication.java
+++ b/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/AuditServiceApplication.java
@@ -1,31 +1,26 @@
package com.sourcefuse.jarc.services.auditservice;
+import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
+import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Bean;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
-import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
+@ComponentScan(
+ { "com.sourcefuse.jarc.authlib", "com.sourcefuse.jarc.services.auditservice" }
+)
+@EntityScan({ "com.sourcefuse.jarc.services.auditservice" })
+@SecurityScheme(
+ name = "bearerAuth",
+ type = SecuritySchemeType.HTTP,
+ bearerFormat = "JWT",
+ scheme = "bearer"
+)
public class AuditServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AuditServiceApplication.class, args);
}
-
- /**
- * TO_DO: need to remove this code when authentication
- * service is integrated, This code is added to allow
- * access to all url in this app for temporary purpose
- */
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- return http
- .csrf(CsrfConfigurer::disable)
- .authorizeHttpRequests(requests ->
- requests.requestMatchers("/**").permitAll()
- )
- .build();
- }
}
diff --git a/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/controllers/AuditLogController.java b/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/controllers/AuditLogController.java
index 83f11f1d..448c9879 100644
--- a/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/controllers/AuditLogController.java
+++ b/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/controllers/AuditLogController.java
@@ -1,12 +1,16 @@
package com.sourcefuse.jarc.services.auditservice.controllers;
+import com.sourcefuse.jarc.core.constants.AuditPermissions;
import com.sourcefuse.jarc.services.auditservice.models.AuditLog;
import com.sourcefuse.jarc.services.auditservice.repositories.AuditLogRepository;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -19,17 +23,19 @@
@RestController
@RequestMapping("/audit_logs")
@Validated
+@SecurityRequirement(name = "bearerAuth")
public class AuditLogController {
@Autowired
private AuditLogRepository auditLogRepository;
- /*
- * TO_DO: Remove comments of @PreAuthorize("isAuthenticated()") once
- * authorization service is integrated
- */
@PostMapping
- // @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ AuditPermissions.CREATE_AUDIT +
+ "')"
+ )
+ @Operation(summary = "create audit log")
public ResponseEntity create(
@Valid @RequestBody AuditLog auditLog
) {
@@ -40,13 +46,23 @@ public ResponseEntity create(
}
@GetMapping("/count")
- // @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ AuditPermissions.VIEW_AUDIT +
+ "')"
+ )
+ @Operation(summary = "get count of audit logs")
public ResponseEntity count() {
return new ResponseEntity<>(this.auditLogRepository.count(), HttpStatus.OK);
}
@GetMapping
- // @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ AuditPermissions.VIEW_AUDIT +
+ "')"
+ )
+ @Operation(summary = "find audit logs")
public ResponseEntity> find() {
return new ResponseEntity<>(
this.auditLogRepository.findAll(),
@@ -55,7 +71,12 @@ public ResponseEntity> find() {
}
@GetMapping("/{id}")
- // @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ AuditPermissions.VIEW_AUDIT +
+ "')"
+ )
+ @Operation(summary = "find audit log by provided id")
public ResponseEntity findById(@PathVariable("id") UUID id) {
AuditLog auditLog =
this.auditLogRepository.findById(id)
diff --git a/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/models/AuditLog.java b/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/models/AuditLog.java
index 00a6d5df..5c95eac8 100644
--- a/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/models/AuditLog.java
+++ b/services/audit-service/src/main/java/com/sourcefuse/jarc/services/auditservice/models/AuditLog.java
@@ -1,6 +1,10 @@
package com.sourcefuse.jarc.services.auditservice.models;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.sourcefuse.jarc.core.enums.AuditActions;
+import com.sourcefuse.jarc.core.serializers.JsonBDeserializer;
+import com.sourcefuse.jarc.core.serializers.JsonBSerializer;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
@@ -28,7 +32,7 @@
@AllArgsConstructor
@ToString
@Entity
-@Table(name = "audit_logs", schema = "main")
+@Table(name = "audit_logs", schema = "logs")
public class AuditLog {
@Id
@@ -65,10 +69,14 @@ public class AuditLog {
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb", nullable = true)
+ @JsonSerialize(using = JsonBSerializer.class)
+ @JsonDeserialize(using = JsonBDeserializer.class)
private Object before;
@JdbcTypeCode(SqlTypes.JSON)
@Column(columnDefinition = "jsonb", nullable = true)
+ @JsonSerialize(using = JsonBSerializer.class)
+ @JsonDeserialize(using = JsonBDeserializer.class)
private Object after;
@NotNull
diff --git a/services/audit-service/src/main/resources/application.properties b/services/audit-service/src/main/resources/application.properties
index b19efb5e..e69de29b 100644
--- a/services/audit-service/src/main/resources/application.properties
+++ b/services/audit-service/src/main/resources/application.properties
@@ -1,21 +0,0 @@
-#
-#### datasource config (required)
-#spring.datasource.url=jdbc:postgresql://localhost:5432/jarc_audit
-#spring.datasource.username=postgres
-#spring.datasource.password=Source@123
-#spring.jpa.show-sql=true
-#
-#### to auto migrate the db as per models
-#spring.jpa.hibernate.ddl-auto = update
-#
-#### Optimization for POSTGRES queries
-##spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect
-#
-#spring.liquibase.enabled=false
-#
-#server.port=8089
-#
-#### Temporary Login Config for Spring Security
-#spring.security.user.name=admin
-#spring.security.user.password=admin
-#spring.security.user.roles=ADMIN
\ No newline at end of file
diff --git a/services/audit-service/src/main/resources/application.yml b/services/audit-service/src/main/resources/application.yml
index 268a8de3..e69de29b 100644
--- a/services/audit-service/src/main/resources/application.yml
+++ b/services/audit-service/src/main/resources/application.yml
@@ -1,18 +0,0 @@
-#
-#### datasource config (required)
-#spring:
-# datasource:
-# driverClassName: org.h2.Driver
-# username: sa
-# password:
-# url: jdbc:h2:mem:test;MODE=PostgreSQL;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS main\;CREATE SCHEMA IF NOT EXISTS logs\;
-# jpa:
-# database-platform: org.hibernate.dialect.H2Dialect
-# show-sql: true
-# hibernate:
-# ddl-auto: create
-# liquibase:
-# enabled: false
-#
-##server:
-## port: 8089
diff --git a/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/AuditControllerTests.java b/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/AuditControllerTests.java
index a5dc30ca..5c2a1933 100644
--- a/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/AuditControllerTests.java
+++ b/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/AuditControllerTests.java
@@ -11,9 +11,10 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+import com.sourcefuse.jarc.authlib.utils.JwtUtils;
import com.sourcefuse.jarc.core.adapters.LocalDateTimeTypeAdapter;
import com.sourcefuse.jarc.core.enums.AuditActions;
-import com.sourcefuse.jarc.core.enums.ContentTypes;
+import com.sourcefuse.jarc.services.auditservice.constant.TestConstants;
import com.sourcefuse.jarc.services.auditservice.models.AuditLog;
import com.sourcefuse.jarc.services.auditservice.repositories.AuditLogRepository;
import com.sourcefuse.jarc.services.auditservice.test.models.Role;
@@ -27,8 +28,10 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
@@ -45,6 +48,12 @@ class AuditControllerTests {
@Autowired
private AuditLogRepository auditLogRepository;
+ @Value("${app.jwt-secret}")
+ private String jwtSecret;
+
+ @Value("${app-jwt-expiration-milliseconds}")
+ private long jwtExpirationDate;
+
ObjectMapper objectMapper = new ObjectMapper();
UUID mockUserId = UUID.fromString("db66f86d-a7e8-45b7-a6ad-8a5024158377");
@@ -59,38 +68,59 @@ class AuditControllerTests {
private final String BASE_PATH = "/audit_logs";
+ String authToken;
+
@BeforeEach
void clearUserAndAuditLog() {
+ authToken =
+ "Bearer " +
+ JwtUtils.generateAccessToken(
+ jwtSecret,
+ jwtExpirationDate,
+ TestConstants.createMockCurrentUser()
+ );
this.clearTables();
this.addDefaultLogs();
}
@Test
- void testCreateAuditLog() throws Exception {
+ void createAuditLog_Success() throws Exception {
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isCreated());
}
@Test
- void shouldFailedDueToEmptyAction() throws Exception {
+ void createAuditLog_FailsDueToAuthTokenNotFound() throws Exception {
+ this.mockMvc.perform(
+ post(BASE_PATH)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(auditLog))
+ )
+ .andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ void createAuditLog_FailedDueToEmptyAction() throws Exception {
auditLog.setAction(null);
String requestBody = objectMapper.writeValueAsString(auditLog);
requestBody = requestBody.replace("\"action\":null", "\"action\":\"\"");
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(requestBody)
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToWrongActionIsProvided() throws Exception {
+ void createAuditLog_FailedDueToWrongActionIsProvided() throws Exception {
auditLog.setAction(null);
String requestBody = objectMapper.writeValueAsString(auditLog);
requestBody =
@@ -98,14 +128,15 @@ void shouldFailedDueToWrongActionIsProvided() throws Exception {
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(requestBody)
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToEmptyActedAt() throws Exception {
+ void createAuditLog_FailedDueToEmptyActedAt() throws Exception {
auditLog.setActedAt(null);
String requestBody = objectMapper.writeValueAsString(auditLog);
@@ -113,14 +144,15 @@ void shouldFailedDueToEmptyActedAt() throws Exception {
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(requestBody)
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToWrongActedAtIsProvided() throws Exception {
+ void createAuditLog_FailedDueToWrongActedAtIsProvided() throws Exception {
auditLog.setActedAt(null);
String requestBody = objectMapper.writeValueAsString(auditLog);
requestBody =
@@ -129,38 +161,41 @@ void shouldFailedDueToWrongActedAtIsProvided() throws Exception {
System.out.println(requestBody);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(requestBody)
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToEmptyActedOn() throws Exception {
+ void createAuditLog_FailedDueToEmptyActedOn() throws Exception {
auditLog.setActedOn("");
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToEmptyActionKey() throws Exception {
+ void createAuditLog_FailedDueToEmptyActionKey() throws Exception {
auditLog.setActionKey("");
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToEmptyEntityId() throws Exception {
+ void createAuditLog_FailedDueToEmptyEntityId() throws Exception {
auditLog.setEntityId(null);
String requestBody = objectMapper.writeValueAsString(auditLog);
@@ -168,14 +203,15 @@ void shouldFailedDueToEmptyEntityId() throws Exception {
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(requestBody)
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToEmptyActor() throws Exception {
+ void createAuditLog_FailedDueToEmptyActor() throws Exception {
auditLog.setActor(null);
String requestBody = objectMapper.writeValueAsString(auditLog);
@@ -183,119 +219,136 @@ void shouldFailedDueToEmptyActor() throws Exception {
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(requestBody)
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToEmptyActionGroup() throws Exception {
+ void createAuditLog_FailedDueToEmptyActionGroup() throws Exception {
auditLog.setActionGroup("");
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullAction() throws Exception {
+ void createAuditLog_FailedDueToNullAction() throws Exception {
auditLog.setAction(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullActedAt() throws Exception {
+ void createAuditLog_FailedDueToNullActedAt() throws Exception {
auditLog.setActedAt(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullActedOn() throws Exception {
+ void createAuditLog_FailedDueToNullActedOn() throws Exception {
auditLog.setActedOn(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullActionKey() throws Exception {
+ void createAuditLog_FailedDueToNullActionKey() throws Exception {
auditLog.setActionKey(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullEntityId() throws Exception {
+ void createAuditLog_FailedDueToNullEntityId() throws Exception {
auditLog.setEntityId(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullActor() throws Exception {
+ void createAuditLog_FailedDueToNullActor() throws Exception {
auditLog.setActor(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void shouldFailedDueToNullActionGroup() throws Exception {
+ void createAuditLog_FailedDueToNullActionGroup() throws Exception {
auditLog.setActionGroup(null);
this.mockMvc.perform(
post(BASE_PATH)
- .contentType(ContentTypes.APPLICATION_JSON.toString())
+ .header("Authorization", authToken)
+ .contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(auditLog))
)
.andExpect(status().isBadRequest());
}
@Test
- void testGetAuditLogCount() throws Exception {
- this.mockMvc.perform(get("/audit_logs/count"))
+ void getAuditLogCount_Success() throws Exception {
+ this.mockMvc.perform(
+ get(BASE_PATH + "/" + "/count").header("Authorization", authToken)
+ )
.andExpect(status().isOk())
.andExpect(content().string(equalTo("2")));
}
@Test
- void testGetAllAuditLogs() throws Exception {
+ void getAuditLogCount_FailsDueToAuthTokenNotFound() throws Exception {
+ this.mockMvc.perform(get(BASE_PATH + "/" + "/count"))
+ .andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ void getAllAuditLogs_Success() throws Exception {
MvcResult mvcResult =
- this.mockMvc.perform(get(BASE_PATH))
+ this.mockMvc.perform(get(BASE_PATH).header("Authorization", authToken))
.andExpect(status().isOk())
.andReturn();
String actualResponseBody = mvcResult.getResponse().getContentAsString();
@@ -309,19 +362,16 @@ void testGetAllAuditLogs() throws Exception {
expectedResult.add(auditLog2);
/**
- * Need to sanitize the before and after object, since this since H2 DB Don't
- * support JsonB it stores the JsonB data in stringify format
+ * Need to sanitize the string json into role object
*/
- if (isH2DB()) {
- responseAuditLogs.forEach(ele -> {
- if (ele.getBefore() != null) {
- ele.setBefore(gson.fromJson((String) ele.getBefore(), Role.class));
- }
- if (ele.getAfter() != null) {
- ele.setAfter(gson.fromJson((String) ele.getAfter(), Role.class));
- }
- });
- }
+ responseAuditLogs.forEach(ele -> {
+ if (ele.getBefore() != null) {
+ ele.setBefore(gson.fromJson((String) ele.getBefore(), Role.class));
+ }
+ if (ele.getAfter() != null) {
+ ele.setAfter(gson.fromJson((String) ele.getAfter(), Role.class));
+ }
+ });
assertEquals(
gson.toJsonTree(responseAuditLogs),
gson.toJsonTree(expectedResult)
@@ -329,9 +379,17 @@ void testGetAllAuditLogs() throws Exception {
}
@Test
- void testGetAuditLogById() throws Exception {
+ void getAllAuditLogs_FailsDueToAuthTokenNotFound() throws Exception {
+ this.mockMvc.perform(get(BASE_PATH)).andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ void getAuditLogById_Success() throws Exception {
MvcResult mvcResult =
- this.mockMvc.perform(get("/audit_logs/" + auditLog1.getId()))
+ this.mockMvc.perform(
+ get(BASE_PATH + "/" + auditLog1.getId())
+ .header("Authorization", authToken)
+ )
.andExpect(status().isOk())
.andReturn();
String actualResponseBody = mvcResult.getResponse().getContentAsString();
@@ -340,32 +398,39 @@ void testGetAuditLogById() throws Exception {
actualResponseBody,
AuditLog.class
);
+
/**
- * Need to sanitize the before and after object, since this since H2 DB Don't
- * support JsonB it stores the JsonB data in stringify format
+ * Need to sanitize the string json into role object
*/
- if (isH2DB()) {
- if (responseAuditLog.getBefore() != null) {
- responseAuditLog.setBefore(
- gson.fromJson((String) responseAuditLog.getBefore(), Role.class)
- );
- }
- if (responseAuditLog.getAfter() != null) {
- responseAuditLog.setAfter(
- gson.fromJson((String) responseAuditLog.getAfter(), Role.class)
- );
- }
+ if (responseAuditLog.getBefore() != null) {
+ responseAuditLog.setBefore(
+ gson.fromJson((String) responseAuditLog.getBefore(), Role.class)
+ );
}
+ if (responseAuditLog.getAfter() != null) {
+ responseAuditLog.setAfter(
+ gson.fromJson((String) responseAuditLog.getAfter(), Role.class)
+ );
+ }
+
assertEquals(gson.toJsonTree(responseAuditLog), gson.toJsonTree(auditLog1));
}
@Test
- void testGetAuditLogByIdForInvalidId() throws Exception {
+ void getAuditLogById_FailsDueToAuthTokenNotFound() throws Exception {
+ this.mockMvc.perform(get(BASE_PATH + "/" + auditLog1.getId()))
+ .andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ void getAuditLogById_FailedDueToInvalidId() throws Exception {
this.mockMvc.perform(
get(
- "/audit_logs/" +
+ BASE_PATH +
+ "/" +
UUID.fromString("fc2984b1-5ca5-4242-a522-c83b67909fb1")
)
+ .header("Authorization", authToken)
)
.andExpect(status().isNotFound());
}
@@ -377,7 +442,7 @@ void clearTables() {
System.out.println("reps");
em.getTransaction().begin();
try {
- em.createNativeQuery("TRUNCATE TABLE main.audit_logs;").executeUpdate();
+ em.createNativeQuery("TRUNCATE TABLE logs.audit_logs;").executeUpdate();
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
@@ -447,15 +512,4 @@ private void setAuditLog() {
"Role"
);
}
-
- private Boolean isH2DB() {
- String databaseProductName = entityManager
- .unwrap(org.hibernate.Session.class)
- .doReturningWork(conn -> conn.getMetaData().getDatabaseProductName());
- if ("H2".equals(databaseProductName)) {
- return true;
- } else {
- return false;
- }
- }
}
diff --git a/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/constant/TestConstants.java b/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/constant/TestConstants.java
new file mode 100644
index 00000000..19dbe131
--- /dev/null
+++ b/services/audit-service/src/test/java/com/sourcefuse/jarc/services/auditservice/constant/TestConstants.java
@@ -0,0 +1,40 @@
+package com.sourcefuse.jarc.services.auditservice.constant;
+
+import com.sourcefuse.jarc.core.constants.AuditPermissions;
+import com.sourcefuse.jarc.core.constants.NotificationPermissions;
+import com.sourcefuse.jarc.core.models.session.CurrentUser;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.UUID;
+
+public class TestConstants {
+
+ public static UUID mockUserId = UUID.fromString(
+ "d262e1bf-1be8-3bac-ce49-166324df1e33"
+ );
+
+ public static CurrentUser createMockCurrentUser() {
+ // Create a dummy user object
+ CurrentUser currentUser = new CurrentUser();
+ currentUser.setId(mockUserId);
+ currentUser.setFirstName("Dummy");
+ currentUser.setLastName("User");
+ currentUser.setEmail("dummy.user@example.com");
+ currentUser.setUsername("dummy.user@example.com");
+ currentUser.setPermissions(
+ Arrays.asList(
+ AuditPermissions.CREATE_AUDIT,
+ AuditPermissions.VIEW_AUDIT,
+ AuditPermissions.UPDATE_AUDIT,
+ AuditPermissions.DELETE_AUDIT,
+ NotificationPermissions.CAN_GET_NOTIFICATION_ACCESS,
+ NotificationPermissions.CREATE_NOTIFICATION,
+ NotificationPermissions.DELETE_NOTIFICATION,
+ NotificationPermissions.UPDATE_NOTIFICATION,
+ NotificationPermissions.VIEW_NOTIFICATION
+ )
+ );
+
+ return currentUser;
+ }
+}
diff --git a/services/audit-service/src/test/resources/application.yml b/services/audit-service/src/test/resources/application.yml
index 19569b3c..26868fae 100644
--- a/services/audit-service/src/test/resources/application.yml
+++ b/services/audit-service/src/test/resources/application.yml
@@ -16,3 +16,9 @@ spring:
#server:
# port: 8089
+
+
+app:
+ jwt-secret: daf66e01593f61a15b857cf433aae03a005812b31234e149036bcc8dee755dbb
+app-jwt-expiration-milliseconds: 3600000
+
diff --git a/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/Utils.java b/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/Utils.java
deleted file mode 100644
index ed4178ec..00000000
--- a/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/Utils.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.sourcefuse.jarc.services.authservice;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
-
-public final class Utils {
- private Utils() {}
-
- public static ObjectMapper getObjectMapperInstance() {
- return new Jackson2ObjectMapperBuilder()
- .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
- .modulesToInstall(new JavaTimeModule())
- .build();
- }
-}
diff --git a/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/providers/JwtTokenProvider.java b/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/providers/JwtTokenProvider.java
index 47b60526..f2821cff 100644
--- a/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/providers/JwtTokenProvider.java
+++ b/services/auth-service/src/main/java/com/sourcefuse/jarc/services/authservice/providers/JwtTokenProvider.java
@@ -1,36 +1,23 @@
package com.sourcefuse.jarc.services.authservice.providers;
-import java.security.Key;
-import java.util.Date;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Component;
-
-import com.sourcefuse.jarc.core.constants.AuthConstants;
+import com.sourcefuse.jarc.authlib.utils.JwtUtils;
import com.sourcefuse.jarc.core.exception.CommonRuntimeException;
import com.sourcefuse.jarc.core.models.session.CurrentUser;
-import com.sourcefuse.jarc.services.authservice.Utils;
import com.sourcefuse.jarc.services.authservice.dtos.JWTAuthResponse;
import com.sourcefuse.jarc.services.authservice.models.AuthClient;
import com.sourcefuse.jarc.services.authservice.models.RefreshTokenRedis;
import com.sourcefuse.jarc.services.authservice.models.Role;
import com.sourcefuse.jarc.services.authservice.models.User;
import com.sourcefuse.jarc.services.authservice.models.UserTenant;
-import com.sourcefuse.jarc.services.authservice.security.CustomJwtBuilder;
-
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.MalformedJwtException;
-import io.jsonwebtoken.UnsupportedJwtException;
-import io.jsonwebtoken.io.Decoders;
-import io.jsonwebtoken.security.Keys;
+import java.util.Date;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
@RequiredArgsConstructor
@Component
@@ -46,25 +33,6 @@ public class JwtTokenProvider {
private final JwtPayloadProvider jwtPayloadProvider;
private final RedisTemplate redisTemplate;
- private String generateToken(CurrentUser currentUser) {
- Date currentDate = new Date();
- Date expireDate = new Date(currentDate.getTime() + jwtExpirationDate);
- Claims claims = Jwts
- .claims()
- .setSubject(currentUser.getUsername());
- claims.put(AuthConstants.CURRENT_USER_KEY, currentUser);
- return new CustomJwtBuilder()
- .setClaims(claims)
- .setIssuedAt(currentDate)
- .setExpiration(expireDate)
- .signWith(key())
- .compact();
- }
-
- private Key key() {
- return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
- }
-
public JWTAuthResponse createJwt(
User user,
UserTenant userTenant,
@@ -74,7 +42,11 @@ public JWTAuthResponse createJwt(
try {
CurrentUser currentUser =
this.jwtPayloadProvider.provide(user, userTenant, role);
- String accessToken = this.generateToken(currentUser);
+ String accessToken = JwtUtils.generateAccessToken(
+ jwtSecret,
+ jwtExpirationDate,
+ currentUser
+ );
String refreshToken = UUID.randomUUID().toString();
RefreshTokenRedis refreshTokenRedis = new RefreshTokenRedis();
@@ -100,12 +72,11 @@ public JWTAuthResponse createJwt(
jwtAuthResponse.setRefreshToken(refreshToken);
return jwtAuthResponse;
} catch (Exception e) {
- log.error(null,e);
+ log.error(null, e);
throw new CommonRuntimeException(
HttpStatus.INTERNAL_SERVER_ERROR,
"Error while generating JWT token"
);
}
}
-
}
diff --git a/services/notification-service/README.md b/services/notification-service/README.md
index 00472c73..76325cb7 100644
--- a/services/notification-service/README.md
+++ b/services/notification-service/README.md
@@ -475,6 +475,10 @@ Do not forget to set Application properties. The examples below show a common co
| notification.provider.email | N | | Email Notification provider provided by us. values can be SesProvider, JavaMailerProvider. |
| notification.provider.push | N | | Push Notification provider provided by us. values can be FcmProvider, PubNubProvider, SocketIoProvider. |
| notification.provider.sms | N | | SMS Notification provider provided by us. values can be SnsProvider, TwilioProvider. |
+| app.jwt-secret | Y | | JWT Secrete should be in Base64 Format |
+| app-jwt-expiration-milliseconds | Y | | JWT token expiration in milliseconds |
+| swagger.auth.username | Y | | Username for accessing swagger URL's |
+| swagger.auth.password | Y | | Password for accessing swagger URL's |
### Create Notification Payload Structures
diff --git a/services/notification-service/pom.xml b/services/notification-service/pom.xml
index b0740623..66bc293c 100644
--- a/services/notification-service/pom.xml
+++ b/services/notification-service/pom.xml
@@ -148,6 +148,11 @@
com.sourcefuse.jarc
jarc-core
0.0.1-SNAPSHOT
+
+
+ com.sourcefuse.jarc
+ jarc-auth-lib
+ 0.0.1-SNAPSHOT
org.springdoc
diff --git a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/NotificationServiceApplication.java b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/NotificationServiceApplication.java
index a98adaf5..858f0991 100644
--- a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/NotificationServiceApplication.java
+++ b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/NotificationServiceApplication.java
@@ -1,38 +1,28 @@
package com.sourcefuse.jarc.services.notificationservice;
+import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
+import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
-import org.springframework.security.web.SecurityFilterChain;
@SpringBootApplication
@ComponentScan(
{
"com.sourcefuse.jarc.core",
+ "com.sourcefuse.jarc.authlib",
"com.sourcefuse.jarc.services.notificationservice"
}
)
+@SecurityScheme(
+ name = "bearerAuth",
+ type = SecuritySchemeType.HTTP,
+ bearerFormat = "JWT",
+ scheme = "bearer"
+)
public class NotificationServiceApplication {
public static void main(String[] args) {
SpringApplication.run(NotificationServiceApplication.class, args);
}
-
- /**
- * TO_DO: need to remove this code when authentication service is integrated,
- * This code is added to allow access to all url in this app for temporary
- * purpose
- */
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- return http
- .csrf(CsrfConfigurer::disable)
- .authorizeHttpRequests(requests ->
- requests.requestMatchers("/**").permitAll()
- )
- .build();
- }
}
diff --git a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationController.java b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationController.java
index af0619a5..fa8c93c5 100644
--- a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationController.java
+++ b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationController.java
@@ -1,5 +1,6 @@
package com.sourcefuse.jarc.services.notificationservice.controllers;
+import com.sourcefuse.jarc.core.constants.NotificationPermissions;
import com.sourcefuse.jarc.core.dtos.CountResponse;
import com.sourcefuse.jarc.core.utils.CommonUtils;
import com.sourcefuse.jarc.services.notificationservice.dtos.NotificationList;
@@ -11,6 +12,7 @@
import com.sourcefuse.jarc.services.notificationservice.types.INotification;
import com.sourcefuse.jarc.services.notificationservice.types.INotificationFilterFunc;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Valid;
import jakarta.validation.Validator;
@@ -24,6 +26,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
@@ -37,6 +40,7 @@
@RestController
@RequestMapping("/notifications")
@RequiredArgsConstructor
+@SecurityRequirement(name = "bearerAuth")
public class NotificationController {
private static final int MAX_BODY_LENGTH = 1000;
@@ -56,7 +60,12 @@ public class NotificationController {
@Operation(summary = "Create and publish Notification")
@PostMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.CREATE_NOTIFICATION +
+ "')"
+ )
+ @Transactional
public ResponseEntity create(
@Valid @RequestBody Notification notification
) {
@@ -79,7 +88,12 @@ public ResponseEntity create(
@Operation(summary = "Create and publish Notifications")
@PostMapping("/bulk")
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.CREATE_NOTIFICATION +
+ "')"
+ )
+ @Transactional
public ResponseEntity> createBulkNotificaitions(
@Valid @RequestBody NotificationList notificationList
) {
@@ -111,7 +125,11 @@ public ResponseEntity> createBulkNotificaitions(
@Operation(summary = "Get total count of notifications")
@GetMapping("/count")
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.VIEW_NOTIFICATION +
+ "')"
+ )
public ResponseEntity count() {
return new ResponseEntity<>(
CountResponse
@@ -134,7 +152,11 @@ public ResponseEntity> find() {
@Operation(summary = "get notification by id")
@GetMapping("/{id}")
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.VIEW_NOTIFICATION +
+ "')"
+ )
public ResponseEntity findById(@PathVariable("id") UUID id) {
Notification notification =
this.notificationRepository.findById(id)
@@ -149,7 +171,11 @@ public ResponseEntity findById(@PathVariable("id") UUID id) {
@Operation(summary = "update notification by id")
@PatchMapping("/{id}")
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.UPDATE_NOTIFICATION +
+ "')"
+ )
public ResponseEntity updateById(
@PathVariable("id") UUID id,
@RequestBody Notification notification
@@ -189,7 +215,11 @@ public ResponseEntity updateById(
@Operation(summary = "delete all notifications")
@DeleteMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.DELETE_NOTIFICATION +
+ "')"
+ )
public ResponseEntity deleteAll() {
this.notificationRepository.deleteAll();
return new ResponseEntity<>(
diff --git a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationNotificationuserController.java b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationNotificationuserController.java
index 26810e45..a6c96947 100644
--- a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationNotificationuserController.java
+++ b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationNotificationuserController.java
@@ -1,11 +1,14 @@
package com.sourcefuse.jarc.services.notificationservice.controllers;
+import com.sourcefuse.jarc.core.constants.NotificationPermissions;
+import com.sourcefuse.jarc.core.dtos.CountResponse;
import com.sourcefuse.jarc.core.utils.CommonUtils;
import com.sourcefuse.jarc.services.notificationservice.models.Notification;
import com.sourcefuse.jarc.services.notificationservice.models.NotificationUser;
import com.sourcefuse.jarc.services.notificationservice.repositories.softdelete.NotificationUserRepository;
import com.sourcefuse.jarc.services.notificationservice.specifications.NotificationUserSpecifications;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Valid;
import jakarta.validation.Validator;
@@ -30,6 +33,7 @@
@RestController
@RequestMapping("/notifications/{id}/notification-users")
@RequiredArgsConstructor
+@SecurityRequirement(name = "bearerAuth")
public class NotificationNotificationuserController {
private final NotificationUserRepository notificationUserRepository;
@@ -38,7 +42,11 @@ public class NotificationNotificationuserController {
@Operation(summary = "find all notification users by notification id")
@GetMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.VIEW_NOTIFICATION +
+ "')"
+ )
public ResponseEntity> find(
@PathVariable("id") UUID notificationId
) {
@@ -52,7 +60,11 @@ public ResponseEntity> find(
@Operation(summary = "create notification user for given notification id")
@PostMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.CREATE_NOTIFICATION +
+ "')"
+ )
public ResponseEntity create(
@PathVariable("id") UUID notificationId,
@Valid @RequestBody NotificationUser notificationUser
@@ -69,7 +81,11 @@ public ResponseEntity create(
@Operation(summary = "update notification user for given notification id")
@PatchMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.UPDATE_NOTIFICATION +
+ "')"
+ )
public ResponseEntity update(
@PathVariable("id") UUID notificationId,
@RequestBody NotificationUser notificationUser
@@ -109,7 +125,11 @@ public ResponseEntity update(
summary = "mark notification as read for given notification id and notification user id"
)
@PatchMapping("/{notificationUserId}/mark-as-read")
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.UPDATE_NOTIFICATION +
+ "')"
+ )
public ResponseEntity markAsRead(
@PathVariable("id") UUID notificationId,
@PathVariable("notificationUserId") UUID notificationUserId
@@ -136,8 +156,12 @@ public ResponseEntity markAsRead(
@Operation(summary = "delete all notification users of given notification id")
@DeleteMapping
- @PreAuthorize("isAuthenticated()")
- public ResponseEntity delete(
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.DELETE_NOTIFICATION +
+ "')"
+ )
+ public ResponseEntity delete(
@PathVariable("id") UUID notificationId
) {
List notificationUsers =
@@ -145,6 +169,10 @@ public ResponseEntity delete(
NotificationUserSpecifications.byNotificationId(notificationId)
);
this.notificationUserRepository.deleteAll(notificationUsers);
- return new ResponseEntity<>(notificationUsers.size(), HttpStatus.OK);
+ CountResponse countResponse = CountResponse
+ .builder()
+ .count(Long.valueOf(notificationUsers.size()))
+ .build();
+ return new ResponseEntity<>(countResponse, HttpStatus.OK);
}
}
diff --git a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationuserNotificationController.java b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationuserNotificationController.java
index 85005507..9aaab62c 100644
--- a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationuserNotificationController.java
+++ b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/NotificationuserNotificationController.java
@@ -1,9 +1,11 @@
package com.sourcefuse.jarc.services.notificationservice.controllers;
+import com.sourcefuse.jarc.core.constants.NotificationPermissions;
import com.sourcefuse.jarc.services.notificationservice.models.Notification;
import com.sourcefuse.jarc.services.notificationservice.models.NotificationUser;
import com.sourcefuse.jarc.services.notificationservice.repositories.softdelete.NotificationUserRepository;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
@@ -18,13 +20,18 @@
@RestController
@RequestMapping("/notification-users/{id}/notification")
@RequiredArgsConstructor
+@SecurityRequirement(name = "bearerAuth")
public class NotificationuserNotificationController {
private final NotificationUserRepository notificationUserRepository;
@Operation(summary = "get all notification of given notification user id")
@GetMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.VIEW_NOTIFICATION +
+ "')"
+ )
public ResponseEntity find(@PathVariable("id") UUID id) {
NotificationUser notificationUser =
this.notificationUserRepository.findById(id)
diff --git a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/PubNubNotificationController.java b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/PubNubNotificationController.java
index 55e49893..4421593f 100644
--- a/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/PubNubNotificationController.java
+++ b/services/notification-service/src/main/java/com/sourcefuse/jarc/services/notificationservice/controllers/PubNubNotificationController.java
@@ -1,5 +1,6 @@
package com.sourcefuse.jarc.services.notificationservice.controllers;
+import com.sourcefuse.jarc.core.constants.NotificationPermissions;
import com.sourcefuse.jarc.core.models.session.CurrentUser;
import com.sourcefuse.jarc.services.notificationservice.dtos.AccessResponse;
import com.sourcefuse.jarc.services.notificationservice.dtos.SuccessResponse;
@@ -9,6 +10,7 @@
import com.sourcefuse.jarc.services.notificationservice.repositories.redis.NotificationAccessRepository;
import com.sourcefuse.jarc.services.notificationservice.types.Config;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -29,6 +31,7 @@
@RestController
@RequestMapping("/notifications/access/{id}")
@RequiredArgsConstructor
+@SecurityRequirement(name = "bearerAuth")
public class PubNubNotificationController {
@Nullable
@@ -41,7 +44,11 @@ public class PubNubNotificationController {
@Operation(summary = "grant access of notification to user")
@PatchMapping
- @PreAuthorize("isAuthenticated()")
+ @PreAuthorize(
+ "isAuthenticated() && hasAuthority('" +
+ NotificationPermissions.CAN_GET_NOTIFICATION_ACCESS +
+ "')"
+ )
public ResponseEntity grantAccess(
@Valid @RequestBody NotificationAccess notification,
@PathVariable("id") UUID userId,
diff --git a/services/notification-service/src/main/resources/application.properties b/services/notification-service/src/main/resources/application.properties
index 8cc00c49..e69de29b 100644
--- a/services/notification-service/src/main/resources/application.properties
+++ b/services/notification-service/src/main/resources/application.properties
@@ -1,20 +0,0 @@
-notification.provider.email =
-notification.provider.push =
-notification.provider.sms =
-
-spring.datasource.username=
-spring.datasource.password=
-spring.datasource.url=
-
-spring.jpa.show-sql=false
-
-spring.jpa.hibernate.ddl-auto=
-spring.jpa.properties.hibernat.dialect=
-spring.jpa.properties.liquidbase.enabled=
-
-spring.data.redis.host=localhost
-spring.data.redis.port=6379
-spring.data.redis.password=
-
-
-
diff --git a/services/notification-service/src/test/resources/application.properties b/services/notification-service/src/test/resources/application.properties
new file mode 100644
index 00000000..8ea9da75
--- /dev/null
+++ b/services/notification-service/src/test/resources/application.properties
@@ -0,0 +1,3 @@
+
+app.jwt-secret= daf66e01593f61a15b857cf433aae03a005812b31234e149036bcc8dee755dbb
+app.app-jwt-expiration-milliseconds= 3600000