diff --git a/.github/workflows/dockerHub-publish.yml b/.github/workflows/dockerHub-publish.yml new file mode 100644 index 0000000..a538212 --- /dev/null +++ b/.github/workflows/dockerHub-publish.yml @@ -0,0 +1,77 @@ +name: CI/CD Pipeline + +on: + push: + branches: + - dev-yesitha + +jobs: + build: + runs-on: ubuntu-latest + + services: + db: + image: postgres + env: + POSTGRES_DB: itgura + POSTGRES_USER: postgres + POSTGRES_PASSWORD: root + ports: + - 5432:5432 + options: --health-cmd "pg_isready -U postgres" --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up JDK 17 + uses: actions/setup-java@v2 + with: + distribution: 'adopt' + java-version: '17' + + - name: Wait for PostgreSQL + run: | + echo "Waiting for PostgreSQL to be ready..." + until pg_isready -h localhost -p 5432 -U postgres; do + sleep 1 + done + + - name: Initialize Database + run: | + psql -v ON_ERROR_STOP=1 --host=localhost --username=postgres --dbname=itgura <<-EOSQL + CREATE SCHEMA resource_management; + CREATE SCHEMA payment_service; + CREATE SCHEMA auth_service; + EOSQL + env: + PGPASSWORD: root + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Build and publish Docker image + run: mvn clean package -P build-docker-image + env: + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + # deploy: + # needs: build + # runs-on: ubuntu-latest + + # steps: + # - name: Checkout code + # uses: actions/checkout@v2 + + # - name: Deploy to Server + # run: | + # ssh user@your-server "docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/your-image-name:latest && docker-compose up -d" + # env: + # DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + # DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + # SERVER_SSH_USERNAME: ${{ secrets.SERVER_SSH_USERNAME }} + # SERVER_SSH_PASSWORD: ${{ secrets.SERVER_SSH_PASSWORD }} diff --git a/.gitignore b/.gitignore index 511fc24..f54ed0a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ auth-service/mvnw.cmd resource-management/resource-management-all/target/resource-management-all-1.0.0.jar.original *.lst /target/* +auth-service/src/main/resources/application.properties diff --git a/auth-service/pom.xml b/auth-service/pom.xml index 2640a0d..a043a7a 100644 --- a/auth-service/pom.xml +++ b/auth-service/pom.xml @@ -3,12 +3,12 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.2.5 - + com.itgura.lms + lms + 1.0.0 + - com.itgura + jar auth-service 0.0.1-SNAPSHOT auth-service @@ -40,11 +40,7 @@ postgresql runtime - - org.projectlombok - lombok - true - + org.springframework.boot spring-boot-starter-test @@ -93,6 +89,11 @@ org.projectlombok lombok + + + + + @@ -106,19 +107,48 @@ + + + + + + + + + + + + + + + + + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + org.springframework.boot spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - diff --git a/auth-service/src/main/java/com/itgura/authservice/AuthServiceApplication.java b/auth-service/src/main/java/com/itgura/authservice/AuthServiceApplication.java index 310cda2..aac478d 100644 --- a/auth-service/src/main/java/com/itgura/authservice/AuthServiceApplication.java +++ b/auth-service/src/main/java/com/itgura/authservice/AuthServiceApplication.java @@ -13,3 +13,5 @@ public static void main(String[] args) { } } + + diff --git a/auth-service/src/main/java/com/itgura/authservice/config/JwtAuthenticationFilter.java b/auth-service/src/main/java/com/itgura/authservice/config/JwtAuthenticationFilter.java index 4472343..1e635da 100644 --- a/auth-service/src/main/java/com/itgura/authservice/config/JwtAuthenticationFilter.java +++ b/auth-service/src/main/java/com/itgura/authservice/config/JwtAuthenticationFilter.java @@ -36,23 +36,23 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, final String authHeader = request.getHeader("Authorization"); final String jwt; final String userEmail; - if(StringUtils.isEmpty(authHeader) || StringUtils.startsWith(authHeader,"Bearer ")){ + + if (StringUtils.isEmpty(authHeader) || !StringUtils.startsWith(authHeader, "Bearer ")) { filterChain.doFilter(request, response); return; + } jwt = authHeader.substring(7);//Bearer length is 7 userEmail = jwtService.extractUserName(jwt);//todo extract userEmail from jwt Token -if(StringUtils.isNotEmpty(userEmail) && SecurityContextHolder.getContext().getAuthentication() == null){ - UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail); - if(jwtService.isTokenValid(jwt, userDetails)){ - UsernamePasswordAuthenticationToken authToken =new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities()); - authToken.setDetails( - new WebAuthenticationDetailsSource().buildDetails(request) - ); - SecurityContextHolder.getContext().setAuthentication(authToken); - } + if (StringUtils.isNotEmpty(userEmail) && SecurityContextHolder.getContext().getAuthentication() == null) { + UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail); + if (jwtService.isTokenValid(jwt, userDetails)) { + UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authToken); + } } - filterChain.doFilter(request,response); + filterChain.doFilter(request, response); } } diff --git a/auth-service/src/main/java/com/itgura/authservice/controller/AdminController.java b/auth-service/src/main/java/com/itgura/authservice/controller/AdminController.java index 8f9f9db..f73c511 100644 --- a/auth-service/src/main/java/com/itgura/authservice/controller/AdminController.java +++ b/auth-service/src/main/java/com/itgura/authservice/controller/AdminController.java @@ -1,13 +1,19 @@ package com.itgura.authservice.controller; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +@CrossOrigin(origins = "*", allowedHeaders = "*") @RestController @RequestMapping("api/v1/admin") -@RequiredArgsConstructor + public class AdminController { + @PostMapping("/testAdmin") + public ResponseEntity seyHello() { + return ResponseEntity.ok("Hello from Admin Controller!"); + } + } diff --git a/auth-service/src/main/java/com/itgura/authservice/controller/AuthenticationController.java b/auth-service/src/main/java/com/itgura/authservice/controller/AuthenticationController.java index 11f53aa..5cd4dd4 100644 --- a/auth-service/src/main/java/com/itgura/authservice/controller/AuthenticationController.java +++ b/auth-service/src/main/java/com/itgura/authservice/controller/AuthenticationController.java @@ -3,15 +3,19 @@ import com.itgura.authservice.dto.request.AuthenticationRequest; import com.itgura.authservice.dto.request.RegisterRequest; +import com.itgura.authservice.dto.request.changeRoleRequest; import com.itgura.authservice.dto.response.AuthenticationResponse; import com.itgura.authservice.services.AuthenticationService; import com.itgura.dto.AppResponse; +import com.itgura.exception.ApplicationException; +import com.itgura.exception.ValueNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController +@CrossOrigin(origins = "*", allowedHeaders = "*") @RequestMapping("/api/v1/auth-service") @RequiredArgsConstructor public class AuthenticationController { @@ -63,5 +67,22 @@ public AppResponse validateToken(@RequestParam("token") String token){ } } + //ToDo: Remove this endpoint after testing + + @PostMapping("/changeUserRole") + public AppResponse changeUserRole(@RequestBody changeRoleRequest role) { + { + try { + return AppResponse.ok(authenticationService.changeUserRole(role)); + } catch (ValueNotFoundException e) { + return AppResponse.error(null, "Value not found", "404", "", e.getMessage()); + } catch (ApplicationException e) { + return AppResponse.error(null, "Application Error", "500", "", e.getMessage()); + } + + + } + } + } diff --git a/auth-service/src/main/java/com/itgura/authservice/controller/StudentController.java b/auth-service/src/main/java/com/itgura/authservice/controller/StudentController.java index f71ef2f..80286eb 100644 --- a/auth-service/src/main/java/com/itgura/authservice/controller/StudentController.java +++ b/auth-service/src/main/java/com/itgura/authservice/controller/StudentController.java @@ -1,10 +1,12 @@ package com.itgura.authservice.controller; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@CrossOrigin(origins = "*", allowedHeaders = "*") @RequestMapping("api/v1/student") @RequiredArgsConstructor public class StudentController { diff --git a/auth-service/src/main/java/com/itgura/authservice/controller/TeacherController.java b/auth-service/src/main/java/com/itgura/authservice/controller/TeacherController.java index 699a568..a3c1798 100644 --- a/auth-service/src/main/java/com/itgura/authservice/controller/TeacherController.java +++ b/auth-service/src/main/java/com/itgura/authservice/controller/TeacherController.java @@ -1,10 +1,12 @@ package com.itgura.authservice.controller; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@CrossOrigin(origins = "*", allowedHeaders = "*") @RequestMapping("api/v1/teacher") @RequiredArgsConstructor public class TeacherController { diff --git a/user-management/user-management-dao/src/main/java/com/itgura/dto/request/AuthenticationRequest.java b/auth-service/src/main/java/com/itgura/authservice/dto/request/changeRoleRequest.java similarity index 57% rename from user-management/user-management-dao/src/main/java/com/itgura/dto/request/AuthenticationRequest.java rename to auth-service/src/main/java/com/itgura/authservice/dto/request/changeRoleRequest.java index 9825a49..853f7f6 100644 --- a/user-management/user-management-dao/src/main/java/com/itgura/dto/request/AuthenticationRequest.java +++ b/auth-service/src/main/java/com/itgura/authservice/dto/request/changeRoleRequest.java @@ -1,4 +1,5 @@ -package com.itgura.dto.request; +package com.itgura.authservice.dto.request; + import lombok.AllArgsConstructor; import lombok.Builder; @@ -9,7 +10,6 @@ @Builder @AllArgsConstructor @NoArgsConstructor -public class AuthenticationRequest { - private String email; - private String password; +public class changeRoleRequest { + private String changeRole; } diff --git a/auth-service/src/main/java/com/itgura/authservice/services/AuthenticationService.java b/auth-service/src/main/java/com/itgura/authservice/services/AuthenticationService.java index d58aa6c..4d134fb 100644 --- a/auth-service/src/main/java/com/itgura/authservice/services/AuthenticationService.java +++ b/auth-service/src/main/java/com/itgura/authservice/services/AuthenticationService.java @@ -2,21 +2,36 @@ import com.itgura.authservice.dto.request.AuthenticationRequest; import com.itgura.authservice.dto.request.RegisterRequest; +import com.itgura.authservice.dto.request.changeRoleRequest; import com.itgura.authservice.dto.response.AuthenticationResponse; import com.itgura.authservice.entity.Role; import com.itgura.authservice.entity.User; import com.itgura.authservice.repository.UserRepository; +import com.itgura.exception.ApplicationException; +import com.itgura.exception.ValueNotExistException; +import com.itgura.util.UserUtil; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.HashMap; +import java.util.Optional; @Service @RequiredArgsConstructor public class AuthenticationService { + + @Value("${jwt.secretKey}") + private String SECRET_KEY; + + private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final JwtService jwtService; @@ -65,4 +80,35 @@ public AuthenticationResponse refreshToken(String refreshToken) { public Boolean validateToken(String token) { return jwtService.validateToken(token); } + + public String changeUserRole( changeRoleRequest role) throws ApplicationException { + + + String authorizationHeader = UserUtil.extractToken(); + if (!authorizationHeader.isBlank()) { + + String token = authorizationHeader; + + Claims claims = Jwts.parser() + .setSigningKey(SECRET_KEY) // Replace with your actual secret key + .build() + .parseClaimsJws(token) + .getBody(); + + String email = claims.getSubject(); + Optional user = userRepository.findByEmail(email); + + if (user.isPresent()) { + user.get().setRole(Role.valueOf(role.getChangeRole())); + userRepository.save(user.get()); + return "Role changed successfully"; + }else { + throw new ValueNotExistException("User not found"); + } + + }else { + throw new ApplicationException("Token not found"); + } + + } } diff --git a/auth-service/src/main/resources/application-docker.properties b/auth-service/src/main/resources/application-docker.properties new file mode 100644 index 0000000..fcfcb84 --- /dev/null +++ b/auth-service/src/main/resources/application-docker.properties @@ -0,0 +1,25 @@ +spring.application.name=auth-service +server.port=8098 + +#datasource configuration +#spring.datasource.url=jdbc:postgresql://dpg-cp2qofi1hbls738314e0-a.oregon-postgres.render.com:5432/it_gura +#spring.datasource.username= it_gura_user +#spring.datasource.password= lsbflvJ0HfdVIgbHNbCEZnzV3o9SAErn +#spring.datasource.hikari.schema=auth_service +spring.datasource.url=jdbc:postgresql://postgres-main:5432/itgura +spring.datasource.username=postgres +spring.datasource.password=root +spring.datasource.hikari.schema=auth_service +spring.datasource.driver-class-name=org.postgresql.Driver +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.format_sql=true + + +# eureka +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=eureka-server +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 \ No newline at end of file diff --git a/auth-service/src/main/resources/application-kube.properties b/auth-service/src/main/resources/application-kube.properties new file mode 100644 index 0000000..a45455c --- /dev/null +++ b/auth-service/src/main/resources/application-kube.properties @@ -0,0 +1,30 @@ +spring.application.name=auth-service +server.port=8098 + +#datasource configuration +#spring.datasource.url=jdbc:postgresql://dpg-cp2qofi1hbls738314e0-a.oregon-postgres.render.com:5432/it_gura +#spring.datasource.username= it_gura_user +#spring.datasource.password= lsbflvJ0HfdVIgbHNbCEZnzV3o9SAErn +#spring.datasource.hikari.schema=auth_service +spring.datasource.url=jdbc:postgresql://postgres/itgura +spring.datasource.username=postgres +spring.datasource.password=root +spring.datasource.hikari.schema=auth_service +spring.datasource.driver-class-name=org.postgresql.Driver +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.format_sql=true + +#linkered +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lower-case-service-id=true + + +# eureka +eureka.client.enabled=false +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=eureka-server +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 \ No newline at end of file diff --git a/auth-service/src/main/resources/application.properties b/auth-service/src/main/resources/application.properties index acea25a..f02958b 100644 --- a/auth-service/src/main/resources/application.properties +++ b/auth-service/src/main/resources/application.properties @@ -1,6 +1,12 @@ spring.application.name=auth-service server.port=8098 +# eureka +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=localhost +eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka + #datasource configuration #spring.datasource.url=jdbc:postgresql://dpg-cp2qofi1hbls738314e0-a.oregon-postgres.render.com:5432/it_gura #spring.datasource.username= it_gura_user @@ -8,7 +14,7 @@ server.port=8098 #spring.datasource.hikari.schema=auth_service spring.datasource.url=jdbc:postgresql://localhost:5432/itgura spring.datasource.username=postgres -spring.datasource.password=1234 +spring.datasource.password=root spring.datasource.hikari.schema=auth_service spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.show-sql=true @@ -16,10 +22,6 @@ spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.format_sql=true -# eureka -eureka.client.register-with-eureka=true -eureka.client.fetch-registry=true -eureka.instance.hostname=localhost -eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka + jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 \ No newline at end of file diff --git a/ca.crt b/ca.crt new file mode 100644 index 0000000..6d5bec3 Binary files /dev/null and b/ca.crt differ diff --git a/config/alfresco-global.properties b/config/alfresco-global.properties new file mode 100644 index 0000000..e591102 --- /dev/null +++ b/config/alfresco-global.properties @@ -0,0 +1,10 @@ +dir.keystore=${dir.root}/keystore +keystore.type=JCEKS +ssl.keystore.location=${dir.keystore}/ssl.keystore +ssl.keystore.type=JCEKS +ssl.truststore.location=${dir.keystore}/ssl.truststore +ssl.truststore.type=JCEKS + + + + diff --git a/config/solrcore.properties b/config/solrcore.properties new file mode 100644 index 0000000..1d3c741 --- /dev/null +++ b/config/solrcore.properties @@ -0,0 +1,6 @@ +dir.keystore=${dir.root}/keystore +ssl.keystore.location=${dir.keystore}/ssl.repo.client.keystore +ssl.keystore.type=JCEKS +ssl.truststore.location=${dir.keystore}/ssl.repo.client.truststore +ssl.truststore.type=JCEKS +ssl.truststore.password=[your_truststore_password] \ No newline at end of file diff --git a/dms-mediator/dms-mediator-all/pom.xml b/dms-mediator/dms-mediator-all/pom.xml index 07f72fc..a0cf251 100644 --- a/dms-mediator/dms-mediator-all/pom.xml +++ b/dms-mediator/dms-mediator-all/pom.xml @@ -6,8 +6,31 @@ com.itgura.lms 1.0.0 + jar dms-mediator-all + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + + com.itgura.lms @@ -21,6 +44,7 @@ 17 17 + UTF-8 diff --git a/dms-mediator/dms-mediator-all/src/main/resources/application-docker.properties b/dms-mediator/dms-mediator-all/src/main/resources/application-docker.properties new file mode 100644 index 0000000..4586757 --- /dev/null +++ b/dms-mediator/dms-mediator-all/src/main/resources/application-docker.properties @@ -0,0 +1,52 @@ +server.port=8099 +spring.application.name=dms-mediator +#logging.level.org.springframework.core.env=DEBUG + + +spring.servlet.multipart.max-file-size=35MB +spring.servlet.multipart.max-request-size=35MB +## Alfresco +#alfresco.base.url=http://alfresco:8080/alfresco +# +#alfresco.username=admin +#alfresco.password=admin +#alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name +#alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content +#alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true +#alfresco.uploadRelativePath=/dms +# Nextcloud +nextcloud.base.url=http://nextcloud:8080 +nextcloud.username=admin +nextcloud.password=admin + + +# Upload URL Template +nextcloud.uploadUrl=/remote.php/dav/files/{username}/{path} + +# Download URL Template +nextcloud.downloadUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Delete URL Template +nextcloud.deleteUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Relative Path for Uploads +nextcloud.uploadRelativePath=/dms + +#alfresco.base.url=http://192.168.1.87:8080/alfresco + +#eureka +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka/ +eureka.client.registerWithEureka=true +eureka.client.fetchRegistry=true +eureka.instance.prefer-ip-address=true + +#swagger +#server.servlet.context-path=/ +# +#openapi.service.title=Document Mediator +#openapi.service.version=1.0 +#openapi.service.url=http://localhost:8081 +#springdoc.api-docs.path=dms-mediator/v3/api-docs +#springdoc.swagger-ui.path=dms-mediator/swagger-ui.html + + diff --git a/dms-mediator/dms-mediator-all/src/main/resources/application-kube.properties b/dms-mediator/dms-mediator-all/src/main/resources/application-kube.properties new file mode 100644 index 0000000..79f8bdb --- /dev/null +++ b/dms-mediator/dms-mediator-all/src/main/resources/application-kube.properties @@ -0,0 +1,55 @@ +server.port=8099 +spring.application.name=dms-mediator +#logging.level.org.springframework.core.env=DEBUG + + +spring.servlet.multipart.max-file-size=35MB +spring.servlet.multipart.max-request-size=35MB +## Alfresco +#alfresco.base.url=http://alfresco:8080/alfresco +# +#alfresco.username=admin +#alfresco.password=admin +#alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name +#alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content +#alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true +#alfresco.uploadRelativePath=/dms +# Nextcloud +nextcloud.base.url=http://nextcloud:8080 +nextcloud.username=admin +nextcloud.password=admin +# Upload URL +nextcloud.uploadUrl=/remote.php/dav/files/{username}/{path} + +# Download URL +nextcloud.downloadUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Delete URL +nextcloud.deleteUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Relative Path for Uploads +nextcloud.uploadRelativePath=/dms + +#alfresco.base.url=http://192.168.1.87:8080/alfresco + +#linkered +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lower-case-service-id=true + +#eureka +eureka.client.enabled=false +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka/ +eureka.client.registerWithEureka=true +eureka.client.fetchRegistry=true +eureka.instance.prefer-ip-address=true + +#swagger +#server.servlet.context-path=/ +# +#openapi.service.title=Document Mediator +#openapi.service.version=1.0 +#openapi.service.url=http://localhost:8081 +#springdoc.api-docs.path=dms-mediator/v3/api-docs +#springdoc.swagger-ui.path=dms-mediator/swagger-ui.html + + diff --git a/dms-mediator/dms-mediator-dao/pom.xml b/dms-mediator/dms-mediator-dao/pom.xml index 2a66cd0..c97807b 100644 --- a/dms-mediator/dms-mediator-dao/pom.xml +++ b/dms-mediator/dms-mediator-dao/pom.xml @@ -6,10 +6,10 @@ dms-mediator 1.0.0 + jar dms-mediator-dao - 17 - 17 + UTF-8 @@ -27,16 +27,29 @@ org.projectlombok lombok - - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.0.0 - - - org.springframework.boot - spring-boot-starter-validation - + + + + + + + + + com.google.cloud.tools + jib-maven-plugin + + + jib-execution + + build + + none + + + + + \ No newline at end of file diff --git a/dms-mediator/dms-mediator-dao/src/main/resources/application-dev.properties b/dms-mediator/dms-mediator-dao/src/main/resources/application-dev.properties index cca3956..f21c5d4 100644 --- a/dms-mediator/dms-mediator-dao/src/main/resources/application-dev.properties +++ b/dms-mediator/dms-mediator-dao/src/main/resources/application-dev.properties @@ -1,14 +1,30 @@ spring.servlet.multipart.max-file-size=35MB spring.servlet.multipart.max-request-size=35MB # Alfresco -alfresco.base.url=http://localhost:8080/alfresco - -alfresco.username=admin -alfresco.password=admin -alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name -alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content -alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true -alfresco.uploadRelativePath=/dms +#alfresco.base.url=http://localhost:8080/alfresco +# +#alfresco.username=admin +#alfresco.password=admin +#alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name +#alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content +#alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true +#alfresco.uploadRelativePath=/dms + +# Nextcloud +nextcloud.base.url=http://localhost:8080 +nextcloud.username=admin +nextcloud.password=admin +# Upload URL +nextcloud.uploadUrl=/remote.php/dav/files/{username}/{path} + +# Download URL +nextcloud.downloadUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Delete URL +nextcloud.deleteUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Relative Path for Uploads +nextcloud.uploadRelativePath=/dms #alfresco.base.url=http://192.168.1.87:8080/alfresco diff --git a/dms-mediator/dms-mediator-dao/src/main/resources/application-prod.properties b/dms-mediator/dms-mediator-dao/src/main/resources/application-prod.properties index 5d47cca..7cc8996 100644 --- a/dms-mediator/dms-mediator-dao/src/main/resources/application-prod.properties +++ b/dms-mediator/dms-mediator-dao/src/main/resources/application-prod.properties @@ -1,13 +1,29 @@ spring.servlet.multipart.max-file-size=35MB spring.servlet.multipart.max-request-size=35MB -# Alfresco -alfresco.base.url=http://localhost:8080/alfresco - -alfresco.username=admin -alfresco.password=admin -alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name -alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content -alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true -alfresco.uploadRelativePath=/dms +## Alfresco +#alfresco.base.url=http://localhost:8080/alfresco +# +#alfresco.username=admin +#alfresco.password=admin +#alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name +#alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content +#alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true +#alfresco.uploadRelativePath=/dms + +# Nextcloud +nextcloud.base.url=http://localhost:8080 +nextcloud.username=admin +nextcloud.password=admin +# Upload URL +nextcloud.uploadUrl=/remote.php/dav/files/{username}/{path} + +# Download URL +nextcloud.downloadUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Delete URL +nextcloud.deleteUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Relative Path for Uploads +nextcloud.uploadRelativePath=/dms #alfresco.base.url=http://192.168.1.87:8080/alfresco diff --git a/dms-mediator/dms-mediator-dao/src/main/resources/application-stg.properties b/dms-mediator/dms-mediator-dao/src/main/resources/application-stg.properties index ef561de..552dc40 100644 --- a/dms-mediator/dms-mediator-dao/src/main/resources/application-stg.properties +++ b/dms-mediator/dms-mediator-dao/src/main/resources/application-stg.properties @@ -1,14 +1,32 @@ spring.servlet.multipart.max-file-size=35MB spring.servlet.multipart.max-request-size=35MB -# Alfresco -alfresco.base.url=http://localhost:8080/alfresco - -alfresco.username=admin -alfresco.password=admin -alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name -alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content -alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true -alfresco.uploadRelativePath=/dms +## Alfresco +#alfresco.base.url=http://localhost:8080/alfresco +# +#alfresco.username=admin +#alfresco.password=admin +#alfresco.uploadUrl=/api/-default-/public/alfresco/versions/1/nodes/-my-/children?fields=id,parentId,name +#alfresco.downloadUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}/content +#alfresco.deleteUrl=/api/-default-/public/alfresco/versions/1/nodes/{0}?permanent=true +#alfresco.uploadRelativePath=/dms +# Nextcloud +nextcloud.base.url=http://localhost:8080 +nextcloud.username=admin +nextcloud.password=admin + +# Upload URL Template +nextcloud.uploadUrl=/remote.php/dav/files/{username}/{path} + +# Download URL Template +nextcloud.downloadUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Delete URL Template +nextcloud.deleteUrl=/remote.php/dav/files/{username}/{path}/{filename} + +# Relative Path for Uploads +nextcloud.uploadRelativePath=/dms + + #alfresco.base.url=http://192.168.1.87:8080/alfresco diff --git a/dms-mediator/dms-mediator-service/pom.xml b/dms-mediator/dms-mediator-service/pom.xml index 6b0cb11..7544448 100644 --- a/dms-mediator/dms-mediator-service/pom.xml +++ b/dms-mediator/dms-mediator-service/pom.xml @@ -7,6 +7,7 @@ dms-mediator 1.0.0 + jar dms-mediator-service @@ -28,7 +29,23 @@ - 17 - 17 + + + + + com.google.cloud.tools + jib-maven-plugin + + + jib-execution + + build + + none + + + + + \ No newline at end of file diff --git a/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/config/AlfrescoConfig.java b/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/config/AlfrescoConfig.java deleted file mode 100644 index 11e6389..0000000 --- a/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/config/AlfrescoConfig.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.itgura.dms_mediator.service.config; - - - -import com.itgura.dms_mediator.util.DummyEntityManagerFactory; -import jakarta.persistence.EntityManagerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration - - -public class AlfrescoConfig { - @Value("${alfresco.base.url}") - private String alfrescoBaseUrl; - - @Value("${alfresco.uploadUrl}") - private String uploadUrl; - - @Value("${alfresco.downloadUrl}") - private String downloadUrl; - - @Value("${alfresco.deleteUrl}") - private String deleteUrl; - - - @Value("${alfresco.username}") - private String username; - - @Value("${alfresco.password}") - private String password; - - @Value("${alfresco.uploadRelativePath}") - private String uploadRelativePath; - - public String getUploadRelativePath() { - return uploadRelativePath; - } - - public void setUploadRelativePath(String uploadRelativePath) { - this.uploadRelativePath = uploadRelativePath; - } - - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) { - return builder - .basicAuthentication(username, password) - .build(); - } - - public String getDownloadUrl() { - return downloadUrl; - } - - public void setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - public String getDeleteUrl() { - return deleteUrl; - } - - public void setDeleteUrl(String deleteUrl) { - this.deleteUrl = deleteUrl; - } - - public String getAlfrescoBaseUrl() { - return alfrescoBaseUrl; - } - - public void setAlfrescoBaseUrl(String alfrescoBaseUrl) { - this.alfrescoBaseUrl = alfrescoBaseUrl; - } - - public String getUploadUrl() { - return uploadUrl; - } - - public void setUploadUrl(String uploadUrl) { - this.uploadUrl = uploadUrl; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Bean - public EntityManagerFactory entityManagerFactory() { - // Implement a dummy EntityManagerFactory - return new DummyEntityManagerFactory(); - } -} diff --git a/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/config/NextCloudConfig.java b/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/config/NextCloudConfig.java new file mode 100644 index 0000000..f59f1b4 --- /dev/null +++ b/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/config/NextCloudConfig.java @@ -0,0 +1,100 @@ +package com.itgura.dms_mediator.service.config; + + + +import com.itgura.dms_mediator.util.DummyEntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration + + +public class NextCloudConfig { + @Value("${nextcloud.base.url}") + private String nextcloudBaseUrl; + + @Value("${nextcloud.uploadUrl}") + private String uploadUrlTemplate; + + @Value("${nextcloud.downloadUrl}") + private String downloadUrlTemplate; + + @Value("${nextcloud.deleteUrl}") + private String deleteUrlTemplate; + + + @Value("${nextcloud.username}") + private String username; + + @Value("${nextcloud.password}") + private String password; + + @Value("${nextcloud.uploadRelativePath}") + private String uploadRelativePath; + + + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder + .basicAuthentication(username, password) + .build(); + } + + public String buildUploadUrl(String path) { + return nextcloudBaseUrl + uploadUrlTemplate + .replace("{username}", username) + .replace("{path}", path.startsWith("/") ? path.substring(1) : path); + } + + public String buildDownloadUrl(String path, String filename) { + return nextcloudBaseUrl + downloadUrlTemplate + .replace("{username}", username) + .replace("{path}", path.startsWith("/") ? path.substring(1) : path) + .replace("{filename}", filename); + } + + public String buildDeleteUrl(String path, String filename) { + return nextcloudBaseUrl + deleteUrlTemplate + .replace("{username}", username) + .replace("{path}", path.startsWith("/") ? path.substring(1) : path) + .replace("{filename}", filename); + } + public String getNextcloudBaseUrl() { + return nextcloudBaseUrl; + } + + public String getUploadUrlTemplate() { + return uploadUrlTemplate; + } + + public String getDownloadUrlTemplate() { + return downloadUrlTemplate; + } + + public String getDeleteUrlTemplate() { + return deleteUrlTemplate; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getUploadRelativePath() { + return uploadRelativePath; + } + @Bean + public EntityManagerFactory entityManagerFactory() { + // Implement a dummy EntityManagerFactory + return new DummyEntityManagerFactory(); + } + +} diff --git a/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/impl/DmsServiceImpl.java b/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/impl/DmsServiceImpl.java index 9ef34c0..f9cfcc1 100644 --- a/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/impl/DmsServiceImpl.java +++ b/dms-mediator/dms-mediator-service/src/main/java/com/itgura/dms_mediator/service/impl/DmsServiceImpl.java @@ -1,7 +1,7 @@ package com.itgura.dms_mediator.service.impl; import com.itgura.dms_mediator.response.dto.DocumentResponseDto; import com.itgura.dms_mediator.service.DmsService; -import com.itgura.dms_mediator.service.config.AlfrescoConfig; +import com.itgura.dms_mediator.service.config.NextCloudConfig; import com.itgura.exception.ApplicationException; import com.itgura.exception.ValueNotFoundException; import org.json.JSONObject; @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.text.MessageFormat; import java.util.Base64; import java.util.UUID; @@ -32,7 +33,7 @@ public class DmsServiceImpl implements DmsService { private RestTemplate restTemplate; @Autowired - private AlfrescoConfig config; + private NextCloudConfig config; @Override @@ -40,11 +41,7 @@ public String uploadDocument(MultipartFile file) throws ApplicationException { HttpHeaders headers = new HttpHeaders(); headers.setBasicAuth(config.getUsername(), config.getPassword()); - StringBuilder urlString = new StringBuilder(); - urlString.append(config.getAlfrescoBaseUrl() + config.getUploadUrl()); - try { -// // Generate a unique file name by appending _id_[Random UUID] String originalFileName = file.getOriginalFilename(); @@ -52,101 +49,93 @@ public String uploadDocument(MultipartFile file) throws ApplicationException { String baseName = originalFileName.substring(0, originalFileName.lastIndexOf(".")); String uniqueFileName = baseName + "_id_" + UUID.randomUUID() + extension; - // Convert multipart file to File with unique file name + // Build the upload URL + String path = config.getUploadRelativePath(); + String uploadUrl = config.buildUploadUrl(path + "/" + uniqueFileName); + System.out.println("uploadUrl: " + uploadUrl); + + // Convert MultipartFile to a File File tempFile = convertMultiPartToFile(file, uniqueFileName); headers.setContentType(MediaType.MULTIPART_FORM_DATA); headers.setContentLength(tempFile.length()); -// - MultiValueMap fileValueMap = new LinkedMultiValueMap<>(); - - fileValueMap.add("filedata", new FileSystemResource(tempFile)); - fileValueMap.add("relativePath", config.getUploadRelativePath()); - fileValueMap.add("name", uniqueFileName); - HttpEntity> entity = new HttpEntity<>(fileValueMap, - headers); + // Create a resource for the file to be uploaded + FileSystemResource resource = new FileSystemResource(tempFile); + // Use RestTemplate to upload the file + HttpEntity entity = new HttpEntity<>(resource, headers); RestTemplate restTemplate = new RestTemplate(); - ResponseEntity responseEntity = restTemplate.exchange(urlString.toString(), HttpMethod.POST, entity, - String.class); - + ResponseEntity responseEntity = restTemplate.exchange(uploadUrl, HttpMethod.PUT, entity, String.class); + // Clean up temporary file tempFile.delete(); - - JSONObject jsonResponse = new JSONObject(responseEntity.getBody()); - String alfrescoDocumentId = jsonResponse.getJSONObject("entry").getString("id"); - - if (alfrescoDocumentId != null) { - return alfrescoDocumentId; + // Check for successful response + if (responseEntity.getStatusCode().is2xxSuccessful()) { + return uniqueFileName; // Return the unique file name or path as a reference ID } else { - throw new ApplicationException("Failed to upload document to Alfresco: " + responseEntity.getStatusCode()); + throw new ApplicationException("Failed to upload document to Nextcloud: " + responseEntity.getStatusCode()); } } catch (Exception e) { throw new ApplicationException("Exception: " + e.getMessage(), e); } - } - @Override - public DocumentResponseDto downloadDocument(String alfrescoDocumentId) throws ValueNotFoundException, ApplicationException { + public DocumentResponseDto downloadDocument(String documentPath) throws ValueNotFoundException, ApplicationException { HttpHeaders headers = new HttpHeaders(); headers.setBasicAuth(config.getUsername().trim(), config.getPassword()); - // URL to access the document content - String fileUrl = config.getAlfrescoBaseUrl() + config.getDownloadUrl(); - StringBuilder urlString = new StringBuilder(); - urlString.append(MessageFormat.format(fileUrl, alfrescoDocumentId)); + // Build the URL to access the document content + String downloadUrl = config.buildDownloadUrl(config.getUploadRelativePath(), documentPath); + System.out.println("downloadUrl: " + downloadUrl); headers.setContentType(MediaType.MULTIPART_FORM_DATA); ResponseEntity response; try { response = restTemplate.exchange( - urlString.toString(), + downloadUrl, HttpMethod.GET, new HttpEntity<>(headers), Resource.class); } catch (HttpClientErrorException e) { - if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) { throw new ValueNotFoundException("Document not found: " + e.getStatusCode()); } else { throw new ApplicationException("Client error during document download: " + e.getStatusCode()); } } catch (HttpServerErrorException e) { - throw new ApplicationException("Server error during document download: " + e.getStatusCode()); } if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { + Resource resource = response.getBody(); + String base64Content = convertResourceToBase64(resource); - Resource imageResource = response.getBody(); - String base64Image = convertResourceToBase64(imageResource); - // Extract filename from 'Content-Disposition' header if available + // Extract filename from 'Content-Disposition' header if available, or use documentPath String filename = extractOriginalFileName(response.getHeaders().getContentDisposition().getFilename()); - return new DocumentResponseDto(base64Image, filename); + + return new DocumentResponseDto(base64Content, filename); } else { // Handle unexpected scenarios + System.out.println(response); throw new ApplicationException("Unexpected error during document download: " + response.getStatusCode()); } } @Override - public String deleteDocument(String alfrescoDocumentId) throws ApplicationException, ValueNotFoundException { + public String deleteDocument(String documentPath) throws ApplicationException, ValueNotFoundException { HttpHeaders headers = new HttpHeaders(); headers.setBasicAuth(config.getUsername(), config.getPassword()); - // Include the 'permanent=true' query parameter in the delete URL - String deleteUrl = config.getAlfrescoBaseUrl() + config.getDeleteUrl(); - StringBuilder urlString = new StringBuilder(); - urlString.append(MessageFormat.format(deleteUrl, alfrescoDocumentId)); + // Build the delete URL using the document path + String deleteUrl = config.buildDeleteUrl(config.getUploadRelativePath(), documentPath); try { - restTemplate.exchange(urlString.toString(), HttpMethod.DELETE, new HttpEntity<>(headers), String.class); - return "Document with ID: " + alfrescoDocumentId + " deleted successfully."; + restTemplate.exchange(deleteUrl, HttpMethod.DELETE, new HttpEntity<>(headers), String.class); + return "Document at path: " + documentPath + " deleted successfully."; } catch (HttpClientErrorException.NotFound e) { - throw new ValueNotFoundException("Document not found with ID: " + alfrescoDocumentId); + throw new ValueNotFoundException("Document not found at path: " + documentPath); } catch (HttpClientErrorException e) { throw new ApplicationException("Client error during document deletion: " + e.getMessage()); } catch (HttpServerErrorException e) { diff --git a/dms-mediator/pom.xml b/dms-mediator/pom.xml index 369570f..93c553e 100644 --- a/dms-mediator/pom.xml +++ b/dms-mediator/pom.xml @@ -4,29 +4,30 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.1.5 - - - com.itgura.lms - dms-mediator - pom - 1.0.0 - + com.itgura.lms + lms + 1.0.0 + + dms-mediator + pom dms-mediator-all dms-mediator-dao dms-mediator-service + 1.0.0 + + + + + - 17 - 17 - 2022.0.5 + 17 + 2023.0.1 @@ -34,7 +35,15 @@ org.springframework.cloud spring-cloud-starter-netflix-eureka-client - + + org.springframework.boot + spring-boot-starter-web + + + + + + @@ -48,4 +57,14 @@ + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d41ad97 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,237 @@ +services: + postgres-main: + container_name: postgres-main + image: postgres + ports: + - "5432:5432" + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: root + POSTGRES_DB: itgura + PGDATA: /data/postgres + + + volumes: + - ./init-db.sh:/docker-entrypoint-initdb.d/init-db.sh + - postgres:/data/postgres + networks: + - postgres-main + - nextcloud-network + restart: unless-stopped + + pgadmin: + container_name: pgadmin + image: dpage/pgadmin4 + ports: + - "5050:80" + environment: + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.com} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin} + PGADMIN_CONFIG_SERVER_MODE: 'False' + volumes: + - pgadmin:/var/lib/pgadmin + networks: + - postgres-main + restart: unless-stopped + + eureka-server: + container_name: eureka-server + image: yesitha/eureka-server:latest + ports: + - "8761:8761" + environment: + - SPRING_PROFILES_ACTIVE=docker + networks: + - spring + + lms-gateway: + container_name: lms-gateway + image: yesitha/lms-gateway:latest + ports: + - "8081:8081" + environment: + - SPRING_PROFILES_ACTIVE=docker + - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka + - EUREKA_INSTANCE_HOSTNAME=lms-gateway + depends_on: + - eureka-server + networks: + - spring + + auth-service: + container_name: auth-service + image: yesitha/auth-service:latest + ports: + - "8098:8098" + environment: + - SPRING_PROFILES_ACTIVE=docker + - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka + - EUREKA_INSTANCE_HOSTNAME=auth-service + depends_on: + - eureka-server + - postgres-main + networks: + - spring + - postgres-main + + payment-service: + container_name: payment-service + image: yesitha/payment-service:latest + ports: + - "8199:8199" + environment: + - SPRING_PROFILES_ACTIVE=docker + - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka + - EUREKA_INSTANCE_HOSTNAME=payment-service + depends_on: + - eureka-server + - postgres-main + networks: + - spring + - postgres-main + + resource-management: + container_name: resource-management + image: yesitha/resource-management-all:latest + ports: + - "8092:8092" + environment: + - SPRING_PROFILES_ACTIVE=docker + - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka + - EUREKA_INSTANCE_HOSTNAME=resource-management + depends_on: + - eureka-server + - postgres-main + networks: + - spring + - postgres-main + + dms-mediator: + container_name: dms-mediator + image: yesitha/dms-mediator-all:latest + ports: + - "8099:8099" + environment: + - SPRING_PROFILES_ACTIVE=docker + - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka + - EUREKA_INSTANCE_HOSTNAME=dms-mediator + - NEXTCLOUD_BASE_URL=http://nextcloud:80 + - NEXTCLOUD_USERNAME=admin + - NEXTCLOUD_PASSWORD=admin + depends_on: + - eureka-server + - nextcloud + - postgres-main + + networks: + - spring + - nextcloud-network + + nextcloud: + image: nextcloud:latest + container_name: nextcloud + ports: + - "8080:80" + volumes: + - nextcloud_data:/var/www/html +# - ./set_trusted_domains.sh:/usr/local/bin/set_trusted_domains.sh + environment: + - POSTGRES_DB=alfresco + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=root + - POSTGRES_HOST=postgres-main + - POSTGRES_PORT=5432 + depends_on: + - postgres-main + networks: + - nextcloud-network +# entrypoint: ["/bin/sh", "-c", "/usr/local/bin/set_trusted_domains.sh && /entrypoint.sh apache2-foreground"] + +# alfresco: +# image: docker.io/alfresco/alfresco-content-repository-community:23.2.1 +# mem_limit: 1900m +# environment: +# JAVA_TOOL_OPTIONS: >- +# -Dencryption.keystore.type=JCEKS +# -Dencryption.cipherAlgorithm=DESede/CBC/PKCS5Padding +# -Dencryption.keyAlgorithm=DESede +# -Dencryption.keystore.location=/usr/local/tomcat/shared/classes/alfresco/extension/keystore/keystore +# -Dmetadata-keystore.password=mp6yc0UD9e +# -Dmetadata-keystore.aliases=metadata +# -Dmetadata-keystore.metadata.password=oKIWzVdEdA +# -Dmetadata-keystore.metadata.algorithm=DESede +# JAVA_OPTS: >- +# -Ddb.driver=org.postgresql.Driver +# -Ddb.username=postgres +# -Ddb.password=root +# -Ddb.url=jdbc:postgresql://postgres-main:5432/alfresco +# -Dshare.host=localhost +# -Dshare.port=8085 +## -Dcsrf.filter.enabled=false +## -Ddeployment.method=DOCKER_COMPOSE +# +# depends_on: +# - postgres-main +# ports: +# - "8080:8080" +# networks: +# - alfresco-network +# - postgres-main +# +## postgres: +## image: postgres:14.4 +## mem_limit: 512m +## environment: +## - POSTGRES_PASSWORD=alfresco +## - POSTGRES_USER=alfresco +## - POSTGRES_DB=alfresco +## ports: +## - "5433:5432" +## networks: +## - alfresco-network +## volumes: +## - alfresco_data:/var/lib/postgresql/data +# +# share: +# image: docker.io/alfresco/alfresco-share:23.2.2 +# mem_limit: 1g +# environment: +# REPO_HOST: "alfresco" +# REPO_PORT: "8080" +# JAVA_OPTS: >- +# -Dalfresco.host=localhost +# -Dalfresco.port=8080 +# -Dalfresco.context=alfresco +# -Dalfresco.protocol=http +# networks: +# - alfresco-network +# ports: +# - "8085:8080" + +networks: + postgres-main: + driver: bridge + spring: + driver: bridge + nextcloud-network: + driver: bridge + +volumes: + postgres: + pgadmin: + nextcloud_data: +# alfresco_data: + + + +##commands +# mvn clean package -P build-docker-image +# docker-compose up -d + +# docker exec -it nextcloud /bin/bash +# nano /var/www/html/config/config.php +# 'trusted_domains' => +# array ( +# 0 => 'localhost', +# 1 => 'nextcloud', +# ), diff --git a/eureka-server/pom.xml b/eureka-server/pom.xml index 9449eb2..585c3bd 100644 --- a/eureka-server/pom.xml +++ b/eureka-server/pom.xml @@ -3,19 +3,50 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.2.4 - + com.itgura.lms + lms + 1.0.0 + + + + + + + + + jar com.itgura eureka-server 0.0.1-SNAPSHOT eureka-server service discovery server for Itgura LMS + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + 17 2023.0.1 + 17 + 17 @@ -47,6 +78,7 @@ org.springframework.boot spring-boot-maven-plugin + diff --git a/eureka-server/src/main/resources/application-docker.properties b/eureka-server/src/main/resources/application-docker.properties new file mode 100644 index 0000000..cad25c9 --- /dev/null +++ b/eureka-server/src/main/resources/application-docker.properties @@ -0,0 +1,11 @@ +spring.application.name=eureka-server +server.port=8761 +eureka.instance.prefer-ip-address=true +eureka.client.register-with-eureka=false +eureka.client.fetch-registry=false +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka/ +eureka.server.wait-time-in-ms-when-sync-empty=0 + + +#spring.cloud.config.import-check.enabled=false + diff --git a/init-db.sh b/init-db.sh new file mode 100644 index 0000000..82b9762 --- /dev/null +++ b/init-db.sh @@ -0,0 +1,6 @@ +# init-db.sh + +set -e +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL + CREATE DATABASE alfresco; +EOSQL \ No newline at end of file diff --git a/k8s/minikube/bootstrap/postgres/configmap.yml b/k8s/minikube/bootstrap/postgres/configmap.yml new file mode 100644 index 0000000..84822f4 --- /dev/null +++ b/k8s/minikube/bootstrap/postgres/configmap.yml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-config +data: + POSTGRES_DB: itgura + POSTGRES_USER: postgres + POSTGRES_PASSWORD: root + + + + + diff --git a/k8s/minikube/bootstrap/postgres/service.yml b/k8s/minikube/bootstrap/postgres/service.yml new file mode 100644 index 0000000..9f4a135 --- /dev/null +++ b/k8s/minikube/bootstrap/postgres/service.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: postgres + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + selector: + app: postgres + ports: + - port: 5432 + targetPort: 5432 + type: ClusterIP + \ No newline at end of file diff --git a/k8s/minikube/bootstrap/postgres/statefulset.yml b/k8s/minikube/bootstrap/postgres/statefulset.yml new file mode 100644 index 0000000..1326b86 --- /dev/null +++ b/k8s/minikube/bootstrap/postgres/statefulset.yml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: postgres + namespace: itgura + annotations: + linkerd.io/inject: enabled + labels: + app: postgres +spec: + serviceName: postgres + replicas: 1 + template: + metadata: + name: postgres + labels: + app: postgres + spec: + volumes: + - name: postgres + persistentVolumeClaim: + claimName: postgres-pc-volume-claim + containers: + - name: postgres + image: postgres + imagePullPolicy: IfNotPresent + volumeMounts: + - mountPath: /var/lib/postgresql/data + name: postgres + envFrom: + - configMapRef: + name: postgres-config + resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + restartPolicy: Always + selector: + matchLabels: + app: postgres + + diff --git a/k8s/minikube/bootstrap/postgres/volume.yml b/k8s/minikube/bootstrap/postgres/volume.yml new file mode 100644 index 0000000..62bcfad --- /dev/null +++ b/k8s/minikube/bootstrap/postgres/volume.yml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: postgres-pc-volume + labels: + type: local + app : postgres + +spec: + storageClassName: manual + capacity: + storage: 5Gi + accessModes: + - ReadWriteMany + hostPath: + path: /mnt/data + +--- + +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres-pc-volume-claim + labels: + app: postgres +spec: + storageClassName: manual + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi + + + + + \ No newline at end of file diff --git a/k8s/minikube/services/auth-service/deployment.yml b/k8s/minikube/services/auth-service/deployment.yml new file mode 100644 index 0000000..ff9b6b9 --- /dev/null +++ b/k8s/minikube/services/auth-service/deployment.yml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: auth-service + labels: + app: auth-service + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + replicas: 1 + selector: + matchLabels: + app: auth-service + template: + metadata: + name: auth-service + labels: + app: auth-service + spec: + containers: + - name: auth-service + image: yesitha/auth-service:latest + imagePullPolicy: Always + ports: + - containerPort: 8098 + protocol: TCP + env: + - name: SPRING_PROFILES_ACTIVE + value: kube + + restartPolicy: Always + \ No newline at end of file diff --git a/k8s/minikube/services/auth-service/service.yml b/k8s/minikube/services/auth-service/service.yml new file mode 100644 index 0000000..b7a47d7 --- /dev/null +++ b/k8s/minikube/services/auth-service/service.yml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: auth-service + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + selector: + app: auth-service + ports: + - protocol: TCP + port: 80 + targetPort: 8098 + type: ClusterIP + \ No newline at end of file diff --git a/k8s/minikube/services/dms-mediator/deployment.yml b/k8s/minikube/services/dms-mediator/deployment.yml new file mode 100644 index 0000000..c32735e --- /dev/null +++ b/k8s/minikube/services/dms-mediator/deployment.yml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dms-mediator + labels: + app: dms-mediator + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + replicas: 1 + selector: + matchLabels: + app: dms-mediator + template: + metadata: + name: dms-mediator + labels: + app: dms-mediator + spec: + containers: + - name: dms-mediator + image: yesitha/dms-mediator-all:latest + imagePullPolicy: Always + ports: + - containerPort: 8099 + protocol: TCP + env: + - name: SPRING_PROFILES_ACTIVE + value: kube + + restartPolicy: Always + \ No newline at end of file diff --git a/k8s/minikube/services/dms-mediator/service.yml b/k8s/minikube/services/dms-mediator/service.yml new file mode 100644 index 0000000..246881e --- /dev/null +++ b/k8s/minikube/services/dms-mediator/service.yml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: dms-mediator + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + selector: + app: dms-mediator + ports: + - protocol: TCP + port: 80 + targetPort: 8099 + type: ClusterIP + \ No newline at end of file diff --git a/k8s/minikube/services/lms-gateway/deployment.yml b/k8s/minikube/services/lms-gateway/deployment.yml new file mode 100644 index 0000000..da4bf6f --- /dev/null +++ b/k8s/minikube/services/lms-gateway/deployment.yml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lms-gateway + labels: + app: lms-gateway + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + replicas: 1 + selector: + matchLabels: + app: lms-gateway + template: + metadata: + name: lms-gateway + labels: + app: lms-gateway + spec: + containers: + - name: lms-gateway + image: yesitha/lms-gateway:latest + imagePullPolicy: Always + ports: + - containerPort: 8081 + protocol: TCP + env: + - name: SPRING_PROFILES_ACTIVE + value: kube + restartPolicy: Always diff --git a/k8s/minikube/services/lms-gateway/service.yml b/k8s/minikube/services/lms-gateway/service.yml new file mode 100644 index 0000000..fd52e4b --- /dev/null +++ b/k8s/minikube/services/lms-gateway/service.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: lms-gateway + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + selector: + app: lms-gateway + ports: + - protocol: TCP + port: 80 + targetPort: 8081 + type: LoadBalancer diff --git a/k8s/minikube/services/payment-service/deployment.yml b/k8s/minikube/services/payment-service/deployment.yml new file mode 100644 index 0000000..9f9402f --- /dev/null +++ b/k8s/minikube/services/payment-service/deployment.yml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: payment-service + labels: + app: payment-service + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + replicas: 1 + selector: + matchLabels: + app: payment-service + template: + metadata: + name: payment-service + labels: + app: payment-service + spec: + containers: + - name: payment-service + image: yesitha/payment-service:latest + imagePullPolicy: Always + ports: + - containerPort: 8199 + protocol: TCP + env: + - name: SPRING_PROFILES_ACTIVE + value: kube + restartPolicy: Always diff --git a/k8s/minikube/services/payment-service/service.yml b/k8s/minikube/services/payment-service/service.yml new file mode 100644 index 0000000..d99e55a --- /dev/null +++ b/k8s/minikube/services/payment-service/service.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: payment-service + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + selector: + app: payment-service + ports: + - protocol: TCP + port: 80 + targetPort: 8199 + type: ClusterIP diff --git a/k8s/minikube/services/resource-management/deployment.yml b/k8s/minikube/services/resource-management/deployment.yml new file mode 100644 index 0000000..218282c --- /dev/null +++ b/k8s/minikube/services/resource-management/deployment.yml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: resource-management + labels: + app: resource-management + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + replicas: 1 + selector: + matchLabels: + app: resource-management + template: + metadata: + name: resource-management + labels: + app: resource-management + spec: + containers: + - name: resource-management + image: yesitha/resource-management-all:latest + imagePullPolicy: Always + ports: + - containerPort: 8092 + protocol: TCP + env: + - name: SPRING_PROFILES_ACTIVE + value: kube + restartPolicy: Always diff --git a/k8s/minikube/services/resource-management/service.yml b/k8s/minikube/services/resource-management/service.yml new file mode 100644 index 0000000..09d84db --- /dev/null +++ b/k8s/minikube/services/resource-management/service.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: resource-management + namespace: itgura + annotations: + linkerd.io/inject: enabled +spec: + selector: + app: resource-management + ports: + - protocol: TCP + port: 80 + targetPort: 8092 + type: ClusterIP diff --git a/lib-common/pom.xml b/lib-common/pom.xml index b4c7269..e1c9468 100644 --- a/lib-common/pom.xml +++ b/lib-common/pom.xml @@ -5,19 +5,20 @@ 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.1.5 - + com.itgura.lms + lms + 1.0.0 + - com.itgura.lms + + lib-common + jar 0.0.1 - 17 - 17 + UTF-8 @@ -25,8 +26,7 @@ org.springframework.boot spring-boot-devtools - runtime - true + 3.3.1 io.swagger.core.v3 diff --git a/lib-global/pom.xml b/lib-global/pom.xml index 3505d56..45d0670 100644 --- a/lib-global/pom.xml +++ b/lib-global/pom.xml @@ -3,33 +3,15 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - - - - org.apache.maven.plugins - maven-compiler-plugin - - 16 - 16 - - - - org.apache.maven.plugins - maven-compiler-plugin - - 16 - 16 - - - - - org.springframework.boot - spring-boot-starter-parent - 3.1.5 - + com.itgura.lms + lms + 1.0.0 + - com.itgura.lms + jar + + lib-global 0.0.1 @@ -40,8 +22,7 @@ - 17 - 17 + UTF-8 diff --git a/lib-global/src/main/java/com/itgura/util/ResourceManagementURI.java b/lib-global/src/main/java/com/itgura/util/ResourceManagementURI.java index 806d2fc..d40420f 100644 --- a/lib-global/src/main/java/com/itgura/util/ResourceManagementURI.java +++ b/lib-global/src/main/java/com/itgura/util/ResourceManagementURI.java @@ -16,7 +16,15 @@ public class ResourceManagementURI { public static final String CLASS_ID = "/{classId}"; public static final String ANNOUNCEMENT = "/announcement"; public static final String ANNOUNCEMENT_ID = "/{announcementId}"; + public static final String ID = "/{id}"; public static final String CONTENT = "/content"; public static final String TAGS = "/tags"; + public static final String QUIZ = "/quiz"; + public static final String ASSIGNMENT = "/assignment"; + public static final String FORUM = "/forum"; + public static final String MY = "/my"; + public static final String REPLY = "/reply"; + public static final String GET_BY_ID = "/get-by-id"; + public static final String PUBLISH = "/publish"; } diff --git a/lib-global/src/main/java/com/itgura/util/URIPathVariable.java b/lib-global/src/main/java/com/itgura/util/URIPathVariable.java index 0c1ba66..ccd7412 100644 --- a/lib-global/src/main/java/com/itgura/util/URIPathVariable.java +++ b/lib-global/src/main/java/com/itgura/util/URIPathVariable.java @@ -15,5 +15,6 @@ public class URIPathVariable { public static final String PAYMENT_SERVICE = "/payment-service"; + public static final String QUIZ_SERVICE = "/quiz-service"; public static final String CONTENT_ID = "/{contentId}"; } diff --git a/lib-security/src/main/java/com/itgura/config/JwtAuthenticationFilter.java b/lib-security/src/main/java/com/itgura/config/JwtAuthenticationFilter.java deleted file mode 100644 index 7c17bd7..0000000 --- a/lib-security/src/main/java/com/itgura/config/JwtAuthenticationFilter.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.itgura.config; - - -import com.itgura.util.JwtService; -import com.itgura.util.JwtServiceImpl; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.lang.NonNull; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; - -@Component - -public class JwtAuthenticationFilter extends OncePerRequestFilter { - private JwtService jwtService; - private UserDetailsService userDetailsService; - - @Autowired - public void setJwtService(JwtService jwtService) { - this.jwtService = jwtService; - } - - @Autowired - public void setUserDetailsService(UserDetailsService userDetailsService) { - this.userDetailsService = userDetailsService; - } - - - @Override - protected void doFilterInternal(@NonNull HttpServletRequest request, - @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain - ) throws ServletException, IOException { - - final String authHeader = request.getHeader("Authorization"); - final String jwt; - final String userEmail; - if(StringUtils.isEmpty(authHeader) || StringUtils.startsWith(authHeader,"Bearer ")){ - filterChain.doFilter(request, response); - return; - } - jwt = authHeader.substring(7);//Bearer length is 7 - userEmail = jwtService.extractUserName(jwt);//todo extract userEmail from jwt Token -if(StringUtils.isNotEmpty(userEmail) && SecurityContextHolder.getContext().getAuthentication() == null){ - UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail); - if(jwtService.isTokenValid(jwt, userDetails)){ - UsernamePasswordAuthenticationToken authToken =new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities()); - authToken.setDetails( - new WebAuthenticationDetailsSource().buildDetails(request) - ); - SecurityContextHolder.getContext().setAuthentication(authToken); - } - } - filterChain.doFilter(request,response); - - } -} diff --git a/lib-security/src/main/java/com/itgura/util/JwtService.java b/lib-security/src/main/java/com/itgura/util/JwtService.java deleted file mode 100644 index 22a1b97..0000000 --- a/lib-security/src/main/java/com/itgura/util/JwtService.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.itgura.util; - -import io.jsonwebtoken.Claims; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -public interface JwtService { - public String extractUserName(String token); - public T extractClaim(String token, Function claimsResolver); - public String generateToken(UserDetails userDetails); - public String generateToken( - Map extraClaims, - UserDetails userDetails); - public Boolean isTokenValid(String token, UserDetails userDetails); - public String generateRefresh(Map extraClaims, UserDetails userDetails); - -} diff --git a/lib-security/src/main/java/com/itgura/util/JwtServiceImpl.java b/lib-security/src/main/java/com/itgura/util/JwtServiceImpl.java deleted file mode 100644 index 1eb04fd..0000000 --- a/lib-security/src/main/java/com/itgura/util/JwtServiceImpl.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.itgura.util; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.security.Keys; -import org.springframework.context.annotation.Lazy; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Service; - -import java.security.Key; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -@Service -@Lazy -public class JwtServiceImpl implements JwtService{ - - private static final String SECRET_KEY ="f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635"; - public String extractUserName(String token) { - return extractClaim(token,Claims::getSubject); - } - - public T extractClaim(String token, Function claimsResolver) { - final Claims claims = extractAllClaims(token); - return claimsResolver.apply(claims); - } - - public String generateToken(UserDetails userDetails) { - return generateToken(new HashMap<>(), userDetails); - } - public String generateToken( - Map extraClaims, - UserDetails userDetails) { - return Jwts.builder() - .setSubject(userDetails.getUsername()) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 24)) - .signWith(getSignInKey(), SignatureAlgorithm.HS256) - .compact(); - } - - public Boolean isTokenValid(String token, UserDetails userDetails) { - final String username = extractUserName(token); - return (username.equals(userDetails.getUsername())&& !isTokenExpired(token)); - } - - private Boolean isTokenExpired(String token) { - return extractExpiration(token).before(new Date()); - } - - private Date extractExpiration(String token) { - - return extractClaim(token, Claims::getExpiration); - } - - - private Claims extractAllClaims(String token) { - return Jwts.parser().setSigningKey(getSignInKey()).build().parseClaimsJws(token).getBody(); - } - - private Key getSignInKey() { - byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY); - return Keys.hmacShaKeyFor(keyBytes); - } - - public String generateRefresh(Map extraClaims, UserDetails userDetails) { - return Jwts.builder() - .setClaims(extraClaims) - .setSubject(userDetails.getUsername()) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + 604800000)) - .signWith(getSignInKey(), SignatureAlgorithm.HS256) - .compact(); - - } -} diff --git a/lib-security/src/main/resources/entity-field-validation.properties b/lib-security/src/main/resources/entity-field-validation.properties deleted file mode 100644 index 43d769a..0000000 --- a/lib-security/src/main/resources/entity-field-validation.properties +++ /dev/null @@ -1,4 +0,0 @@ -error.not_exist=The entity does not exist. -error.create_fail=Failed to create the entity. -error.update_fail=Failed to update the entity. -error.cannot_be_null=Field cannot be null. diff --git a/lib-security/src/main/resources/static-field-validation.properties b/lib-security/src/main/resources/static-field-validation.properties deleted file mode 100644 index 2cf0d6a..0000000 --- a/lib-security/src/main/resources/static-field-validation.properties +++ /dev/null @@ -1,3 +0,0 @@ -regex.patten.nic=your_nic_pattern_here -regex.patten.email=your_email_pattern_here -regex.patten.mobile.number=your_mobile_number_pattern_here diff --git a/lib-security/src/main/resources/swagger.properties b/lib-security/src/main/resources/swagger.properties deleted file mode 100644 index aa92dba..0000000 --- a/lib-security/src/main/resources/swagger.properties +++ /dev/null @@ -1,15 +0,0 @@ -api.version=1.0 -swagger.enabled=false -swagger.title=Your API Title -swagger.description=Your API Description -swagger.useDefaultResponseMessages=false -swagger.enableUrlTemplating=true -swagger.deepLinking=false -swagger.defaultModelsExpandDepth=1 -swagger.defaultModelExpandDepth=1 -swagger.displayOperationId=false -swagger.displayRequestDuration=false -swagger.filter=false -swagger.maxDisplayedTags=10 -swagger.showExtensions=false -swagger.authheader.default=YourDefaultAuthorizationHeader diff --git a/lms-gateway/pom.xml b/lms-gateway/pom.xml index 4fb4f08..cfcf514 100644 --- a/lms-gateway/pom.xml +++ b/lms-gateway/pom.xml @@ -3,12 +3,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.2.4 - + com.itgura.lms + lms + 1.0.0 + - com.itgura + jar + lms-gateway 0.0.1-SNAPSHOT lms-gateway @@ -17,6 +18,28 @@ 17 2023.0.1 + + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + org.springframework.cloud @@ -60,6 +83,11 @@ jjwt-jackson 0.12.5 + + + + + diff --git a/lms-gateway/src/main/java/com/itgura/lmsgateway/filter/RouteValidator.java b/lms-gateway/src/main/java/com/itgura/lmsgateway/filter/RouteValidator.java index 44c3907..f6731c1 100644 --- a/lms-gateway/src/main/java/com/itgura/lmsgateway/filter/RouteValidator.java +++ b/lms-gateway/src/main/java/com/itgura/lmsgateway/filter/RouteValidator.java @@ -16,11 +16,10 @@ public class RouteValidator { "/auth-service/register", "/auth-service/refresh", "/auth-service/validateToken", + "/auth-service/changeUserRole", "/eureka", "/resource-management/public" - - ); public Predicate isSecured = request -> openApiEndpoints.stream() diff --git a/lms-gateway/src/main/resources/application-docker.properties b/lms-gateway/src/main/resources/application-docker.properties new file mode 100644 index 0000000..c08d3d5 --- /dev/null +++ b/lms-gateway/src/main/resources/application-docker.properties @@ -0,0 +1,88 @@ +spring.application.name=lms-gateway +server.port=8081 +server.servlet.context-path=/ + +#swagger +#springdoc.enable-native-support=true +#springdoc.api-docs.enabled=true +#springdoc.api-docs.path=/swagger-ui.html +#springdoc.swagger-ui.enabled=true +#springdoc.swagger-ui.path=/swagger-ui.html +#springdoc.swagger-ui.config-url=/v3/api-docs/swagger-config +# +#springdoc.swagger-ui.urls[0].name=lms-gateway +#springdoc.swagger-ui.urls[0].url=/v3/api-docs +#springdoc.swagger-ui.urls[0].display-name=lms-gateway +# +#springdoc.swagger-ui.urls[1].name=dms-mediator +#springdoc.swagger-ui.urls[1].url=/dms-mediator/v3/api-docs +#springdoc.swagger-ui.urls[1].display-name=dms-mediator + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 + +# eureka +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=eureka-server +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka +# gateway + +#resource-management--not setup yet +spring.cloud.gateway.routes[0].id:resource-management +spring.cloud.gateway.routes[0].uri:lb://resource-management +spring.cloud.gateway.routes[0].predicates[0].name=Path +spring.cloud.gateway.routes[0].predicates[0].args.pattern=/resource-management/** + + +spring.cloud.gateway.routes[0].filters[1].name=RewritePath +spring.cloud.gateway.routes[0].filters[1].args.regexp=/resource-management/(?.*) +spring.cloud.gateway.routes[0].filters[1].args.replacement=/api/v1/resource-management/${remaining} + +spring.cloud.gateway.routes[0].filters[0].name=AuthenticationFilter + +#dms-mediator +spring.cloud.gateway.routes[1].id=dms-mediator +spring.cloud.gateway.routes[1].uri=lb://dms-mediator +spring.cloud.gateway.routes[1].predicates[0].name=Path +spring.cloud.gateway.routes[1].predicates[0].args.pattern=/dms-mediator/** + +spring.cloud.gateway.routes[1].filters[1].name=RewritePath +spring.cloud.gateway.routes[1].filters[1].args.regexp=/dms-mediator/(?.*) +spring.cloud.gateway.routes[1].filters[1].args.replacement=/api/v1/dms-mediator/${remaining} + +spring.cloud.gateway.routes[1].filters[0].name=AuthenticationFilter + +#auth-service +spring.cloud.gateway.routes[2].id=auth-service +spring.cloud.gateway.routes[2].uri=lb://auth-service +spring.cloud.gateway.routes[2].predicates[0].name=Path +spring.cloud.gateway.routes[2].predicates[0].args.pattern=/auth-service/** + + +spring.cloud.gateway.routes[2].filters[0].name=RewritePath +spring.cloud.gateway.routes[2].filters[0].args.regexp=/auth-service/(?.*) +spring.cloud.gateway.routes[2].filters[0].args.replacement=/api/v1/auth-service/${remaining} + +#payment-service +spring.cloud.gateway.routes[3].id=payment-service +spring.cloud.gateway.routes[3].uri=lb://payment-service +spring.cloud.gateway.routes[3].predicates[0].name=Path +spring.cloud.gateway.routes[3].predicates[0].args.pattern=/payment-service/** + + +spring.cloud.gateway.routes[3].filters[1].name=RewritePath +spring.cloud.gateway.routes[3].filters[1].args.regexp=/payment-service/(?.*) +spring.cloud.gateway.routes[3].filters[1].args.replacement=/api/v1/payment-service/${remaining} + +spring.cloud.gateway.routes[3].filters[0].name=AuthenticationFilter + + + + + + + + + + + diff --git a/lms-gateway/src/main/resources/application-kube.properties b/lms-gateway/src/main/resources/application-kube.properties new file mode 100644 index 0000000..e59386a --- /dev/null +++ b/lms-gateway/src/main/resources/application-kube.properties @@ -0,0 +1,93 @@ +spring.application.name=lms-gateway +server.port=8081 +server.servlet.context-path=/ + +#swagger +#springdoc.enable-native-support=true +#springdoc.api-docs.enabled=true +#springdoc.api-docs.path=/swagger-ui.html +#springdoc.swagger-ui.enabled=true +#springdoc.swagger-ui.path=/swagger-ui.html +#springdoc.swagger-ui.config-url=/v3/api-docs/swagger-config +# +#springdoc.swagger-ui.urls[0].name=lms-gateway +#springdoc.swagger-ui.urls[0].url=/v3/api-docs +#springdoc.swagger-ui.urls[0].display-name=lms-gateway +# +#springdoc.swagger-ui.urls[1].name=dms-mediator +#springdoc.swagger-ui.urls[1].url=/dms-mediator/v3/api-docs +#springdoc.swagger-ui.urls[1].display-name=dms-mediator + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 + +#linkered +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lower-case-service-id=true + +# eureka +eureka.client.enabled=false +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=eureka-server +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka +# gateway + +#resource-management--not setup yet +spring.cloud.gateway.routes[0].id:resource-management +spring.cloud.gateway.routes[0].uri:lb://resource-management +spring.cloud.gateway.routes[0].predicates[0].name=Path +spring.cloud.gateway.routes[0].predicates[0].args.pattern=/resource-management/** + + +spring.cloud.gateway.routes[0].filters[1].name=RewritePath +spring.cloud.gateway.routes[0].filters[1].args.regexp=/resource-management/(?.*) +spring.cloud.gateway.routes[0].filters[1].args.replacement=/api/v1/resource-management/${remaining} + +spring.cloud.gateway.routes[0].filters[0].name=AuthenticationFilter + +#dms-mediator +spring.cloud.gateway.routes[1].id=dms-mediator +spring.cloud.gateway.routes[1].uri=lb://dms-mediator +spring.cloud.gateway.routes[1].predicates[0].name=Path +spring.cloud.gateway.routes[1].predicates[0].args.pattern=/dms-mediator/** + +spring.cloud.gateway.routes[1].filters[1].name=RewritePath +spring.cloud.gateway.routes[1].filters[1].args.regexp=/dms-mediator/(?.*) +spring.cloud.gateway.routes[1].filters[1].args.replacement=/api/v1/dms-mediator/${remaining} + +spring.cloud.gateway.routes[1].filters[0].name=AuthenticationFilter + +#auth-service +spring.cloud.gateway.routes[2].id=auth-service +spring.cloud.gateway.routes[2].uri=lb://auth-service +spring.cloud.gateway.routes[2].predicates[0].name=Path +spring.cloud.gateway.routes[2].predicates[0].args.pattern=/auth-service/** + + +spring.cloud.gateway.routes[2].filters[0].name=RewritePath +spring.cloud.gateway.routes[2].filters[0].args.regexp=/auth-service/(?.*) +spring.cloud.gateway.routes[2].filters[0].args.replacement=/api/v1/auth-service/${remaining} + +#payment-service +spring.cloud.gateway.routes[3].id=payment-service +spring.cloud.gateway.routes[3].uri=lb://payment-service +spring.cloud.gateway.routes[3].predicates[0].name=Path +spring.cloud.gateway.routes[3].predicates[0].args.pattern=/payment-service/** + + +spring.cloud.gateway.routes[3].filters[1].name=RewritePath +spring.cloud.gateway.routes[3].filters[1].args.regexp=/payment-service/(?.*) +spring.cloud.gateway.routes[3].filters[1].args.replacement=/api/v1/payment-service/${remaining} + +spring.cloud.gateway.routes[3].filters[0].name=AuthenticationFilter + + + + + + + + + + + diff --git a/lms-gateway/src/main/resources/application.properties b/lms-gateway/src/main/resources/application.properties index 128e199..ab89c37 100644 --- a/lms-gateway/src/main/resources/application.properties +++ b/lms-gateway/src/main/resources/application.properties @@ -2,6 +2,8 @@ spring.application.name=lms-gateway server.port=8081 server.servlet.context-path=/ +logging.level.org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping=DEBUG + #swagger #springdoc.enable-native-support=true #springdoc.api-docs.enabled=true @@ -52,6 +54,9 @@ spring.cloud.gateway.routes[1].filters[1].args.replacement=/api/v1/dms-mediator/ spring.cloud.gateway.routes[1].filters[0].name=AuthenticationFilter + + + #auth-service spring.cloud.gateway.routes[2].id=auth-service spring.cloud.gateway.routes[2].uri=lb://auth-service @@ -76,6 +81,19 @@ spring.cloud.gateway.routes[3].filters[1].args.replacement=/api/v1/payment-servi spring.cloud.gateway.routes[3].filters[0].name=AuthenticationFilter +#quiz-management +spring.cloud.gateway.routes[4].id=quiz-management +spring.cloud.gateway.routes[4].uri=lb://quiz-management +spring.cloud.gateway.routes[4].predicates[0].name=Path +spring.cloud.gateway.routes[4].predicates[0].args.pattern=/quiz-management/** + +spring.cloud.gateway.routes[4].filters[1].name=RewritePath +spring.cloud.gateway.routes[4].filters[1].args.regexp=/quiz-management/(?.*) +spring.cloud.gateway.routes[4].filters[1].args.replacement=/api/v1/quiz-management/${remaining} + +spring.cloud.gateway.routes[4].filters[0].name=AuthenticationFilter + + diff --git a/lms-gateway/src/main/resources/application.yml b/lms-gateway/src/main/resources/application.yml deleted file mode 100644 index 02a2f21..0000000 --- a/lms-gateway/src/main/resources/application.yml +++ /dev/null @@ -1,23 +0,0 @@ -#springdoc: -# enable-native-support: true -# api-docs: -# groups: -# enabled: true -# enabled: true -# group-configs: -# - group: dms-mediator -# paths-to-match: -# - /dms-mediator/** -# display-name: dms-mediator -# - group: resource-management -# paths-to-match: -# - /resource-management/** -# display-name: resource-management -# swagger-ui: -# config-url: /v1/api-docs/swagger-config -# url: /v1/api-docs -# urls: -# - url: /dms-mediator/v1/api-docs -# name: dms-mediator -# - url: /resource-management/v1/api-docs -# name: resource-management \ No newline at end of file diff --git a/payment-service/pom.xml b/payment-service/pom.xml index 340db80..b96415c 100644 --- a/payment-service/pom.xml +++ b/payment-service/pom.xml @@ -3,16 +3,38 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.2.5 - + com.itgura.lms + lms + 1.0.0 + - com.itgura + jar + payment-service 0.0.1-SNAPSHOT payment-service Payment Service for LMS + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + 17 2023.0.1 @@ -84,6 +106,11 @@ org.glassfish.jaxb jaxb-runtime + + + + + @@ -97,19 +124,27 @@ + + + + + + + + + + + + + + + + org.springframework.boot spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - diff --git a/payment-service/src/main/java/com/itgura/paymentservice/controller/PaymentController.java b/payment-service/src/main/java/com/itgura/paymentservice/controller/PaymentController.java index fcdf64b..127766b 100644 --- a/payment-service/src/main/java/com/itgura/paymentservice/controller/PaymentController.java +++ b/payment-service/src/main/java/com/itgura/paymentservice/controller/PaymentController.java @@ -23,6 +23,7 @@ import java.util.UUID; @RestController +@CrossOrigin(origins = "*", allowedHeaders = "*") @RequestMapping("/api/v1/payment-service") @RequiredArgsConstructor public class PaymentController { diff --git a/payment-service/src/main/java/com/itgura/paymentservice/controller/PermissionController.java b/payment-service/src/main/java/com/itgura/paymentservice/controller/PermissionController.java index f9f79f5..d58fe51 100644 --- a/payment-service/src/main/java/com/itgura/paymentservice/controller/PermissionController.java +++ b/payment-service/src/main/java/com/itgura/paymentservice/controller/PermissionController.java @@ -16,6 +16,7 @@ import java.util.List; @RestController +@CrossOrigin(origins = "*", allowedHeaders = "*") @RequestMapping(URIPrefix.API + URIPrefix.V1 + URIPathVariable.PAYMENT_SERVICE) @RequiredArgsConstructor public class PermissionController { diff --git a/payment-service/src/main/java/com/itgura/paymentservice/service/impl/PaymentServiceImpl.java b/payment-service/src/main/java/com/itgura/paymentservice/service/impl/PaymentServiceImpl.java index 68f9a7c..cfaea11 100644 --- a/payment-service/src/main/java/com/itgura/paymentservice/service/impl/PaymentServiceImpl.java +++ b/payment-service/src/main/java/com/itgura/paymentservice/service/impl/PaymentServiceImpl.java @@ -231,6 +231,8 @@ private double getMonthlyPayment(UUID classId) throws ApplicationException { ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, entity, AppResponse.class); AppResponse response = responseEntity.getBody(); + System.out.println("Monthly Payment Received : "+response); + if (response == null || response.getData() == null) { throw new ApplicationException("Error while getting monthly payment: response or data is null"); } diff --git a/payment-service/src/main/resources/application-docker.properties b/payment-service/src/main/resources/application-docker.properties new file mode 100644 index 0000000..3d3908e --- /dev/null +++ b/payment-service/src/main/resources/application-docker.properties @@ -0,0 +1,30 @@ +spring.application.name=payment-service +server.port=8199 +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration + + +#datasource configuration +spring.datasource.url=jdbc:postgresql://postgres-main:5432/itgura +spring.datasource.username=postgres +spring.datasource.password=root +spring.datasource.hikari.schema=payment_service +spring.datasource.driver-class-name=org.postgresql.Driver +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.format_sql=true + + +# eureka +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=eureka-server +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 + +# payhere +payhere.merchentSecretCode=YOUR_MERCHANT_SECRET_KEY +payhere.merchentID=YOUR_MERCHANT_ID +# +## api gateway +#apiGateway.url=http://localhost:8081 \ No newline at end of file diff --git a/payment-service/src/main/resources/application-kube.properties b/payment-service/src/main/resources/application-kube.properties new file mode 100644 index 0000000..827f97e --- /dev/null +++ b/payment-service/src/main/resources/application-kube.properties @@ -0,0 +1,34 @@ +spring.application.name=payment-service +server.port=8199 +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration + + +#datasource configuration +spring.datasource.url=jdbc:postgresql://postgres/itgura +spring.datasource.username=postgres +spring.datasource.password=root +spring.datasource.hikari.schema=payment_service +spring.datasource.driver-class-name=org.postgresql.Driver +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.format_sql=true + +#linkered +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lower-case-service-id=true + +# eureka +eureka.client.enabled=false +eureka.client.register-with-eureka=true +eureka.client.fetch-registry=true +eureka.instance.hostname=eureka-server +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 + +# payhere +payhere.merchentSecretCode=YOUR_MERCHANT_SECRET_KEY +payhere.merchentID=YOUR_MERCHANT_ID +# +## api gateway +#apiGateway.url=http://localhost:8081 \ No newline at end of file diff --git a/payment-service/src/main/resources/application.properties b/payment-service/src/main/resources/application.properties index c9d38a1..93810f7 100644 --- a/payment-service/src/main/resources/application.properties +++ b/payment-service/src/main/resources/application.properties @@ -6,7 +6,7 @@ spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.ser #datasource configuration spring.datasource.url=jdbc:postgresql://localhost:5432/itgura spring.datasource.username=postgres -spring.datasource.password=1234 +spring.datasource.password=root spring.datasource.hikari.schema=payment_service spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.show-sql=true diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b2fabfb --- /dev/null +++ b/pom.xml @@ -0,0 +1,117 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.4 + + + com.itgura.lms + lms + pom + 1.0.0 + + + lib-common + lib-global + eureka-server + lms-gateway + resource-management + auth-service + dms-mediator + payment-service + quiz-management + + + + + lms + Learning Management System + + + + 17 + 17 + 17 + 3.2.4 + 3.2.4 + 3.2.4 + yesitha/${project.artifactId}:${project.version} + + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.dependencies.version} + import + pom + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 17 + 17 + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.maven.plugin.version} + + + com.google.cloud.tools + jib-maven-plugin + 3.4.3 + + + eclipse-temurin:17 + + + amd64 + linux + + + + arm64 + linux + + + + + + + + latest + + + + + + + + + + + \ No newline at end of file diff --git a/quiz-management/pom.xml b/quiz-management/pom.xml new file mode 100644 index 0000000..a467eb1 --- /dev/null +++ b/quiz-management/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + com.itgura.lms + lms + 1.0.0 + + + pom + quiz-management + + + quiz-management-all + quiz-management-dao + quiz-management-service + + 1.0.0 + + + 17 + 2023.0.1 + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-web + + + + + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + diff --git a/user-management/user-management-all/pom.xml b/quiz-management/quiz-management-all/pom.xml similarity index 51% rename from user-management/user-management-all/pom.xml rename to quiz-management/quiz-management-all/pom.xml index eb0128f..79c354b 100644 --- a/user-management/user-management-all/pom.xml +++ b/quiz-management/quiz-management-all/pom.xml @@ -5,24 +5,43 @@ 4.0.0 com.itgura.lms - user-management + quiz-management 1.0.0 - com.itgura.lms - user-management-all + jar + quiz-management-all + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + com.itgura.lms - user-management-service + quiz-management-service 1.0.0 compile - com.itgura.lms - lib-common - 0.0.1 - compile + org.springframework.boot + spring-boot-starter-security @@ -30,6 +49,7 @@ 17 UTF-8 + @@ -39,4 +59,5 @@ + \ No newline at end of file diff --git a/user-management/user-management-all/src/main/java/com/itgura/UserMain.java b/quiz-management/quiz-management-all/src/main/java/com/itgura/QuizMain.java similarity index 83% rename from user-management/user-management-all/src/main/java/com/itgura/UserMain.java rename to quiz-management/quiz-management-all/src/main/java/com/itgura/QuizMain.java index 6f064a7..9d40e1a 100644 --- a/user-management/user-management-all/src/main/java/com/itgura/UserMain.java +++ b/quiz-management/quiz-management-all/src/main/java/com/itgura/QuizMain.java @@ -1,16 +1,16 @@ package com.itgura; + import com.itgura.util.BootMain; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; - @EnableDiscoveryClient @SpringBootApplication -public class UserMain { +public class QuizMain { public static void main(String[] args) { BootMain.main(args); - SpringApplication.run(UserMain.class); + SpringApplication.run(QuizMain.class); } -} \ No newline at end of file +} diff --git a/quiz-management/quiz-management-all/src/main/java/com/itgura/config/SecurityConfig.java b/quiz-management/quiz-management-all/src/main/java/com/itgura/config/SecurityConfig.java new file mode 100644 index 0000000..b8d7ee0 --- /dev/null +++ b/quiz-management/quiz-management-all/src/main/java/com/itgura/config/SecurityConfig.java @@ -0,0 +1,101 @@ +package com.itgura.config; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity(prePostEnabled = true) +public class SecurityConfig { + + @Value("${jwt.secretKey}") + private String SECRET_KEY; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(request -> request.requestMatchers( + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html", + "/webjars/**", + "/api/v1/resource-management/public/sample") + + .permitAll() + .anyRequest().authenticated()) + .addFilterBefore(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + class JWTAuthorizationFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String authorizationHeader = request.getHeader("Authorization"); + + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + String token = authorizationHeader.substring(7); + Claims claims = Jwts.parser() + .setSigningKey(SECRET_KEY).build()// Use as a formality to parse without validation + .parseClaimsJws(token) + .getBody(); + + String username = claims.getSubject(); + if (username != null) { + var authorities = extractAuthorities(claims); // Method to extract authorities from claims + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, authorities); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + }else { + System.out.println("Authorization header is null"); + } + filterChain.doFilter(request, response); + + } + + private Collection extractAuthorities(Claims claims) { + // Extract the roles claim as a list of maps + List> roles = claims.get("roles", List.class); + if (roles == null) { + return List.of(); // Return an empty list if no roles are found + } + + return roles.stream() + .map(roleMap -> new SimpleGrantedAuthority("ROLE_" + roleMap.get("authority"))) + .collect(Collectors.toList()); + } + } + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} \ No newline at end of file diff --git a/quiz-management/quiz-management-all/src/main/java/com/itgura/controller/AssignmentController.java b/quiz-management/quiz-management-all/src/main/java/com/itgura/controller/AssignmentController.java new file mode 100644 index 0000000..4d43dc7 --- /dev/null +++ b/quiz-management/quiz-management-all/src/main/java/com/itgura/controller/AssignmentController.java @@ -0,0 +1,87 @@ +package com.itgura.controller; + +import com.itgura.dto.AppRequest; +import com.itgura.dto.AppResponse; +import com.itgura.request.CreateAssignmentRequest; +import com.itgura.response.AssignmentResponse; +import com.itgura.response.AssignmentSummaryDTO; +import com.itgura.service.AssignmentService; +import com.itgura.util.ResourceManagementURI; +import com.itgura.util.URIPathVariable; +import com.itgura.util.URIPrefix; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@CrossOrigin(origins = "*", allowedHeaders = "*") +@RestController +@RequestMapping(URIPrefix.API + URIPrefix.V1 + URIPathVariable.QUIZ_SERVICE) +public class AssignmentController { + @Autowired + private AssignmentService assignmentService; + + @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_TEACHER')") + @PostMapping(ResourceManagementURI.ASSIGNMENT + ResourceManagementURI.CREATE) + public AppResponse createAssignment(@RequestBody AppRequest request) { + try { + String response = this.assignmentService.createAssignment(request.getData()); + return AppResponse.ok(response); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + @GetMapping(ResourceManagementURI.ASSIGNMENT + ResourceManagementURI.GET_BY_ID) + public AppResponse getAssignmentById(@RequestParam("id") UUID id) { + try { + AssignmentResponse assignment = assignmentService.getAssignmentById(id); + if (assignment != null) { + return AppResponse.ok(assignment); + } else { + return AppResponse.error(null, "Assignment not found", "Not Found", "404", ""); + } + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + + @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_TEACHER')") + @DeleteMapping(ResourceManagementURI.ASSIGNMENT + "/{id}") + public AppResponse deleteAssignment(@PathVariable UUID id) { + try { + this.assignmentService.deleteAssignment(id); + return AppResponse.ok("Assignment deleted successfully"); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + + + @GetMapping(ResourceManagementURI.ASSIGNMENT) + public AppResponse> getAssignmentsByClassIds(@RequestParam List classIds) { + try { + List assignments = assignmentService.getAssignmentsByClassIds(classIds); + return AppResponse.ok(assignments); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + + @PatchMapping(ResourceManagementURI.ASSIGNMENT+ResourceManagementURI.ID+ResourceManagementURI.PUBLISH) + public ResponseEntity updateAssignmentPublishedStatus(@PathVariable UUID id, @RequestParam Boolean isPublished) { + try { + boolean updated = assignmentService.updatePublishedStatus(id, isPublished); + if (updated) { + return ResponseEntity.ok("Assignment published status updated successfully."); + } else { + return ResponseEntity.status(404).body("Assignment not found."); + } + } catch (Exception e) { + return ResponseEntity.status(500).body("Error updating assignment published status: " + e.getMessage()); + } + } + +} diff --git a/quiz-management/quiz-management-all/src/main/java/com/itgura/controller/QuizController.java b/quiz-management/quiz-management-all/src/main/java/com/itgura/controller/QuizController.java new file mode 100644 index 0000000..f9f5186 --- /dev/null +++ b/quiz-management/quiz-management-all/src/main/java/com/itgura/controller/QuizController.java @@ -0,0 +1,91 @@ +package com.itgura.controller; + +import com.itgura.dto.AppRequest; +import com.itgura.dto.AppResponse; +import com.itgura.request.CreateAssignmentRequest; +import com.itgura.request.CreateQuizRequest; +import com.itgura.response.QuizResponse; +import com.itgura.response.QuizSummaryDTO; +import com.itgura.service.QuizService; +import com.itgura.util.ResourceManagementURI; +import com.itgura.util.URIPathVariable; +import com.itgura.util.URIPrefix; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; +@CrossOrigin(origins = "*", allowedHeaders = "*") +@RestController +@RequestMapping(URIPrefix.API + URIPrefix.V1 + URIPathVariable.QUIZ_SERVICE) +public class QuizController { + @Autowired + private QuizService quizService; + + public QuizController(QuizService quizService) { + this.quizService = quizService; + } + + @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_TEACHER')") + @PostMapping(ResourceManagementURI.QUIZ + ResourceManagementURI.CREATE) + public AppResponse createQuiz(@RequestBody AppRequest request) { + try { + String response = this.quizService.createQuiz(request.getData()); + return AppResponse.ok(response); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + @GetMapping(ResourceManagementURI.QUIZ + ResourceManagementURI.GET_BY_ID) + public AppResponse getQuizById(@RequestParam("id") UUID id) { + try { + QuizResponse quiz = quizService.getQuizById(id); + if (quiz != null) { + return AppResponse.ok(quiz); + } else { + return AppResponse.error(null, "Quiz not found", "Not Found", "404", ""); + } + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + + @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_TEACHER')") + @DeleteMapping(ResourceManagementURI.QUIZ + "/{id}") + public AppResponse deleteQuiz(@PathVariable UUID id) { + try { + this.quizService.deleteQuiz(id); + return AppResponse.ok("Quiz deleted successfully"); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + + @GetMapping(ResourceManagementURI.QUIZ) + public AppResponse> getQuizzesByClassIds(@RequestParam List classIds) { + try { + List quizzes = quizService.getQuizzesByClassIds(classIds); + return AppResponse.ok(quizzes); + } catch (Exception e) { + return AppResponse.error(null, e.getMessage(), "Server Error", "500", ""); + } + } + + @PatchMapping(ResourceManagementURI.QUIZ+ResourceManagementURI.ID+ResourceManagementURI.PUBLISH) + public ResponseEntity updateQuizPublishedStatus(@PathVariable UUID id, @RequestParam Boolean isPublished) { + try { + boolean updated = quizService.updatePublishedStatus(id, isPublished); + if (updated) { + return ResponseEntity.ok("Quiz published status updated successfully."); + } else { + return ResponseEntity.status(404).body("Quiz not found."); + } + } catch (Exception e) { + return ResponseEntity.status(500).body("Error updating quiz published status: " + e.getMessage()); + } + } + + +} diff --git a/quiz-management/quiz-management-all/src/main/resources/application.properties b/quiz-management/quiz-management-all/src/main/resources/application.properties new file mode 100644 index 0000000..a2a00a5 --- /dev/null +++ b/quiz-management/quiz-management-all/src/main/resources/application.properties @@ -0,0 +1,6 @@ +server.port=8094 +spring.application.name=quiz-management +logging.level.org.springframework.core.env=DEBUG +spring.profiles.active=dev +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration +logging.level.org.springframework.security=DEBUG \ No newline at end of file diff --git a/lib-security/pom.xml b/quiz-management/quiz-management-dao/pom.xml similarity index 57% rename from lib-security/pom.xml rename to quiz-management/quiz-management-dao/pom.xml index ae5a816..f707be5 100644 --- a/lib-security/pom.xml +++ b/quiz-management/quiz-management-dao/pom.xml @@ -3,45 +3,54 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.1.5 - + com.itgura.lms + quiz-management + 1.0.0 - com.itgura.lms - lib-security - 0.0.1 + jar + quiz-management-dao - 17 - 17 + UTF-8 - - - - org.springframework.boot - spring-boot-test - test + com.itgura.lms + lib-common + 0.0.1 - - org.springframework.boot - spring-boot-starter-web + com.itgura.lms + lib-global + 0.0.1 - org.springframework.boot - spring-boot-starter-security + org.apache.commons + commons-lang3 + 3.14.0 - org.springframework.boot - spring-boot-starter + com.mysql + mysql-connector-j + 8.1.0 + + + org.postgresql + postgresql + 42.7.1 + + + org.projectlombok + lombok + + + org.springframework.security + spring-security-test + test io.jsonwebtoken @@ -58,24 +67,17 @@ jjwt-jackson 0.12.5 + - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.security - spring-security-test - test - - - org.apache.commons - commons-lang3 + org.mapstruct + mapstruct-processor + 1.5.5.Final + - org.projectlombok - lombok - provided + org.mapstruct + mapstruct + 1.5.5.Final diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Assignment.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Assignment.java new file mode 100644 index 0000000..669ad93 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Assignment.java @@ -0,0 +1,68 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "assignment", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class Assignment { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @Column(name = "title", nullable = false) + private String title; + + @Column(name = "description") + private String description; + + @ElementCollection + @CollectionTable(name = "assignment_files", joinColumns = @JoinColumn(name = "assignment_id")) + @Column(name = "file_url") + private List fileUrls; // List of URLs to files that students need to download + + @Column(name = "deadline") + private Timestamp deadline; + @Column(name = "duration") + private Long duration; // Duration in minutes + + @Column(name = "is_published", nullable = false) + private Boolean isPublished = false; + + @Column(name = "created_by", nullable = false) + private UUID createdBy; + + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @Column(name = "updated_by") + private UUID updatedBy; + + @Column(name = "updated_at") + private Timestamp updatedAt; + + @ElementCollection + @CollectionTable(name = "assignment_class", joinColumns = @JoinColumn(name = "assignment_id")) + @Column(name = "class_id") + private List classIds; + + @OneToMany(mappedBy = "assignment", cascade = CascadeType.ALL, orphanRemoval = true) + private List submissions; + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/AssignmentSubmission.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/AssignmentSubmission.java new file mode 100644 index 0000000..10f2d14 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/AssignmentSubmission.java @@ -0,0 +1,53 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.sql.Timestamp; +import java.util.UUID; + +@Entity +@Table(name = "assignment_submission", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class AssignmentSubmission { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "assignment_id", nullable = false) + private Assignment assignment; + + @Column(name = "student_id", nullable = false) + private UUID studentId; + + @Column(name = "submitted_at") + private Timestamp submittedAt; + + @Column(name = "file_url") + private UUID fileUrl; // URL to the student's uploaded file + + @Column(name = "created_by", nullable = false) + private UUID createdBy; + + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @Column(name = "updated_by") + private UUID updatedBy; + + @Column(name = "updated_at") + private Timestamp updatedAt; + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/MCQOption.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/MCQOption.java new file mode 100644 index 0000000..dd40c22 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/MCQOption.java @@ -0,0 +1,40 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.util.UUID; + +@Entity +@Table(name = "mcq_option", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class MCQOption { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "question_id", nullable = false) + private Question question; + + @Column(name = "option_text", nullable = false) + private String optionText; + + @Column(name = "is_correct", nullable = false) + private Boolean isCorrect; + + @Column(name = "image_url") + private UUID imageUrl; // URL to the option image + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Question.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Question.java new file mode 100644 index 0000000..47da59c --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Question.java @@ -0,0 +1,63 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "question", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class Question { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "quiz_id", nullable = false) + private Quiz quiz; + + @Column(name = "question_text", nullable = false) + private String questionText; + + @Column(name = "question_type", nullable = false) + @Enumerated(EnumType.STRING) + private QuestionType questionType; // MCQ, ESSAY, etc. + @Column(name = "marks") + private Double marks; + + @Column(name = "created_by", nullable = false) + private UUID createdBy; + + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @Column(name = "updated_by") + private UUID updatedBy; + + @Column(name = "updated_at") + private Timestamp updatedAt; + + @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true) + private List images; + + @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true) + private List options; + + @OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true) + private List answers; + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionAnswer.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionAnswer.java new file mode 100644 index 0000000..fa7130b --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionAnswer.java @@ -0,0 +1,48 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.sql.Timestamp; +import java.util.UUID; + +@Entity +@Table(name = "question_answer", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class QuestionAnswer { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "question_id", nullable = false) + private Question question; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "quiz_submission_id", nullable = false) + private QuizSubmission quizSubmission; // Added reference to QuizSubmission + + @Column(name = "student_id", nullable = false) + private UUID studentId; + + @Column(name = "answer_text") + private String answerText; + + @Column(name = "file_url") + private UUID fileUrl; // URL to the file or image with the answer + + @Column(name = "submitted_at") + private Timestamp submittedAt; + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionFile.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionFile.java new file mode 100644 index 0000000..142873b --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionFile.java @@ -0,0 +1,34 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.util.UUID; + +@Entity +@Table(name = "question_image", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class QuestionFile { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "question_id", nullable = false) + private Question question; + + @Column(name = "image_url", nullable = false) + private UUID imageUrl; // URL to the image file + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionType.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionType.java new file mode 100644 index 0000000..3f242ad --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuestionType.java @@ -0,0 +1,8 @@ +package com.itgura.entity; + + +public enum QuestionType { + MCQ, + ESSAY +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Quiz.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Quiz.java new file mode 100644 index 0000000..0ad3abe --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/Quiz.java @@ -0,0 +1,71 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "quiz", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class Quiz { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @Column(name = "title", nullable = false) + private String title; + + @ElementCollection + @CollectionTable(name = "quiz_class", joinColumns = @JoinColumn(name = "quiz_id")) + @Column(name = "class_id") + private List classIds; + + @Column(name = "description") + private String description; + + @Column(name = "total_marks") + private Double totalMarks; + @Column(name = "deadline") + private Timestamp deadline; + @Column(name = "duration") + private Long duration; // Duration in minutes + + @Column(name = "start_time") + private Timestamp startTime; + + @Column(name = "end_time") + private Timestamp endTime; + + @Column(name = "is_published", nullable = false) + private Boolean isPublished = false; + + @Column(name = "created_by", nullable = false) + private UUID createdBy; + + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @Column(name = "updated_by") + private UUID updatedBy; + + @Column(name = "updated_at") + private Timestamp updatedAt; + + @OneToMany(mappedBy = "quiz", cascade = CascadeType.ALL, orphanRemoval = true) + private List questions; + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuizSubmission.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuizSubmission.java new file mode 100644 index 0000000..5322a84 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/entity/QuizSubmission.java @@ -0,0 +1,59 @@ +package com.itgura.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "quiz_submission", schema = "quiz_management") +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class QuizSubmission { + + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "quiz_id", nullable = false) + private Quiz quiz; + + @Column(name = "student_id", nullable = false) + private UUID studentId; + + @Column(name = "submitted_at") + private Timestamp submittedAt; + + @Column(name = "score") + private Double score; + + @OneToMany(mappedBy = "quizSubmission", cascade = CascadeType.ALL, orphanRemoval = true) + private List answers; + + + @Column(name = "created_by", nullable = false) + private UUID createdBy; + + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @Column(name = "updated_by") + private UUID updatedBy; + + @Column(name = "updated_at") + private Timestamp updatedAt; + + // Getters and Setters +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/AssignmentRepository.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/AssignmentRepository.java new file mode 100644 index 0000000..2bc6cb2 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/AssignmentRepository.java @@ -0,0 +1,15 @@ +package com.itgura.repository; + +import com.itgura.entity.Assignment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.UUID; +@Repository +public interface AssignmentRepository extends JpaRepository { + @Query("SELECT a FROM Assignment a JOIN a.classIds c WHERE c IN :classIds") + List findByClassIdsIn(@Param("classIds") List classIds); +} diff --git a/user-management/user-management-dao/src/main/java/com/itgura/repository/UserRepository.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/QuestionRepository.java similarity index 50% rename from user-management/user-management-dao/src/main/java/com/itgura/repository/UserRepository.java rename to quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/QuestionRepository.java index acf3dde..14f6b34 100644 --- a/user-management/user-management-dao/src/main/java/com/itgura/repository/UserRepository.java +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/QuestionRepository.java @@ -1,19 +1,15 @@ package com.itgura.repository; - -import com.itgura.entity.User; -import com.itgura.enums.Role; +import com.itgura.entity.Question; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.stereotype.Repository; -import java.util.Optional; +import java.util.List; +import java.util.UUID; @Repository @EnableJpaRepositories -public interface UserRepository extends JpaRepository { - - - Optional findByEmail(String email); - Optional findByRole(Role role); +public interface QuestionRepository extends JpaRepository { + List findByQuiz_Id(UUID quizId); } diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/QuizRepository.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/QuizRepository.java new file mode 100644 index 0000000..4f8aada --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/repository/QuizRepository.java @@ -0,0 +1,17 @@ +package com.itgura.repository; + +import com.itgura.entity.Quiz; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.UUID; +@Repository +@EnableJpaRepositories +public interface QuizRepository extends JpaRepository { + @Query("SELECT q FROM Quiz q JOIN q.classIds c WHERE c IN :classIds") + List findByClassIdsIn(@Param("classIds") List classIds); +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/CreateAssignmentRequest.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/CreateAssignmentRequest.java new file mode 100644 index 0000000..e68f211 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/CreateAssignmentRequest.java @@ -0,0 +1,26 @@ +package com.itgura.request; + +import lombok.*; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class CreateAssignmentRequest { + + private String title; + private String description; + private List fileUrls; // Updated to handle a list of file URLs + private Timestamp deadline; + private Boolean isPublished; + private Long duration; + private UUID createdBy; + private List classIds; +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/CreateQuizRequest.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/CreateQuizRequest.java new file mode 100644 index 0000000..4934e17 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/CreateQuizRequest.java @@ -0,0 +1,49 @@ +package com.itgura.request; + +import com.itgura.entity.QuestionType; +import lombok.*; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class CreateQuizRequest { + + private String title; + private String description; + private Double totalMarks; + private UUID createdBy; + private List questions; + private List classIds; + private Long duration; + private Timestamp deadline; + + @Data + public static class QuizQuestionDTO { + private String questionText; + private QuestionType questionType; // MCQ, ESSAY, etc. + private Double marks; + private List options; // Only applicable for MCQ questions + private List files; // Applicable for both MCQ and Essay questions + } + + @Data + public static class MCQOptionDTO { + private String optionText; + private boolean isCorrect; + private QuestionFileDTO file; // Optional, for images or other files + } + + @Data + public static class QuestionFileDTO { + private UUID fileUrl; + private String fileType; // e.g., image/jpeg, application/pdf + } +} + diff --git a/user-management/user-management-dao/src/main/java/com/itgura/dto/response/AuthenticationResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/FileDTO.java similarity index 53% rename from user-management/user-management-dao/src/main/java/com/itgura/dto/response/AuthenticationResponse.java rename to quiz-management/quiz-management-dao/src/main/java/com/itgura/request/FileDTO.java index 6439f2a..30c9b48 100644 --- a/user-management/user-management-dao/src/main/java/com/itgura/dto/response/AuthenticationResponse.java +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/FileDTO.java @@ -1,4 +1,4 @@ -package com.itgura.dto.response; +package com.itgura.request; import lombok.AllArgsConstructor; import lombok.Builder; @@ -6,10 +6,12 @@ import lombok.NoArgsConstructor; @Data -@Builder @AllArgsConstructor @NoArgsConstructor -public class AuthenticationResponse { - private String authenticationToken; - private String refreshToken; +@Builder +public class FileDTO { + private String fileUrl; + private String fileType; + + } diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/OptionDTO.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/OptionDTO.java new file mode 100644 index 0000000..7fbb004 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/OptionDTO.java @@ -0,0 +1,19 @@ +package com.itgura.request; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class OptionDTO { + + private String optionText; + private Boolean isCorrect; + private FileDTO file; + + // Getters and Setters +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/QuestionDTO.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/QuestionDTO.java new file mode 100644 index 0000000..cd66b5d --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/request/QuestionDTO.java @@ -0,0 +1,20 @@ +package com.itgura.request; + +import lombok.*; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Setter +public class QuestionDTO { + private String questionText; + private String questionType; // e.g., MCQ, Essay + private Integer marks; + private List options; // Only for MCQ + private List files; + +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/AssignmentResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/AssignmentResponse.java new file mode 100644 index 0000000..ac84bdb --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/AssignmentResponse.java @@ -0,0 +1,24 @@ +package com.itgura.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class AssignmentResponse { + private UUID id; + private String title; + private String description; + private List fileUrl; + private Timestamp deadline; + private Boolean isPublished; + private List classIds; +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/AssignmentSummaryDTO.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/AssignmentSummaryDTO.java new file mode 100644 index 0000000..6cdde50 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/AssignmentSummaryDTO.java @@ -0,0 +1,22 @@ +package com.itgura.response; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.sql.Timestamp; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class AssignmentSummaryDTO { + private UUID id; + private String title; + private String description; + private Timestamp deadline; + private Long duration; // Duration in minutes +} diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/MCQOptionResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/MCQOptionResponse.java new file mode 100644 index 0000000..e405fd3 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/MCQOptionResponse.java @@ -0,0 +1,17 @@ +package com.itgura.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MCQOptionResponse { + private UUID id; + private String optionText; + private Boolean isCorrect; +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionAnswerResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionAnswerResponse.java new file mode 100644 index 0000000..077d01f --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionAnswerResponse.java @@ -0,0 +1,20 @@ +package com.itgura.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QuestionAnswerResponse { + private UUID id; + private UUID studentId; + private String answerText; + private UUID fileUrl; // URL to the file or image with the answer + private Timestamp submittedAt; +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionFileResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionFileResponse.java new file mode 100644 index 0000000..edbcaf9 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionFileResponse.java @@ -0,0 +1,17 @@ +package com.itgura.response; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QuestionFileResponse { + private UUID id; + private UUID imageUrl; // URL to the image file +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionResponse.java new file mode 100644 index 0000000..1ab5857 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuestionResponse.java @@ -0,0 +1,28 @@ +package com.itgura.response; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QuestionResponse { + private UUID id; + private String questionText; + private String questionType; // MCQ, ESSAY, etc. + private Double marks; + private UUID createdBy; + private Timestamp createdAt; + private UUID updatedBy; + private Timestamp updatedAt; + private List options; // List of options for MCQ questions + private List answers; // List of answers + private List images; // List of images associated with the question +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuizResponse.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuizResponse.java new file mode 100644 index 0000000..1ae5466 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuizResponse.java @@ -0,0 +1,21 @@ +package com.itgura.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.UUID; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class QuizResponse { + private UUID id; + private String title; + private String description; + private Double totalMarks; + private List classIds; // UUIDs of associated classes + private List questions; // List of questions associated with the quiz +} + diff --git a/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuizSummaryDTO.java b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuizSummaryDTO.java new file mode 100644 index 0000000..7a9f062 --- /dev/null +++ b/quiz-management/quiz-management-dao/src/main/java/com/itgura/response/QuizSummaryDTO.java @@ -0,0 +1,24 @@ +package com.itgura.response; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.sql.Timestamp; +import java.util.UUID; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class QuizSummaryDTO { + private UUID id; + private String title; + private String description; + private Timestamp startTime; + private Long duration; // Duration in minutes + private Timestamp deadline; +} + diff --git a/user-management/user-management-dao/src/main/resources/application-dev.properties b/quiz-management/quiz-management-dao/src/main/resources/application-dev.properties similarity index 78% rename from user-management/user-management-dao/src/main/resources/application-dev.properties rename to quiz-management/quiz-management-dao/src/main/resources/application-dev.properties index 17218b1..cd35b15 100644 --- a/user-management/user-management-dao/src/main/resources/application-dev.properties +++ b/quiz-management/quiz-management-dao/src/main/resources/application-dev.properties @@ -1,8 +1,9 @@ + spring.datasource.url=jdbc:postgresql://localhost:5432/itgura spring.datasource.username=postgres -spring.datasource.password=1234 -spring.datasource.hikari.schema=user_management +spring.datasource.password=root +spring.datasource.hikari.schema=quiz_management spring.datasource.driver-class-name=org.postgresql.Driver # Hibernate/JPA properties @@ -17,8 +18,7 @@ spring.jpa.properties.hibernate.schema_update.unique_constraint_strategy=RECREAT #spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true -spring.security.user.name=user -spring.security.user.password=user + spring.datasource.hikari.maximum-pool-size=10000 spring.datasource.hikari.minimum-idle= 10 @@ -28,4 +28,7 @@ spring.datasource.hikari.connectionTimeout= 5000 #eureka eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ eureka.client.registerWithEureka=true -eureka.client.fetchRegistry=true \ No newline at end of file +eureka.client.fetchRegistry=true +eureka.instance.hostname=localhost + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 \ No newline at end of file diff --git a/user-management/user-management-dao/src/main/resources/application-prod.properties b/quiz-management/quiz-management-dao/src/main/resources/application-prod.properties similarity index 83% rename from user-management/user-management-dao/src/main/resources/application-prod.properties rename to quiz-management/quiz-management-dao/src/main/resources/application-prod.properties index 973b78c..21548cf 100644 --- a/user-management/user-management-dao/src/main/resources/application-prod.properties +++ b/quiz-management/quiz-management-dao/src/main/resources/application-prod.properties @@ -1,8 +1,8 @@ spring.datasource.url=jdbc:postgresql://dpg-cp2qofi1hbls738314e0-a.oregon-postgres.render.com:5432/itgura -spring.datasource.username= it_gura_user +spring.datasource.username= postgres spring.datasource.password= lsbflvJ0HfdVIgbHNbCEZnzV3o9SAErn -spring.datasource.hikari.schema=resource_management +spring.datasource.hikari.schema=quiz_management spring.datasource.driver-class-name=org.postgresql.Driver # Hibernate/JPA properties @@ -17,8 +17,7 @@ spring.jpa.properties.hibernate.schema_update.unique_constraint_strategy=RECREAT #spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true -spring.security.user.name=user -spring.security.user.password=user + spring.datasource.hikari.maximum-pool-size=10000 spring.datasource.hikari.minimum-idle= 10 diff --git a/user-management/user-management-service/pom.xml b/quiz-management/quiz-management-service/pom.xml similarity index 69% rename from user-management/user-management-service/pom.xml rename to quiz-management/quiz-management-service/pom.xml index d6a82bc..db5042a 100644 --- a/user-management/user-management-service/pom.xml +++ b/quiz-management/quiz-management-service/pom.xml @@ -5,24 +5,23 @@ 4.0.0 com.itgura.lms - user-management + quiz-management 1.0.0 + jar - com.itgura.lms - user-management-service + quiz-management-service com.itgura.lms - user-management-dao + quiz-management-dao 1.0.0 compile - 17 - 17 + UTF-8 diff --git a/quiz-management/quiz-management-service/src/main/java/com/itgura/service/AssignmentService.java b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/AssignmentService.java new file mode 100644 index 0000000..2b1bf8a --- /dev/null +++ b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/AssignmentService.java @@ -0,0 +1,16 @@ +package com.itgura.service; + +import com.itgura.request.CreateAssignmentRequest; +import com.itgura.response.AssignmentResponse; +import com.itgura.response.AssignmentSummaryDTO; + +import java.util.List; +import java.util.UUID; + +public interface AssignmentService { + public String createAssignment(CreateAssignmentRequest request); + AssignmentResponse getAssignmentById(UUID id); // New method + public void deleteAssignment(UUID id); + public List getAssignmentsByClassIds(List classIds) ; + public boolean updatePublishedStatus(UUID id, Boolean isPublished); +} diff --git a/quiz-management/quiz-management-service/src/main/java/com/itgura/service/QuizService.java b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/QuizService.java new file mode 100644 index 0000000..831ad3f --- /dev/null +++ b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/QuizService.java @@ -0,0 +1,17 @@ +package com.itgura.service; + +import com.itgura.request.CreateAssignmentRequest; +import com.itgura.request.CreateQuizRequest; +import com.itgura.response.QuizResponse; +import com.itgura.response.QuizSummaryDTO; + +import java.util.List; +import java.util.UUID; + +public interface QuizService { + public String createQuiz(CreateQuizRequest request); + QuizResponse getQuizById(UUID id); + public void deleteQuiz(UUID id); + public List getQuizzesByClassIds(List classIds); + public boolean updatePublishedStatus(UUID id, Boolean isPublished); +} diff --git a/quiz-management/quiz-management-service/src/main/java/com/itgura/service/impl/AssignmentServiceImpl.java b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/impl/AssignmentServiceImpl.java new file mode 100644 index 0000000..1c268e9 --- /dev/null +++ b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/impl/AssignmentServiceImpl.java @@ -0,0 +1,102 @@ +package com.itgura.service.impl; + +import com.itgura.entity.Assignment; +import com.itgura.repository.AssignmentRepository; +import com.itgura.request.CreateAssignmentRequest; +import com.itgura.response.AssignmentResponse; +import com.itgura.response.AssignmentSummaryDTO; +import com.itgura.service.AssignmentService; +import jakarta.transaction.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +public class AssignmentServiceImpl implements AssignmentService { + @Autowired + private AssignmentRepository assignmentRepository; + @Override + @Transactional + public String createAssignment(CreateAssignmentRequest request) { + try { + // Create and set up the Assignment entity + Assignment assignment = new Assignment(); + assignment.setTitle(request.getTitle()); + assignment.setDescription(request.getDescription()); + assignment.setFileUrls(request.getFileUrls()); // Updated to handle list of file URLs + assignment.setDeadline(request.getDeadline()); + assignment.setDuration(request.getDuration()); + assignment.setIsPublished(request.getIsPublished()); + assignment.setCreatedBy(request.getCreatedBy()); + assignment.setCreatedAt(new Timestamp(System.currentTimeMillis())); + assignment.setClassIds(request.getClassIds()); + + // Save the assignment and return the assignment ID + Assignment savedAssignment = assignmentRepository.save(assignment); + return "Assignment created successfully with ID: " + savedAssignment.getId().toString(); + } catch (Exception e) { + return "Error creating assignment: " + e.getMessage(); + } + } + @Override + @Transactional + public AssignmentResponse getAssignmentById(UUID id) { + Optional assignmentOptional = assignmentRepository.findById(id); + if (assignmentOptional.isPresent()) { + Assignment assignment = assignmentOptional.get(); + + // Map to DTO + return new AssignmentResponse( + assignment.getId(), + assignment.getTitle(), + assignment.getDescription(), + assignment.getFileUrls(), // Updated to handle list of file URLs + assignment.getDeadline(), + assignment.getIsPublished(), + assignment.getClassIds() + ); + } else { + throw new RuntimeException("Assignment not found"); + } + } + + @Override + @Transactional + public void deleteAssignment(UUID id) { + if (assignmentRepository.existsById(id)) { + assignmentRepository.deleteById(id); + } else { + throw new RuntimeException("Assignment not found with ID: " + id); + } + } + @Override + @Transactional + public List getAssignmentsByClassIds(List classIds) { + List assignments = assignmentRepository.findByClassIdsIn(classIds); + return assignments.stream().map(assignment -> new AssignmentSummaryDTO( + assignment.getId(), + assignment.getTitle(), + assignment.getDescription(), + assignment.getDeadline(), + assignment.getDuration() + )).collect(Collectors.toList()); + } + + @Override + @Transactional + public boolean updatePublishedStatus(UUID id, Boolean isPublished) { + Optional optionalAssignment = assignmentRepository.findById(id); + if (optionalAssignment.isPresent()) { + Assignment assignment = optionalAssignment.get(); + assignment.setIsPublished(isPublished); + assignmentRepository.save(assignment); + return true; + } + return false; + } +} diff --git a/quiz-management/quiz-management-service/src/main/java/com/itgura/service/impl/QuizServiceImpl.java b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/impl/QuizServiceImpl.java new file mode 100644 index 0000000..84844e5 --- /dev/null +++ b/quiz-management/quiz-management-service/src/main/java/com/itgura/service/impl/QuizServiceImpl.java @@ -0,0 +1,195 @@ +package com.itgura.service.impl; + +import com.itgura.entity.*; +import com.itgura.repository.QuestionRepository; +import com.itgura.repository.QuizRepository; +import com.itgura.repository.AssignmentRepository; +import com.itgura.request.CreateQuizRequest; +import com.itgura.request.CreateAssignmentRequest; +import com.itgura.response.*; +import com.itgura.service.QuizService; +import jakarta.transaction.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.UUID; + +@Service +public class QuizServiceImpl implements QuizService { + + @Autowired + private QuizRepository quizRepository; + + @Autowired + private QuestionRepository questionRepository; + + + + @Override + @Transactional + public String createQuiz(CreateQuizRequest request) { + try { + // Create and set up the Quiz entity + Quiz quiz = new Quiz(); + quiz.setTitle(request.getTitle()); + quiz.setDescription(request.getDescription()); + quiz.setTotalMarks(request.getTotalMarks()); + quiz.setCreatedBy(request.getCreatedBy()); + quiz.setDeadline(request.getDeadline()); + quiz.setDuration(request.getDuration()); + quiz.setCreatedAt(new Timestamp(System.currentTimeMillis())); + quiz.setUpdatedBy(null); + quiz.setUpdatedAt(null); + quiz.setClassIds(request.getClassIds()); + + // Process the questions + List questions = request.getQuestions().stream().map(q -> { + Question question = new Question(); + question.setQuestionText(q.getQuestionText()); + question.setQuestionType(q.getQuestionType()); + question.setMarks(q.getMarks()); + question.setQuiz(quiz); + question.setCreatedBy(request.getCreatedBy()); + question.setCreatedAt(new Timestamp(System.currentTimeMillis())); + question.setUpdatedBy(null); + question.setUpdatedAt(null); + + // Process options if it's an MCQ + if (q.getQuestionType() == QuestionType.MCQ) { + List options = q.getOptions().stream().map(o -> { + MCQOption option = new MCQOption(); + option.setOptionText(o.getOptionText()); + option.setIsCorrect(o.isCorrect()); + // Attach image if exists + if (o.getFile() != null) { + QuestionFile imageFile = new QuestionFile(); + imageFile.setImageUrl(o.getFile().getFileUrl()); // Assuming the file URL is a UUID + imageFile.setQuestion(question); + + } + + option.setQuestion(question); + return option; + }).collect(Collectors.toList()); + question.setOptions(options); + } + + // Attach files for both MCQ and Essay + if (q.getFiles() != null) { + List files = q.getFiles().stream().map(f -> { + QuestionFile file = new QuestionFile(); + file.setImageUrl(f.getFileUrl()); // Assuming the file URL is a UUID + file.setQuestion(question); + + return file; + }).collect(Collectors.toList()); + question.setImages(files); + } + + return question; + }).collect(Collectors.toList()); + + quiz.setQuestions(questions); + + // Save the quiz and return the quiz ID + Quiz savedQuiz = quizRepository.save(quiz); + return "Quiz created successfully with ID: " + savedQuiz.getId().toString(); + } catch (Exception e) { + return "Error creating quiz: " + e.getMessage(); + } + } + @Override + @Transactional + public QuizResponse getQuizById(UUID id) { + Optional quizOptional = quizRepository.findById(id); + if (quizOptional.isPresent()) { + Quiz quiz = quizOptional.get(); + + // Fetch questions for the quiz + List questions = questionRepository.findByQuiz_Id(id); + + // Map to DTO + List questionResponses = questions.stream().map(question -> { + return new QuestionResponse( + question.getId(), + question.getQuestionText(), + question.getQuestionType().name(), // Convert enum to string + question.getMarks(), + question.getCreatedBy(), + question.getCreatedAt(), + question.getUpdatedBy(), + question.getUpdatedAt(), + question.getOptions().stream().map(option -> new MCQOptionResponse( + option.getId(), + option.getOptionText(), + option.getIsCorrect() + )).collect(Collectors.toList()), + question.getAnswers().stream().map(answer -> new QuestionAnswerResponse( + answer.getId(), + answer.getStudentId(), + answer.getAnswerText(), + answer.getFileUrl(), + answer.getSubmittedAt() + )).collect(Collectors.toList()), + question.getImages().stream().map(file -> new QuestionFileResponse( + file.getId(), + file.getImageUrl() + )).collect(Collectors.toList()) + ); + }).collect(Collectors.toList()); + + // Map to QuizResponse DTO + return new QuizResponse( + quiz.getId(), + quiz.getTitle(), + quiz.getDescription(), + quiz.getTotalMarks(), + quiz.getClassIds(), + questionResponses + ); + } else { + throw new RuntimeException("Quiz not found"); + } + } + + @Override + @Transactional + public void deleteQuiz(UUID id) { + if (quizRepository.existsById(id)) { + quizRepository.deleteById(id); + } else { + throw new RuntimeException("Quiz not found with ID: " + id); + } + } + @Override + @Transactional + public List getQuizzesByClassIds(List classIds) { + List quizzes = quizRepository.findByClassIdsIn(classIds); + return quizzes.stream().map(quiz -> new QuizSummaryDTO( + quiz.getId(), + quiz.getTitle(), + quiz.getDescription(), + quiz.getStartTime(), + quiz.getDuration(), + quiz.getDeadline() + )).collect(Collectors.toList()); + } + + @Override + @Transactional + public boolean updatePublishedStatus(UUID id, Boolean isPublished) { + Optional optionalQuiz = quizRepository.findById(id); + if (optionalQuiz.isPresent()) { + Quiz quiz = optionalQuiz.get(); + quiz.setIsPublished(isPublished); + quizRepository.save(quiz); + return true; + } + return false; + } + +} diff --git a/resource-management/pom.xml b/resource-management/pom.xml index bffad5b..29712d7 100644 --- a/resource-management/pom.xml +++ b/resource-management/pom.xml @@ -3,14 +3,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.boot - spring-boot-starter-parent - 3.2.4 - + com.itgura.lms + lms + 1.0.0 + - com.itgura.lms - resource-management pom + resource-management + resource-management-all resource-management-dao @@ -20,16 +20,25 @@ 17 - 17 - 17 2023.0.1 + + org.springframework.cloud spring-cloud-starter-netflix-eureka-client + + org.springframework.boot + spring-boot-starter-web + + + + + + @@ -44,6 +53,16 @@ + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/resource-management/resource-management-all/pom.xml b/resource-management/resource-management-all/pom.xml index 2baf9fe..00368cf 100644 --- a/resource-management/resource-management-all/pom.xml +++ b/resource-management/resource-management-all/pom.xml @@ -9,8 +9,29 @@ 1.0.0 - com.itgura.lms + jar resource-management-all + + + build-docker-image + + + + com.google.cloud.tools + jib-maven-plugin + + + package + + build + + + + + + + + com.itgura.lms @@ -28,6 +49,7 @@ 17 UTF-8 + @@ -37,4 +59,5 @@ + \ No newline at end of file diff --git a/resource-management/resource-management-all/src/main/resources/application-docker.properties b/resource-management/resource-management-all/src/main/resources/application-docker.properties new file mode 100644 index 0000000..fef4fb5 --- /dev/null +++ b/resource-management/resource-management-all/src/main/resources/application-docker.properties @@ -0,0 +1,40 @@ +server.port=8092 +spring.application.name=resource-management +logging.level.org.springframework.core.env=DEBUG +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration +logging.level.org.springframework.security=DEBUG + + + +spring.datasource.url=jdbc:postgresql://postgres-main:5432/itgura +spring.datasource.username=postgres +spring.datasource.password=root +spring.datasource.hikari.schema=resource_management +spring.datasource.driver-class-name=org.postgresql.Driver + +# Hibernate/JPA properties +spring.jpa.show-sql=true + + +spring.jpa.hibernate.ddl-auto = update +spring.sql.init.mode=always +spring.jpa.generate-ddl=true +spring.jpa.open-in-view=false +spring.jpa.properties.hibernate.schema_update.unique_constraint_strategy=RECREATE_QUIETLY +#spring.jpa.hibernate.ddl-auto=create +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true + + + +spring.datasource.hikari.maximum-pool-size=10000 +spring.datasource.hikari.minimum-idle= 10 +spring.datasource.hikari.idle-timeout= 120000 +spring.datasource.hikari.connectionTimeout= 5000 + +#eureka +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka/ +eureka.client.registerWithEureka=true +eureka.client.fetchRegistry=true +eureka.instance.hostname=eureka-server + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 \ No newline at end of file diff --git a/resource-management/resource-management-all/src/main/resources/application-kube.properties b/resource-management/resource-management-all/src/main/resources/application-kube.properties new file mode 100644 index 0000000..c4efa01 --- /dev/null +++ b/resource-management/resource-management-all/src/main/resources/application-kube.properties @@ -0,0 +1,45 @@ +server.port=8092 +spring.application.name=resource-management +logging.level.org.springframework.core.env=DEBUG +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration +logging.level.org.springframework.security=DEBUG + + + +spring.datasource.url=jdbc:postgresql://postgres/itgura +spring.datasource.username=postgres +spring.datasource.password=root +spring.datasource.hikari.schema=resource_management +spring.datasource.driver-class-name=org.postgresql.Driver + +# Hibernate/JPA properties +spring.jpa.show-sql=true + + +spring.jpa.hibernate.ddl-auto = update +spring.sql.init.mode=always +spring.jpa.generate-ddl=true +spring.jpa.open-in-view=false +spring.jpa.properties.hibernate.schema_update.unique_constraint_strategy=RECREATE_QUIETLY +#spring.jpa.hibernate.ddl-auto=create +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true + + + +spring.datasource.hikari.maximum-pool-size=10000 +spring.datasource.hikari.minimum-idle= 10 +spring.datasource.hikari.idle-timeout= 120000 +spring.datasource.hikari.connectionTimeout= 5000 + +#linkered +spring.cloud.gateway.discovery.locator.enabled=true +spring.cloud.gateway.discovery.locator.lower-case-service-id=true + +#eureka +eureka.client.enabled=false +eureka.client.serviceUrl.defaultZone=http://eureka-server:8761/eureka/ +eureka.client.registerWithEureka=true +eureka.client.fetchRegistry=true +eureka.instance.hostname=eureka-server + +jwt.secretKey = f2b21eeadc7f3693dbc373dca5f49400293d722eb955353c11250b9367cd1635 \ No newline at end of file diff --git a/resource-management/resource-management-dao/pom.xml b/resource-management/resource-management-dao/pom.xml index 1ca89ab..3f064ad 100644 --- a/resource-management/resource-management-dao/pom.xml +++ b/resource-management/resource-management-dao/pom.xml @@ -9,12 +9,11 @@ 1.0.0 - com.itgura.lms + jar resource-management-dao - 17 - 17 + UTF-8 diff --git a/resource-management/resource-management-dao/src/main/resources/application-dev.properties b/resource-management/resource-management-dao/src/main/resources/application-dev.properties index 15c30d7..1b0b737 100644 --- a/resource-management/resource-management-dao/src/main/resources/application-dev.properties +++ b/resource-management/resource-management-dao/src/main/resources/application-dev.properties @@ -2,7 +2,7 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/itgura spring.datasource.username=postgres -spring.datasource.password=1234 +spring.datasource.password=root spring.datasource.hikari.schema=resource_management spring.datasource.driver-class-name=org.postgresql.Driver diff --git a/resource-management/resource-management-service/pom.xml b/resource-management/resource-management-service/pom.xml index c356154..baf1330 100644 --- a/resource-management/resource-management-service/pom.xml +++ b/resource-management/resource-management-service/pom.xml @@ -8,8 +8,8 @@ resource-management 1.0.0 + jar - com.itgura.lms resource-management-service @@ -21,8 +21,7 @@ - 17 - 17 + UTF-8 diff --git a/set_trusted_domains.sh b/set_trusted_domains.sh new file mode 100644 index 0000000..ac12b3a --- /dev/null +++ b/set_trusted_domains.sh @@ -0,0 +1,8 @@ +#!/bin/bash +CONFIG_PATH=/var/www/html/config/config.php +if ! grep -q "'trusted_domains' =>" $CONFIG_PATH; then + echo "Setting trusted domain in config.php" + sed -i "s/0 => 'localhost'/0 => 'localhost', 1 => 'nextcloud'/" $CONFIG_PATH +else + echo "Trusted domain already set" +fi \ No newline at end of file diff --git a/test.html b/test.html new file mode 100644 index 0000000..b73ab23 --- /dev/null +++ b/test.html @@ -0,0 +1,40 @@ + + + + + + Sign in with Google + + + +
+

