diff --git a/api-gateway/build.gradle b/api-gateway/build.gradle
index 1250b5a8e0..dadb140664 100755
--- a/api-gateway/build.gradle
+++ b/api-gateway/build.gradle
@@ -21,38 +21,31 @@ repositories {
dependencies {
-
-
- implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
- runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
- runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2'
-
- implementation 'org.springframework.boot:spring-boot-starter-validation'
- implementation 'org.springframework.boot:spring-boot-starter-actuator'
- implementation 'org.springframework.boot:spring-boot-starter-webflux'
- implementation 'org.yaml:snakeyaml:2.2'
-
- implementation 'org.webjars:bootstrap:5.1.0' // https://mvnrepository.com/artifact/org.webjars/bootstrap
- implementation 'org.webjars:jquery:3.6.0' // https://mvnrepository.com/artifact/org.webjars/jquery
- implementation 'org.webjars:angularjs:2.0.0-alpha.22' // https://mvnrepository.com/artifact/org.webjars/angularjs
- implementation 'org.webjars.bower:angular-ui-router:1.0.28' // https://mvnrepository.com/artifact/org.webjars.bower/angular-ui-router
- implementation 'org.webjars:webjars-locator-core:0.47' // https://mvnrepository.com/artifact/org.webjars/webjars-locator-core
- implementation 'ro.isdc.wro4j:wro4j-core:1.10.1' // https://mvnrepository.com/artifact/ro.isdc.wro4j/wro4j-core
- implementation 'com.github.houbie:lesscss-gradle-plugin:1.0.3-less-1.7.0' // https://mvnrepository.com/artifact/com.github.houbie/lesscss-gradle-plugin
- implementation 'com.github.houbie:lesscss-gradle-plugin:1.0.3-less-1.7.0' // https://mvnrepository.com/artifact/com.github.houbie/lesscss-gradle-plugin
- implementation 'org.jolokia:jolokia-core:1.7.0' // https://mvnrepository.com/artifact/org.jolokia/jolokia-core
- implementation 'io.springfox:springfox-boot-starter:3.0.0'
- implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' //for serializing and deserializing java.time.LocalDateTime
-
+ runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2', 'io.jsonwebtoken:jjwt-jackson:0.11.2'
+
+ implementation 'org.webjars:bootstrap:5.1.0', // https://mvnrepository.com/artifact/org.webjars/bootstrap
+ 'org.springframework.boot:spring-boot-starter-webflux',
+ 'org.springframework.boot:spring-boot-starter-actuator',
+ 'org.springframework.boot:spring-boot-starter-validation',
+ 'io.jsonwebtoken:jjwt-api:0.11.2',
+ 'org.webjars:jquery:3.7.1', // https://mvnrepository.com/artifact/org.webjars/jquery
+ 'org.webjars:angularjs:2.0.0-alpha.22', // https://mvnrepository.com/artifact/org.webjars/angularjs
+ 'org.webjars.bower:angular-ui-router:1.0.28', // https://mvnrepository.com/artifact/org.webjars.bower/angular-ui-router
+ 'org.webjars:webjars-locator-core:0.47', // https://mvnrepository.com/artifact/org.webjars/webjars-locator-core
+ 'ro.isdc.wro4j:wro4j-core:1.10.1', // https://mvnrepository.com/artifact/ro.isdc.wro4j/wro4j-core
+ 'com.github.houbie:lesscss-gradle-plugin:1.0.3-less-1.7.0', // https://mvnrepository.com/artifact/com.github.houbie/lesscss-gradle-plugin
+ 'org.jolokia:jolokia-core:1.7.0', // https://mvnrepository.com/artifact/org.jolokia/jolokia-core
+ 'io.springfox:springfox-boot-starter:3.0.0',
+ 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310', //for serializing and deserializing java.time.LocalDateTime
+ 'org.yaml:snakeyaml:2.2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
- testImplementation 'io.projectreactor:reactor-test'
- testImplementation 'com.squareup.okhttp3:okhttp:4.11.0'
- testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
-
+ testImplementation 'com.squareup.okhttp3:okhttp:4.11.0',
+ 'com.squareup.okhttp3:mockwebserver:4.11.0',
+ 'io.projectreactor:reactor-test'
}
jacoco {
@@ -88,4 +81,4 @@ test {
testLogging {
events "passed", "skipped", "failed"
}
-}
\ No newline at end of file
+}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/AuthServiceClient.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/AuthServiceClient.java
index 5c1ae2f5df..3c906ed10b 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/AuthServiceClient.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/AuthServiceClient.java
@@ -11,12 +11,16 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
+import java.time.Duration;
+import java.util.List;
import java.util.UUID;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
@@ -83,6 +87,16 @@ public Flux getUsers(String jwtToken) {
.retrieve()
.bodyToFlux(UserDetails.class);
}
+
+ public Mono deleteUser(String jwtToken, String userId) {
+ return webClientBuilder.build()
+ .delete()
+ .uri(authServiceUrl + "/users/{userId}", userId)
+ .cookie("Bearer", jwtToken)
+ .retrieve()
+ .bodyToMono(void.class);
+ }
+
//FUCK REACTIVE
/*
This shit is beyond cursed, but I do not care. This works, I only spent 6 HOURS OF MY LIFE.
@@ -123,6 +137,23 @@ public Mono createUser (Mono model) {
}
+ public Mono createInventoryMangerUser(Mono registerInventoryManagerMono){
+ String uuid = UUID.randomUUID().toString();
+ return registerInventoryManagerMono.flatMap(registerInventoryManager -> {
+ registerInventoryManager.setUserId(uuid);
+ return webClientBuilder.build().post()
+ .uri(authServiceUrl + "/users")
+ .body(Mono.just(registerInventoryManager), RegisterInventoryManager.class)
+ .accept(MediaType.APPLICATION_JSON)
+ .retrieve()
+ .onStatus(HttpStatusCode::is4xxClientError,
+ n -> rethrower.rethrow(n,
+ x -> new GenericHttpException(x.get("message").toString(), BAD_REQUEST))
+ )
+ .bodyToMono(UserPasswordLessDTO.class);
+ });
+ }
+
public Mono createVetUser(Mono model){
@@ -145,6 +176,7 @@ public Mono createVetUser(Mono model){
VetRequestDTO vetDTO = VetRequestDTO.builder()
.specialties(registerVet.getVet().getSpecialties())
.active(registerVet.getVet().isActive())
+ .photoDefault(registerVet.getVet().isPhotoDefault())
.email(registerVet.getEmail())
.resume(registerVet.getVet().getResume())
.workday(registerVet.getVet().getWorkday())
@@ -154,7 +186,8 @@ public Mono createVetUser(Mono model){
.lastName(registerVet.getVet().getLastName())
.vetId(uuid)
.build();
- return vetsServiceClient.createVet((Mono.just(vetDTO)));
+ log.debug("In Api, photo default is: " + vetDTO.isPhotoDefault());
+ return vetsServiceClient.createVet((Mono.just(vetDTO)));
}
);
}).doOnError(throwable -> {
@@ -177,15 +210,6 @@ public Mono createVetUser(Mono model){
// .bodyToMono(UserDetails.class);
// }
//
-// public Mono deleteUser(String auth, final long userId) {
-// return webClientBuilder.build()
-// .delete()
-// .uri(authServiceUrl + "/users/{userId}", userId)
-// .header("Authorization", auth)
-// .retrieve()
-// .bodyToMono(UserDetails.class);
-// }
-
public Mono> verifyUser(final String token) {
return webClientBuilder.build()
@@ -225,6 +249,26 @@ public Mono> login(final Mono login)
}
}
+ public Mono> logout(ServerHttpRequest request, ServerHttpResponse response) {
+ log.info("Entered AuthServiceClient logout method");
+ List cookies = request.getCookies().get("Bearer");
+ if (cookies != null && !cookies.isEmpty()) {
+ ResponseCookie cookie = ResponseCookie.from("Bearer", "")
+ .httpOnly(true)
+ .secure(true)
+ .path("/api/gateway")
+ .domain("localhost")
+ .maxAge(Duration.ofSeconds(0))
+ .sameSite("Lax").build();
+ response.addCookie(cookie);
+ log.info("Logout Success: Account session ended");
+ return Mono.just(ResponseEntity.noContent().build());
+ } else {
+ log.warn("Logout Error: Problem removing account cookies, Session may have expired, redirecting to login page");
+ return Mono.just(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build());
+ }
+ }
+
public Mono> sendForgottenEmail(Mono emailRequestDTOMono) {
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/BillServiceClient.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/BillServiceClient.java
index 3a7a199f82..4972edb84e 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/BillServiceClient.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/BillServiceClient.java
@@ -95,6 +95,14 @@ public Mono updateBill(String billId, Mono bill
.bodyToMono(BillResponseDTO.class);
}
+ public Mono deleteAllBills() {
+ return webClientBuilder.build()
+ .delete()
+ .uri(billServiceUrl)
+ .accept(MediaType.APPLICATION_JSON)
+ .retrieve()
+ .bodyToMono(Void.class);
+ }
public Mono deleteBill(final String billId) {
return webClientBuilder.build()
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/CustomersServiceClient.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/CustomersServiceClient.java
index 0848f24134..c82ab3fc3d 100755
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/CustomersServiceClient.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/CustomersServiceClient.java
@@ -2,10 +2,7 @@
import com.petclinic.bffapigateway.dtos.CustomerDTOs.OwnerRequestDTO;
import com.petclinic.bffapigateway.dtos.CustomerDTOs.OwnerResponseDTO;
-import com.petclinic.bffapigateway.dtos.Pets.PetRequestDTO;
-import com.petclinic.bffapigateway.dtos.Pets.PetResponseDTO;
-import com.petclinic.bffapigateway.dtos.Pets.PetType;
-import com.petclinic.bffapigateway.dtos.Pets.PetTypeResponseDTO;
+import com.petclinic.bffapigateway.dtos.Pets.*;
import com.petclinic.bffapigateway.dtos.Vets.PhotoDetails;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@@ -263,4 +260,29 @@ public Flux getAllPetTypes() {
.retrieve()
.bodyToFlux(PetTypeResponseDTO.class);
}
+ public Mono getPetTypeByPetTypeId(String petTypeId) {
+ return webClientBuilder.build().get()
+ .uri(customersServiceUrl + "/owners/petTypes/" + petTypeId)
+ .retrieve()
+ .bodyToMono(PetTypeResponseDTO.class);
+ }
+
+ public Mono deletePetType(final String petTypeId) {
+ return webClientBuilder.build().delete()
+ .uri(customersServiceUrl +"/owners/petTypes/"+ petTypeId)
+ .retrieve()
+ .bodyToMono(PetTypeResponseDTO.class);
+ }
+
+ public Mono updatePetType(String petTypeId, Mono petTypeRequestDTO) {
+ return petTypeRequestDTO.flatMap(requestDTO ->
+ webClientBuilder.build()
+ .put()
+ .uri(customersServiceUrl + "/owners/petTypes/" + petTypeId)
+ .body(BodyInserters.fromValue(requestDTO))
+ .retrieve()
+ .bodyToMono(PetTypeResponseDTO.class)
+ );
+ }
+
}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VetsServiceClient.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VetsServiceClient.java
index f1357ddbfa..1510cd4ce1 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VetsServiceClient.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VetsServiceClient.java
@@ -62,6 +62,22 @@ public Mono getPhotoByVetId(String vetId){
)
.bodyToMono(Resource.class);
}
+ public Mono getDefaultPhotoByVetId(String vetId){
+ return webClientBuilder.build()
+ .get()
+ .uri(vetsServiceUrl + "/" + vetId + "/default-photo")
+ .retrieve()
+ .onStatus(HttpStatusCode::is4xxClientError, error->{
+ HttpStatusCode statusCode = error.statusCode();
+ if(statusCode.equals(NOT_FOUND))
+ return Mono.error(new ExistingVetNotFoundException("Photo for vet "+vetId + " not found", NOT_FOUND));
+ return Mono.error(new IllegalArgumentException("Something went wrong"));
+ })
+ .onStatus(HttpStatusCode::is5xxServerError,error->
+ Mono.error(new IllegalArgumentException("Something went wrong"))
+ )
+ .bodyToMono(PhotoResponseDTO.class);
+ }
public Mono addPhotoToVet(String vetId, String photoName, Mono image) {
log.debug("VetsServiceClient addPhoto");
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java
index 265f5fe9b4..c894cbfb6a 100755
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java
@@ -2,10 +2,11 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.petclinic.bffapigateway.dtos.Visits.*;
+import com.petclinic.bffapigateway.dtos.Visits.Status;
+import com.petclinic.bffapigateway.dtos.Visits.VisitRequestDTO;
+import com.petclinic.bffapigateway.dtos.Visits.VisitResponseDTO;
import com.petclinic.bffapigateway.exceptions.BadRequestException;
import com.petclinic.bffapigateway.exceptions.DuplicateTimeException;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
@@ -24,10 +25,8 @@
*/
@Component
-@Slf4j
public class VisitsServiceClient {
private final WebClient webClient;
-
@Autowired
public VisitsServiceClient(
@Value("${app.visits-service-new.host}") String visitsServiceHost,
@@ -125,7 +124,6 @@ else if (httpStatus == HttpStatus.CONFLICT){
else {
return Mono.error(new BadRequestException(message));
}
-
} catch (IOException e) {
// Handle parsing error
return Mono.error(new BadRequestException("Bad Request"));
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/Register.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/Register.java
index 39ae41ea6c..8433f17b5c 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/Register.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/Register.java
@@ -1,5 +1,6 @@
package com.petclinic.bffapigateway.dtos.Auth;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.petclinic.bffapigateway.dtos.CustomerDTOs.OwnerRequestDTO;
import com.petclinic.bffapigateway.dtos.CustomerDTOs.OwnerResponseDTO;
import com.petclinic.bffapigateway.utils.Security.Annotations.PasswordStrengthCheck;
@@ -25,6 +26,7 @@ public class Register {
private String userId;
private String email;
private String username;
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
private final String defaultRole = Roles.OWNER.toString();
@PasswordStrengthCheck
private String password;
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterInventoryManager.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterInventoryManager.java
new file mode 100644
index 0000000000..80db4d667b
--- /dev/null
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterInventoryManager.java
@@ -0,0 +1,23 @@
+package com.petclinic.bffapigateway.dtos.Auth;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.petclinic.bffapigateway.utils.Security.Annotations.PasswordStrengthCheck;
+import com.petclinic.bffapigateway.utils.Security.Variables.Roles;
+import lombok.*;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder(toBuilder = true)
+public class RegisterInventoryManager {
+ private String userId;
+ private String email;
+ private String username;
+ @PasswordStrengthCheck
+ private String password;
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ protected final String defaultRole = Roles.INVENTORY_MANAGER.toString();
+
+
+}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterVet.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterVet.java
index 82f8be9806..2887361cb8 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterVet.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Auth/RegisterVet.java
@@ -1,6 +1,7 @@
package com.petclinic.bffapigateway.dtos.Auth;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.petclinic.bffapigateway.dtos.Vets.VetRequestDTO;
import com.petclinic.bffapigateway.utils.Security.Annotations.PasswordStrengthCheck;
import com.petclinic.bffapigateway.utils.Security.Variables.Roles;
@@ -17,6 +18,7 @@ public class RegisterVet {
private String userId;
private String email;
private String username;
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
private final String defaultRole = Roles.VET.toString();
@PasswordStrengthCheck
private String password;
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetRequestDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetRequestDTO.java
index 3e2df1e18e..4705b91f05 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetRequestDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetRequestDTO.java
@@ -20,5 +20,5 @@ public class PetRequestDTO {
private String petTypeId;
//private String photoId;
private String isActive;
-
+ private String weight;
}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetResponseDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetResponseDTO.java
index 847825f2eb..e3aad3c8b4 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetResponseDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Pets/PetResponseDTO.java
@@ -24,7 +24,7 @@ public class PetResponseDTO {
private String petTypeId;
//private String photoId;
private String isActive;
-
+ private String weight;
//private final List visits = new ArrayList<>();
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/PhotoResponseDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/PhotoResponseDTO.java
new file mode 100644
index 0000000000..ad0bae2fb5
--- /dev/null
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/PhotoResponseDTO.java
@@ -0,0 +1,17 @@
+package com.petclinic.bffapigateway.dtos.Vets;
+
+import lombok.*;
+import org.springframework.core.io.Resource;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PhotoResponseDTO {
+ private String vetId;
+ private String filename;
+ private String imgType;
+ private String resourceBase64;
+ private byte[] resource;
+}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/RatingRequestDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/RatingRequestDTO.java
index c072a6cb58..248085783a 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/RatingRequestDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/RatingRequestDTO.java
@@ -14,5 +14,7 @@ public class RatingRequestDTO {
private Double rateScore;
private String rateDescription;
private String rateDate;
+
+ private String ownerId;
private PredefinedDescription predefinedDescription;
}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/VetRequestDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/VetRequestDTO.java
index 16ac67ff7b..e3fc4397fd 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/VetRequestDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Vets/VetRequestDTO.java
@@ -18,5 +18,5 @@ public class VetRequestDTO {
private Set workday;
private boolean active;
private Set specialties;
-
+ private boolean photoDefault;
}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java
index 4efc69f4ae..464f807503 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java
@@ -19,13 +19,17 @@ public class VisitRequestDTO {
private LocalDateTime visitDate;
private String description;
private String petId;
+ private String ownerId;
+ private String jwtToken;//used to get the userDetails from the Auth-Service when sending visit emails
private String practitionerId;
private Status status;
- public VisitRequestDTO(LocalDateTime now, String description, String petId, String practitionerId) {
+ public VisitRequestDTO(LocalDateTime now, String description, String petId, String ownerId, String jwtToken, String practitionerId) {
this.visitDate = now;
this.description = description;
this.petId = petId;
+ this.ownerId = ownerId;
+ this.jwtToken = jwtToken;
this.practitionerId = practitionerId;
this.status = Status.UPCOMING;
}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitResponseDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitResponseDTO.java
index 2a5a43a4ed..fe2f6c9579 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitResponseDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitResponseDTO.java
@@ -7,6 +7,7 @@
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
+import java.util.Date;
@Data
@AllArgsConstructor
@@ -14,10 +15,17 @@
@Builder
public class VisitResponseDTO {
private String visitId;
-@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
-private LocalDateTime visitDate;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+ private LocalDateTime visitDate;
private String description;
private String petId;
+ private String petName;
+ private Date petBirthDate;
private String practitionerId;
+ private String vetFirstName;
+ private String vetLastName;
+ private String vetEmail;
+ private String vetPhoneNumber;
private Status status;
}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ExistingVetNotFoundException.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ExistingVetNotFoundException.java
index 7022f7cfd0..81c4e30420 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ExistingVetNotFoundException.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ExistingVetNotFoundException.java
@@ -1,10 +1,12 @@
package com.petclinic.bffapigateway.exceptions;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Data
+@EqualsAndHashCode(callSuper = false)
@Getter
public class ExistingVetNotFoundException extends RuntimeException{
public HttpStatus httpStatus;
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/GenericHttpException.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/GenericHttpException.java
index 10270ed821..9f251fb0b9 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/GenericHttpException.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/GenericHttpException.java
@@ -1,6 +1,7 @@
package com.petclinic.bffapigateway.exceptions;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import org.springframework.http.HttpStatus;
/**
@@ -12,6 +13,7 @@
*/
@Data
+@EqualsAndHashCode(callSuper = false)
public class GenericHttpException extends RuntimeException {
private HttpStatus httpStatus;
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/HttpErrorInfo.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/HttpErrorInfo.java
index 9dbed14c57..7fc20da684 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/HttpErrorInfo.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/HttpErrorInfo.java
@@ -1,6 +1,7 @@
package com.petclinic.bffapigateway.exceptions;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import java.time.ZoneOffset;
@@ -15,6 +16,7 @@
* Ticket: feat(APIG-CPC-354)
*/
@Data
+@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class HttpErrorInfo {
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InvalidInputsInventoryException.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InvalidInputsInventoryException.java
index 317c98571b..982c1a89b1 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InvalidInputsInventoryException.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InvalidInputsInventoryException.java
@@ -1,10 +1,12 @@
package com.petclinic.bffapigateway.exceptions;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Data
+@EqualsAndHashCode(callSuper = false)
@Getter
public class InvalidInputsInventoryException extends RuntimeException {
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InventoryNotFoundException.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InventoryNotFoundException.java
index 3c26855354..1dc20b44b6 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InventoryNotFoundException.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/InventoryNotFoundException.java
@@ -2,10 +2,12 @@
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Data
+@EqualsAndHashCode(callSuper = false)
@Getter
public class InventoryNotFoundException extends RuntimeException{
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ProductListNotFoundException.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ProductListNotFoundException.java
index 93d9ffb983..c5dd387960 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ProductListNotFoundException.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/exceptions/ProductListNotFoundException.java
@@ -1,9 +1,11 @@
package com.petclinic.bffapigateway.exceptions;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Data
+@EqualsAndHashCode(callSuper = false)
@Getter
public class ProductListNotFoundException extends RuntimeException{
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java
index 5ef92f2593..1c32f41149 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java
@@ -8,10 +8,7 @@
import com.petclinic.bffapigateway.dtos.CustomerDTOs.OwnerRequestDTO;
import com.petclinic.bffapigateway.dtos.Inventory.*;
import com.petclinic.bffapigateway.dtos.CustomerDTOs.OwnerResponseDTO;
-import com.petclinic.bffapigateway.dtos.Pets.PetRequestDTO;
-import com.petclinic.bffapigateway.dtos.Pets.PetResponseDTO;
-import com.petclinic.bffapigateway.dtos.Pets.PetType;
-import com.petclinic.bffapigateway.dtos.Pets.PetTypeResponseDTO;
+import com.petclinic.bffapigateway.dtos.Pets.*;
import com.petclinic.bffapigateway.dtos.Vets.*;
import com.petclinic.bffapigateway.dtos.Visits.VisitRequestDTO;
import com.petclinic.bffapigateway.utils.Security.Annotations.IsUserSpecific;
@@ -24,13 +21,14 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Map;
-import java.util.List;
import java.util.Optional;
/**
@@ -125,6 +123,11 @@ public Mono> updateBill(@PathVariable String bil
.defaultIfEmpty(ResponseEntity.notFound().build());
}
+ @DeleteMapping(value = "bills")
+ public Mono deleteAllBills(){
+ return billServiceClient.deleteAllBills();
+ }
+
@SecuredEndpoint(allowedRoles = {Roles.ADMIN})
@DeleteMapping(value = "bills/{billId}")
public Mono> deleteBill(final @PathVariable String billId){
@@ -258,8 +261,9 @@ public Mono getVisitByVisitId(@PathVariable String visitId){
return visitsServiceClient.getVisitByVisitId(visitId);
}
@PostMapping(value = "visit/owners/{ownerId}/pets/{petId}/visits", consumes = "application/json", produces = "application/json")
- Mono> addVisit(@RequestBody VisitRequestDTO visit, @PathVariable String ownerId, @PathVariable String petId) {
- // visit.setPetId(petId);
+ Mono> addVisit(@RequestBody VisitRequestDTO visit, @PathVariable String ownerId, /*@PathVariable String petId,*/ @CookieValue("Bearer") String auth) {
+ visit.setOwnerId(ownerId);
+ visit.setJwtToken(auth);
return visitsServiceClient.createVisitForPet(visit).map(ResponseEntity.status(HttpStatus.CREATED)::body)
.defaultIfEmpty(ResponseEntity.badRequest().build());
}
@@ -349,6 +353,13 @@ public Mono> getPhotoByVetId(@PathVariable String vetId
.map(r -> ResponseEntity.ok().header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_JPEG_VALUE).body(r))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
+ @SecuredEndpoint(allowedRoles = {Roles.ANONYMOUS})
+ @GetMapping("vets/{vetId}/default-photo")
+ public Mono> getDefaultPhotoByVetId(@PathVariable String vetId) {
+ return vetsServiceClient.getDefaultPhotoByVetId(vetId)
+ .map(r -> ResponseEntity.ok().body(r))
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+ }
@PostMapping(value = "vets/{vetId}/photos/{photoName}")
public Mono> addPhoto(@PathVariable String vetId, @PathVariable String photoName, @RequestBody Mono image) {
@@ -756,13 +767,20 @@ public Mono> updateUserRoles(final @PathVariable
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
-
+
@SecuredEndpoint(allowedRoles = {Roles.ADMIN})
@GetMapping(value = "users/{userId}", produces = MediaType.APPLICATION_JSON_VALUE)
public Mono getUserById(@PathVariable String userId, @CookieValue("Bearer") String auth) {
return authServiceClient.getUserById(auth, userId);
}
+ @SecuredEndpoint(allowedRoles = {Roles.ADMIN})
+ @DeleteMapping(value = "users/{userId}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public Mono> deleteUserById(@PathVariable String userId, @CookieValue("Bearer") String auth) {
+ return authServiceClient.deleteUser(auth, userId)
+ .then(Mono.just(ResponseEntity.noContent().build()))
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+ }
@SecuredEndpoint(allowedRoles = {Roles.ANONYMOUS})
@PostMapping(value = "/users/login",produces = "application/json;charset=utf-8;", consumes = "application/json")
@@ -772,6 +790,12 @@ public Mono> login(@RequestBody Mono
}
+ @SecuredEndpoint(allowedRoles = {Roles.ANONYMOUS})
+ @PostMapping("/users/logout")
+ public Mono> logout(ServerHttpRequest request, ServerHttpResponse response) {
+ return authServiceClient.logout(request, response);
+ }
+
@SecuredEndpoint(allowedRoles = {Roles.ANONYMOUS})
@PostMapping(value = "/users/forgot_password")
@@ -780,18 +804,29 @@ public Mono> processForgotPassword(@RequestBody Mono> processResetPassword(@RequestBody @Valid Mono resetRequest) {
return authServiceClient.changePassword(resetRequest);
}
+
+ @SecuredEndpoint(allowedRoles = {Roles.ADMIN})
+ @PostMapping(value = "/users/inventoryManager")
+ public Mono> createInventoryManager(@RequestBody @Valid Mono model) {
+ return authServiceClient.createInventoryMangerUser(model).map(s -> ResponseEntity.status(HttpStatus.CREATED).body(s))
+ .defaultIfEmpty(ResponseEntity.badRequest().build());
+ }
+
/**
* End of Auth Methods
**/
//Start of Inventory Methods
@GetMapping("/inventory/{inventoryId}/products-pagination")
+ @SecuredEndpoint(allowedRoles = {Roles.ADMIN,Roles.INVENTORY_MANAGER, Roles.VET})
public Flux getProductsInInventoryByInventoryIdAndProductFieldPagination(@PathVariable String inventoryId,
@RequestParam(required = false) String productName,
@RequestParam(required = false) Double productPrice,
@@ -802,6 +837,7 @@ public Flux getProductsInInventoryByInventoryIdAndProductFie
}
@GetMapping("/inventory/{inventoryId}/products-count")
+ @SecuredEndpoint(allowedRoles = {Roles.ADMIN,Roles.INVENTORY_MANAGER,Roles.VET})
public Mono> getTotalNumberOfProductsWithRequestParams(@PathVariable String inventoryId,
@RequestParam(required = false) String productName,
@RequestParam(required = false) Double productPrice,
@@ -810,6 +846,7 @@ public Mono> getTotalNumberOfProductsWithRequestParams(@Pat
.map(response -> ResponseEntity.status(HttpStatus.OK).body(response));
}
@PostMapping(value = "inventory/{inventoryId}/products")
+ @SecuredEndpoint(allowedRoles = {Roles.ADMIN,Roles.INVENTORY_MANAGER})
public Mono> addProductToInventory(@RequestBody ProductRequestDTO model, @PathVariable String inventoryId){
return inventoryServiceClient.addProductToInventory(model, inventoryId)
.map(s -> ResponseEntity.status(HttpStatus.CREATED).body(s))
@@ -942,4 +979,42 @@ public Flux getAllPetTypes() {
.map(addVisitsToOwner(n))
);*/
}
+
+ @IsUserSpecific(idToMatch = {"petTypeId"}, bypassRoles = {Roles.ALL})
+ @GetMapping(value = "owners/petTypes/{petTypeId}")
+ public Mono> getPetTypeById(final @PathVariable String petTypeId) {
+ return customersServiceClient.getPetTypeByPetTypeId(petTypeId)
+ .map(petTypeResponseDTO -> ResponseEntity.status(HttpStatus.OK).body(petTypeResponseDTO))
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+
+ /*.flatMap(owner ->
+ visitsServiceClient.getVisitsForPets(owner.getPetIds())
+ .map(addVisitsToOwner(owner))
+ );*/
+ }
+ @IsUserSpecific(idToMatch = {"petTypeId"}, bypassRoles = {Roles.ADMIN})
+ @DeleteMapping(value = "owners/petTypes/{petTypeId}")
+ public Mono> deletePetTypeByPetTypeId(final @PathVariable String petTypeId){
+ return customersServiceClient.deletePetType(petTypeId).then(Mono.just(ResponseEntity.noContent().build()))
+ .defaultIfEmpty(ResponseEntity.notFound().build());
+ }
+
+ @IsUserSpecific(idToMatch = {"petTypeId"})
+ @PutMapping("owners/petTypes/{petTypeId}")
+ public Mono> updatePetType(
+ @PathVariable String petTypeId,
+ @RequestBody Mono petTypeRequestMono) {
+ return petTypeRequestMono.flatMap(petTypeRequestDTO ->
+ customersServiceClient.updatePetType(petTypeId, Mono.just(petTypeRequestDTO))
+ .map(updatedOwner -> ResponseEntity.ok().body(updatedOwner))
+ .defaultIfEmpty(ResponseEntity.notFound().build())
+ );
+ }
+
+
+
+
+
+
+
}
\ No newline at end of file
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/IsUserSpecific.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/IsUserSpecific.java
index a002db07c8..12abe51b38 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/IsUserSpecific.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/IsUserSpecific.java
@@ -14,24 +14,25 @@
*
* When present, this annotation will require a valid token and will check if the user id in the token matches the id specified in the annotation.
* You specify which fields need to match in the idToMatch field.
- * This means that if you specify the idToMatch field as {"ownerId"} it will match the path variable called ownerId and the JWS id field.
- * You can add as many fields as you want to the idToMatch field, this will check if the JWS id matched any of the path variables.
+ * This means that if you specify the idToMatch field as {"ownerId"} it will match the path variable called ownerId and the JWT id field.
+ * You can add as many fields as you want to the idToMatch field, this will check if the JWT id matched any of the path variables.
*
*
- *
+ *
*
* The bypass role field is used to specify which roles can bypass this annotation.
* This means if Vet is specified, any vet can access this endpoint, but any owners will need to be the concerned owner.
* If Admin is specified, any admin can access this endpoint, but any owners or vets will need to be the concerned owner.
+ * If an empty array is specified, only the concerned owner can access this endpoint and no role will bypass this requirement.
*
- *
+ *
*
* WARNING : If you specify ANONYMOUS or ALL this annotation is redundant.
*
*
*
* If no roles are specified ADMIN is default.
- *
+ *
* @author Dylan Brassard
* @since 2023-09-27
* @see SecuredEndpoint
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/SecuredEndpoint.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/SecuredEndpoint.java
index 50dc77f71f..e36285f7c9 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/SecuredEndpoint.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/utils/Security/Annotations/SecuredEndpoint.java
@@ -8,13 +8,13 @@
/**
- * Annotation for securing an endpoint with a list of roles.
+ * Annotation for securing an endpoint with a list of roles.
*
*
*
* Note : If All is specified, the endpoint will be accessible by all roles.
* And if Anonymous is specified, the endpoint will be accessible by all roles and all non authenticated users.
- * Also if anonymous is specified, all other roles will be ignored everyone is allowed.
+ * Also if anonymous is specified, all other roles in the array will be ignored since everyone is allowed.
*
*
* If this annotation is not present it will require a valid token but won't look for any roles, basically the default when
diff --git a/api-gateway/src/main/resources/static/index.html b/api-gateway/src/main/resources/static/index.html
index 1f84eb244d..684cee39f2 100755
--- a/api-gateway/src/main/resources/static/index.html
+++ b/api-gateway/src/main/resources/static/index.html
@@ -44,6 +44,8 @@
+
+
@@ -68,6 +70,10 @@
+
+
+
+
@@ -92,6 +98,10 @@
+
+
+
+
@@ -188,11 +198,18 @@
+
+
+
+
+
+
+
diff --git a/api-gateway/src/main/resources/static/scripts/app.js b/api-gateway/src/main/resources/static/scripts/app.js
index 322672a16a..daf9660120 100644
--- a/api-gateway/src/main/resources/static/scripts/app.js
+++ b/api-gateway/src/main/resources/static/scripts/app.js
@@ -10,9 +10,9 @@ const whiteList = new Set([
/* App Module */
const petClinicApp = angular.module('petClinicApp', [
'ui.router', 'layoutNav', 'layoutFooter', 'layoutWelcome', 'ownerList', 'ownerDetails', 'ownerForm', 'ownerRegister', 'petRegister', 'petForm'
- , 'visits', 'vetList','vetForm','vetDetails', 'visitList', 'billForm', 'billUpdateForm', 'loginForm', 'rolesDetails', 'signupForm', 'productDetailsInfo',
+ , 'visits', 'visit', 'visitList' , 'vetList','vetForm','vetDetails', 'billForm', 'billUpdateForm', 'loginForm', 'rolesDetails', 'signupForm', 'productDetailsInfo',
'billDetails', 'billsByOwnerId', 'billHistory','billsByVetId','inventoryList', 'inventoryForm', 'productForm','inventoryProductList', 'inventoryUpdateForm', 'productUpdateForm',
- 'verification' , 'adminPanel','resetPwdForm','forgotPwdForm','petTypeList', 'petDetails','userDetails']);
+ 'verification' , 'adminPanel','resetPwdForm','forgotPwdForm','petTypeList', 'petDetails','userDetails','managerForm','userModule']);
diff --git a/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.controller.js b/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.controller.js
index 9996ea15ed..44aaf458c5 100644
--- a/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.controller.js
+++ b/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.controller.js
@@ -1,6 +1,6 @@
'use strict';
angular.module('adminPanel')
- .controller('AdminPanelController', ['$http', '$scope', "authProvider", function ($http, $scope, authProvider) {
+ .controller('AdminPanelController', ['$http', '$scope', "authProvider", "$window", function ($http, $scope, authProvider, $window) {
var self = this;
self.users = []
@@ -20,11 +20,24 @@ angular.module('adminPanel')
console.log("EventSource error: "+error)
}
}
-
- $scope.startsWith = function (actual, expected) {
- let lowerStr = (actual + "").toLowerCase();
- let lowerExpected = (expected + "").toLowerCase();
- return lowerStr.indexOf(lowerExpected) === 0;
+
+ $scope.search = function () {
+ if ($scope.query === '') {
+ $http.get('api/gateway/users', {
+ headers: {'Authorization': "Bearer " + authProvider.getUser().token}
+ })
+ .then(function (resp) {
+ self.users = resp.data;
+ });
+ } else {
+ $http.get('api/gateway/users', {
+ params: { username: $scope.query },
+ headers: {'Authorization': "Bearer " + authProvider.getUser().token}
+ })
+ .then(function (resp) {
+ self.users = resp.data;
+ });
+ }
};
@@ -32,12 +45,16 @@ angular.module('adminPanel')
$http.delete('api/gateway/users/' + userid, {
headers: {'Authorization': "Bearer " + authProvider.getUser().token}})
.then(function () {
- $http.get('api/gateway/users', {
- headers: {'Authorization': "Bearer " + authProvider.getUser().token}})
- .then(function (resp) {
- self.users = resp.data;
+ $http.get('api/gateway/users', {
+ headers: {'Authorization': "Bearer " + authProvider.getUser().token}})
+ .then(function (resp) {
+ self.users = resp.data;
+ alert("User has been deleted successfully.");
+ $window.location.reload();
+ });
});
- });
};
+
+
}
]);
diff --git a/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html b/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html
index eb58e8668c..1cd6933c8d 100644
--- a/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html
+++ b/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html
@@ -12,11 +12,12 @@ Users
Username
Email
+ Role
Options
-
+
{{ user.username }}
@@ -24,12 +25,22 @@ Users
{{user.email}}
-
+
+
+ {{ role.name }},
+
+
+
+
+ Update Role
-
+
Add Vet
+
+ Add Inventory Manager
+
diff --git a/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.component.js b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.component.js
new file mode 100644
index 0000000000..86894e06d1
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.component.js
@@ -0,0 +1,7 @@
+'use strict';
+
+angular.module('managerForm')
+ .component('managerForm', {
+ templateUrl: 'scripts/auth/manager-form/manager-form.template.html',
+ controller: 'managerFormController'
+ });
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.controller.js b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.controller.js
new file mode 100644
index 0000000000..daaccde3f7
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.controller.js
@@ -0,0 +1,34 @@
+'use strict';
+
+angular.module('managerForm')
+ .controller('managerFormController', ['$http', '$scope', "$location", "authProvider", function ($http, $scope, $location, authProvider) {
+
+ let loaderDiv = document.getElementById("loaderDiv");
+ loaderDiv.style.display = "none";
+
+ this.add = () => {
+ loaderDiv.style.display = "block";
+ $http.post('/api/gateway/users/inventoryManager', {
+ username: $scope.signup.username,
+ password: $scope.signup.password,
+ email: $scope.signup.email
+ })
+ .then(() => {
+ loaderDiv.style.display = "none";
+ alert("Email was sent !");
+ $location.path("/adminPanel")
+ })
+ .catch(n => {
+ loaderDiv.style.display = "none";
+ console.log(n);
+ try {
+ $scope.errorMessages = n.data.password.split`\n`;
+ }
+ catch (e) {
+ $scope.errorMessages = n.data.message.split`\n`;
+ }
+ });
+ }
+
+ this.keypress = ({ originalEvent: { key } }) => key === 'Enter' && this.add()
+ }]);
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.js b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.js
new file mode 100644
index 0000000000..feab07e7e5
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.js
@@ -0,0 +1,11 @@
+'use strict';
+
+angular.module('managerForm', ['ui.router'])
+ .config(['$stateProvider', function ($stateProvider) {
+ $stateProvider
+ .state('managerForm', {
+ parent: 'app',
+ url: '/manager',
+ template: ' '
+ })
+ }]);
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.template.html b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.template.html
new file mode 100644
index 0000000000..fc2e1fe54a
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/manager-form/manager-form.template.html
@@ -0,0 +1,142 @@
+
+
+
Signup
+
+
+
×
+
Error: {{ error }}
+
+
+ Username
+
+ Username is required.
+
+
+
+
+
+
+
+
+
diff --git a/api-gateway/src/main/resources/static/scripts/auth/signup/signup-form.js b/api-gateway/src/main/resources/static/scripts/auth/signup/signup-form.js
index 08f31e3a40..ba1c9d2d92 100644
--- a/api-gateway/src/main/resources/static/scripts/auth/signup/signup-form.js
+++ b/api-gateway/src/main/resources/static/scripts/auth/signup/signup-form.js
@@ -12,4 +12,4 @@ angular.module('signupForm', ['ui.router'])
url: '/signup',
template: ' '
})
- }]);
+ }])
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js
new file mode 100644
index 0000000000..c2726d3ee9
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js
@@ -0,0 +1,10 @@
+'use strict';
+
+angular.module('userModule')
+ .component('updateUserRoleComponent', {
+ templateUrl: 'scripts/auth/update-role-form/role-update.template.html',
+ controller: 'UpdateUserRoleController',
+ bindings: {
+ userId: '<'
+ }
+ });
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js
new file mode 100644
index 0000000000..af5abd257f
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js
@@ -0,0 +1,16 @@
+'use strict';
+
+angular.module('userModule', ['ui.router'])
+ .config(['$stateProvider', function($stateProvider) {
+ $stateProvider
+ .state('updateUserRole', {
+ parent: 'app',
+ url: '/users/:userId/updateRole',
+ component: 'updateUserRoleComponent',
+ resolve: {
+ userId: ['$stateParams', function($stateParams) {
+ return $stateParams.userId;
+ }]
+ }
+ });
+ }]);
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js
new file mode 100644
index 0000000000..753496bb79
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js
@@ -0,0 +1,56 @@
+'use strict';
+
+angular.module('userModule')
+ .controller('UpdateUserRoleController', ['$scope', '$http', 'UserService', '$state', function($scope, $http, UserService, $state) {
+ var ctrl = this; // Capture the controller instance
+
+ $scope.roles = UserService.getAvailableRoles();
+ $scope.selectedRole = {};
+
+ // Use $onInit lifecycle hook to set $scope.userId
+ ctrl.$onInit = function() {
+ $scope.userId = ctrl.userId;
+ };
+
+ $scope.selectedRoles = {};
+
+ $scope.updateRole = function() {
+ var rolesList = [];
+ for (var role in $scope.selectedRoles) {
+ if ($scope.selectedRoles[role]) {
+ rolesList.push(role);
+ }
+ }
+
+ if (rolesList.length === 0) {
+ alert('Please select at least one role.');
+ return;
+ }
+
+ if (rolesList.length > 1) {
+ alert('Please select only one role.');
+ return;
+ }
+
+ var rolesChangeRequest = {
+ roles: rolesList
+ };
+
+ // Send the PATCH request
+ $http({
+ method: 'PATCH',
+ url: 'api/gateway/users/' + $scope.userId,
+ data: rolesChangeRequest,
+ headers: {
+ 'Content-Type': 'application/json',
+ // Add token headers if needed
+ }
+ })
+ .then(function successCallback(response) {
+ alert('Roles updated successfully!');
+ $state.go('AdminPanel');
+ }, function errorCallback(response) {
+ alert('Failed to update roles. ' + response.data.message);
+ });
+ };
+ }]);
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js
new file mode 100644
index 0000000000..fbf12f6add
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js
@@ -0,0 +1,8 @@
+'use strict';
+
+angular.module('userModule').service('UserService', [function() {
+ this.getAvailableRoles = function() {
+ return ['ADMIN', 'VET', 'OWNER'];
+ };
+
+}]);
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html
new file mode 100644
index 0000000000..be352a7b03
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html
@@ -0,0 +1,12 @@
+Update User Role
+
diff --git a/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.controller.js b/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.controller.js
index 08f774f597..b0912e0779 100644
--- a/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.controller.js
+++ b/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.controller.js
@@ -1,7 +1,7 @@
'use strict';
angular.module('userDetails')
- .controller('UserDetailsController', ['$http', '$stateParams', function ($http, $stateParams, $scope) {
+ .controller('UserDetailsController', ['$http', '$stateParams', '$location', function ($http, $stateParams, $location) {
let self = this;
self.userId = $stateParams.userId;
@@ -14,5 +14,8 @@ angular.module('userDetails')
.catch(function (error) {
$scope.errorMessages = n.data.message.split`\n`;
});
- }]);
+ self.goToAdminPanel = function() {
+ $location.path("/adminPanel");
+ }
+ }]);
diff --git a/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.template.html b/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.template.html
index 2041e44462..107a5aa0f3 100644
--- a/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.template.html
+++ b/api-gateway/src/main/resources/static/scripts/auth/user-details/user-details.template.html
@@ -4,39 +4,35 @@
Title
-
-
-
User Details for ID: {{ userDetails.userId }}
-
Username: {{ userDetails.user ? userDetails.user.username : 'N/A' }}
-
Email: {{ userDetails.user ? userDetails.user.email : 'N/A' }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-