Sign in with Google

+ +
+ + diff --git a/user-management/.mvn/wrapper/maven-wrapper.properties b/user-management/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 5f0536e..0000000 --- a/user-management/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,2 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-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/user-management/pom.xml b/user-management/pom.xml deleted file mode 100644 index a77bed2..0000000 --- a/user-management/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.2.4 - - - com.itgura.lms - user-management - pom - - user-management-all - user-management-dao - user-management-service - - 1.0.0 - - - 17 - 17 - 17 - 2023.0.1 - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - - - - diff --git a/user-management/user-management-all/src/main/java/com/itgura/config/SecurityConfiguration.java b/user-management/user-management-all/src/main/java/com/itgura/config/SecurityConfiguration.java deleted file mode 100644 index 5c93bff..0000000 --- a/user-management/user-management-all/src/main/java/com/itgura/config/SecurityConfiguration.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.itgura.config; - - -import com.itgura.enums.Role; -import com.itgura.util.JwtService; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -@EnableWebSecurity -@RequiredArgsConstructor -public class SecurityConfiguration { - - private final JwtService jwtService; - - private final AuthenticationProvider authenticationProvider; - - - - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - - JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(); - jwtAuthenticationFilter.setJwtService(jwtService); - - http.csrf(AbstractHttpConfigurer::disable) - .authorizeHttpRequests(request->request.requestMatchers( - "/api/v1/auth/**", - "/v2/api-docs", - "/configuration/ui", - "/swagger-resources/**", - "/configuration/security", - "/swagger-ui.html", - "/webjars/**") - - .permitAll() - .requestMatchers("/api/v1/admin/**").hasAnyAuthority(Role.ADMIN.name()) - .requestMatchers("/api/v1/user/**").hasAnyAuthority(Role.USER.name()) - .anyRequest().authenticated()) - - .sessionManagement(manager->manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authenticationProvider(authenticationProvider) - .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); - - - - return http.build(); - } -} diff --git a/user-management/user-management-all/src/main/java/com/itgura/controller/sampleController.java b/user-management/user-management-all/src/main/java/com/itgura/controller/sampleController.java deleted file mode 100644 index 90a6da6..0000000 --- a/user-management/user-management-all/src/main/java/com/itgura/controller/sampleController.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.itgura.controller; - -public class sampleController { -} diff --git a/user-management/user-management-all/src/main/resources/application.properties b/user-management/user-management-all/src/main/resources/application.properties deleted file mode 100644 index 1d6e8c7..0000000 --- a/user-management/user-management-all/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -server.port=8091 -spring.application.name=user-management -logging.level.org.springframework.core.env=DEBUG -spring.profiles.active=dev diff --git a/user-management/user-management-dao/pom.xml b/user-management/user-management-dao/pom.xml deleted file mode 100644 index d56c17e..0000000 --- a/user-management/user-management-dao/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - 4.0.0 - - com.itgura.lms - user-management - 1.0.0 - - - com.itgura.lms - user-management-dao - - - 17 - 17 - UTF-8 - - - - com.itgura.lms - lib-security - 0.0.1 - - - com.itgura.lms - lib-global - 0.0.1 - - - org.apache.commons - commons-lang3 - 3.14.0 - - - - com.mysql - mysql-connector-j - 8.1.0 - - - org.postgresql - postgresql - 42.7.1 - - - org.projectlombok - lombok - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - \ No newline at end of file diff --git a/user-management/user-management-dao/src/main/java/com/itgura/dto/request/RegisterRequest.java b/user-management/user-management-dao/src/main/java/com/itgura/dto/request/RegisterRequest.java deleted file mode 100644 index cc3f167..0000000 --- a/user-management/user-management-dao/src/main/java/com/itgura/dto/request/RegisterRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itgura.dto.request; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class RegisterRequest { - private String firstName; - private String lastName; - private String email; - - private String password; -} diff --git a/user-management/user-management-dao/src/main/java/com/itgura/entity/User.java b/user-management/user-management-dao/src/main/java/com/itgura/entity/User.java deleted file mode 100644 index 8891c2d..0000000 --- a/user-management/user-management-dao/src/main/java/com/itgura/entity/User.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.itgura.entity; - -import com.itgura.enums.Role; -import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Collection; -import java.util.List; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Entity -@Table(name = "_user") -public class User implements UserDetails { - - @Id - @GeneratedValue - private Integer id; - private String firstName; - private String lastName; - private String email; - private String password; - @Enumerated(EnumType.STRING) - private Role role; - - @Override - public Collection getAuthorities() { - return List.of(new SimpleGrantedAuthority(role.name())); - } - - @Override - public String getUsername() { - return this.email; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public String getPassword() { - return this.password; - } -} diff --git a/user-management/user-management-dao/src/main/java/com/itgura/enums/Role.java b/user-management/user-management-dao/src/main/java/com/itgura/enums/Role.java deleted file mode 100644 index 06a1f8b..0000000 --- a/user-management/user-management-dao/src/main/java/com/itgura/enums/Role.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.itgura.enums; - -public enum Role { - USER, - ADMIN -} diff --git a/user-management/user-management-service/src/main/java/com/itgura/service/AuthenticationService.java b/user-management/user-management-service/src/main/java/com/itgura/service/AuthenticationService.java deleted file mode 100644 index 4f5c144..0000000 --- a/user-management/user-management-service/src/main/java/com/itgura/service/AuthenticationService.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.itgura.service; - -import com.itgura.dto.request.AuthenticationRequest; -import com.itgura.dto.request.RegisterRequest; -import com.itgura.dto.response.AuthenticationResponse; - -public interface AuthenticationService { - public AuthenticationResponse register(RegisterRequest registerRequest); - public AuthenticationResponse authenticate(AuthenticationRequest authenticationRequest); - public AuthenticationResponse refreshToken(String refreshToken); -} diff --git a/user-management/user-management-service/src/main/java/com/itgura/service/impl/AuthenticationServiceImpl.java b/user-management/user-management-service/src/main/java/com/itgura/service/impl/AuthenticationServiceImpl.java deleted file mode 100644 index 10485fc..0000000 --- a/user-management/user-management-service/src/main/java/com/itgura/service/impl/AuthenticationServiceImpl.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.itgura.service.impl; - -import com.itgura.dto.request.AuthenticationRequest; -import com.itgura.dto.request.RegisterRequest; -import com.itgura.dto.response.AuthenticationResponse; -import com.itgura.entity.User; -import com.itgura.enums.Role; -import com.itgura.repository.UserRepository; -import com.itgura.service.AuthenticationService; -import com.itgura.util.JwtService; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.util.HashMap; - -@Service -@RequiredArgsConstructor -public class AuthenticationServiceImpl implements AuthenticationService { - private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; - private final JwtService jwtService; - private final AuthenticationManager authenticationManager; - @Override - public AuthenticationResponse register(RegisterRequest registerRequest) { - var user = User.builder() - .firstName(registerRequest.getFirstName()) - .lastName(registerRequest.getLastName()) - .email(registerRequest.getEmail()) - .password(passwordEncoder.encode(registerRequest.getPassword())) - .role(Role.USER) - .build(); - userRepository.save(user); - var jwtToken = jwtService.generateToken(user); - return AuthenticationResponse.builder() - .authenticationToken(jwtToken) - .build(); - } - - @Override - public AuthenticationResponse authenticate(AuthenticationRequest authenticationRequest) { - authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(authenticationRequest.getEmail(), authenticationRequest.getPassword()) - ); - var user = userRepository.findByEmail(authenticationRequest.getEmail()).orElseThrow(() -> new IllegalArgumentException("Invalid email or password")); - var jwtToken = jwtService.generateToken(user); - var refreshToken = jwtService.generateRefresh(new HashMap<>(),user); - return AuthenticationResponse.builder() - .authenticationToken(jwtToken) - .refreshToken(refreshToken) - .build(); - } - - @Override - public AuthenticationResponse refreshToken(String refreshToken) { -// var user = userRepository.findByEmail( ) -// var jwtToken = jwtService.generateToken(user); -// return AuthenticationResponse.builder() -// .authenticationToken(jwtToken) -// .build(); - return null; - } - -@Bean - public UserDetailsService userDetailsService() { - return username -> userRepository.findByEmail(username) - .orElseThrow(() -> new UsernameNotFoundException("User not found")); - } - - @Bean - public AuthenticationProvider authenticationProvider(){ - DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); - provider.setUserDetailsService(userDetailsService()); - provider.setPasswordEncoder(passwordEncoder()); - return provider; - } - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { - return config.getAuthenticationManager(); - } - -@Bean - public PasswordEncoder passwordEncoder(){ - return new BCryptPasswordEncoder(); - } -} diff --git a/youtube-permission-manager.iml b/youtube-permission-manager.iml new file mode 100644 index 0000000..27754dd --- /dev/null +++ b/youtube-permission-manager.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file