diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index dd84ea7..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..5666e66 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,96 @@ + +name: Bug Report +title: "[Bug] Bug title " +description: Create a report to help us identify any unintended flaws, errors, or faults. +body: + - type: checkboxes + attributes: + label: Before Creating the Bug Report + options: + - label: > + I found a bug, not just asking a question, which should be created in [GitHub Discussions](https://github.com/mdgspace/activity-leaderboard-backend/discussions). + required: true + - label: > + I have searched the [GitHub Issues](https://github.com/mdgspace/activity-leaderboard-backend/issues) and [GitHub Discussions](https://github.com/mdgspace/activity-leaderboard-backend/discussions) of this repository and believe that this is not a duplicate. + required: true + - label: > + I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ. + required: true + + - type: textarea + attributes: + label: Runtime platform environment + description: Describe the runtime platform environment. + placeholder: > + OS: (e.g., "Ubuntu 20.04") + OS: (e.g., "Windows Server 2019") + validations: + required: true + + - type: textarea + attributes: + label: Backend version + description: Describe the Backend version. + placeholder: > + branch: (e.g main) + version: (e.g. 1.0.0) + Git commit id: (e.g. c88b5cfa72e204962929eea105687647146112c6) + validations: + required: true + + - type: textarea + attributes: + label: JDK Version + description: Run or Compiler version. + placeholder: > + Compiler: (e.g., "Oracle JDK 11.0.17") + OS: (e.g., "Ubuntu 20.04") + Runtime (if different from JDK above): (e.g., "Oracle JRE 8u251") + OS (if different from OS compiled on): (e.g., "Windows Server 2019") + validations: + required: false + + - type: textarea + attributes: + label: Describe the Bug + description: Describe what happened. + placeholder: > + A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + attributes: + label: Steps to Reproduce + description: Describe the steps to reproduce the bug here. + placeholder: > + If possible, provide a recipe for reproducing the error. + validations: + required: true + + - type: textarea + attributes: + label: What Did You Expect to See? + description: You expect to see result. + placeholder: > + A clear and concise description of what you expected to see. + validations: + required: true + + - type: textarea + attributes: + label: What Did You See Instead? + description: You instead to see result. + placeholder: > + A clear and concise description of what you saw instead. + validations: + required: true + + - type: textarea + attributes: + label: Additional Context + description: Additional context. + placeholder: > + Add any other context about the problem here. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..8a095cf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,7 @@ + + +blank_issues_enabled: false +contact_links: + - name: Ask Question + url: https://github.com/mdgspace/activity-leaderboard-backend/discussions + about: Please go to GitHub Disccusions to ask questions diff --git a/.github/ISSUE_TEMPLATE/doc.yml b/.github/ISSUE_TEMPLATE/doc.yml new file mode 100644 index 0000000..540229f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/doc.yml @@ -0,0 +1,39 @@ + +name: Documentation Related +title: "[Doc] Documentation Related " +description: I find some issues related to the documentation. +labels: [ "module/doc" ] +body: + - type: checkboxes + attributes: + label: Search before creation + description: > + Please make sure to search in the [issues](https://github.com/mdgspace/activity-leaderboard-backend/issues) + first to see whether the same issue was reported already. + options: + - label: > + I had searched in the [issues](https://github.com/mdgspace/activity-leaderboard-backend/issues) and found + no similar issues. + required: true + + - type: textarea + attributes: + label: Documentation Related + description: Describe the suggestion about document. + placeholder: > + e.g There is a typo + validations: + required: true + + - type: checkboxes + attributes: + label: Are you willing to submit PR? + description: > + This is absolutely not required, but we are happy to guide you in the contribution process + especially if you already have a good understanding of how to implement the fix. + options: + - label: Yes I am willing to submit a PR! + + - type: markdown + attributes: + value: "Thanks for completing our form!" diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.yml b/.github/ISSUE_TEMPLATE/enhancement_request.yml new file mode 100644 index 0000000..ab04414 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement_request.yml @@ -0,0 +1,59 @@ + + +name: Enhancement Request +title: "[Enhancement] Enhancement title" +description: Suggest an enhancement for this project +labels: [ "type/enhancement" ] +body: + - type: checkboxes + attributes: + label: Before Creating the Enhancement Request + description: > + Most of issues should be classified as bug or feature request. An issue should be considered as an enhancement when it proposes improvements to + existing functionality or user experience, without necessarily introducing new features or fixing existing bugs. + options: + - label: > + I have confirmed that this should be classified as an enhancement rather than a bug/feature. + required: true + + - type: textarea + attributes: + label: Summary + placeholder: > + A clear and concise description of the enhancement you would like to see in the project. + validations: + required: true + + - type: textarea + attributes: + label: Motivation + placeholder: > + Explain why you believe this enhancement is necessary, and how it benefits the project and community. + Include any specific use cases that you have in mind. + validations: + required: true + + - type: textarea + attributes: + label: Describe the Solution You'd Like + placeholder: > + Describe the enhancement you propose, detailing the change and implementation steps involved. + If you have multiple solutions, please list them separately. + validations: + required: true + + - type: textarea + attributes: + label: Describe Alternatives You've Considered + placeholder: > + List any alternative enhancements or implementations you have considered, and explain why they may not be as effective or appropriate. + validations: + required: true + + - type: textarea + attributes: + label: Additional Context + placeholder: > + Add any relevant context, screenshots, prototypes, or other supplementary information to help illustrate the enhancement. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..435718e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,41 @@ + +name: Feature Request +title: "[Feature] New feature title" +description: Suggest an idea for this project. +labels: [ "type/new feature" ] +body: + - type: textarea + attributes: + label: Is Your Feature Request Related to a Problem? + description: Please Describe It. + placeholder: > + A clear and concise description of what the problem is. + validations: + required: true + + - type: textarea + attributes: + label: Describe the Solution You'd Like + description: Describe how you solved it. + placeholder: > + A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + attributes: + label: Describe Alternatives You've Considered + description: Describe your solution + placeholder: > + A clear and concise description of any alternative solutions or features you've considered. + validations: + required: true + + - type: textarea + attributes: + label: Additional Context + description: Additional context. + placeholder: > + Add any other context about the problem here. + validations: + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..96bffa5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ + + +### Which Issue(s) This PR Fixes + + + +Fixes #issue_id + +### Brief Description + + + +### How Did You Test This Change? + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..72c2aa5 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,21 @@ +name: CI Workflow +on: + pull_request: + branches: [ main ] + paths: + - 'src/**' + push: + branches: [main] + paths: + - 'src/**' +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 17 + - name: Build and test + run: mvn clean install \ No newline at end of file diff --git a/.github/workflows/misspell_check.yml b/.github/workflows/misspell_check.yml new file mode 100644 index 0000000..849aa2e --- /dev/null +++ b/.github/workflows/misspell_check.yml @@ -0,0 +1,17 @@ +name: Misspell Check +on: + pull_request: + types: [opened, reopened, synchronize] + push: + branches: [main] +jobs: + misspell-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install misspell + run: | + curl -L -o ./install-misspell.sh https://git.io/misspell + sh ./install-misspell.sh + - name: Run misspell + run: find . -type f -print0 | xargs -0 bin/misspell -error -i transfered,derivate diff --git a/.gitignore b/.gitignore index 313b621..e685abf 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,8 @@ build/ # keys env.sh -env.list \ No newline at end of file +env.list + +postgres +files + diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index efe120e..a397f71 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -1,20 +1,94 @@ -# Contribution guide +# Activity-leaderboard Backend -### Documentation -#### Single Line Docs +## Run Locally + +#### Prerequisites : + + - [Git](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup) + - [WSL (only for windows)](https://www.oracle.com/java/technologies/downloads/) + - [Docker](https://docs.docker.com/engine/install/) + - [AWS CLI](https://cloudacademy.com/blog/how-to-use-aws-cli/) + - [Github OAuth Application](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) + + +#### Clone the Repo +``` +git clone https://github.com/mdgspace/activity-leaderboard-backend.git +``` +#### Change current folder to project folder + +``` +cd activity-leaderboard-backend +``` + +#### Create env.list from env.list.example + +``` + +# Postgres configurations +POSTGRES_HOST=postgres +POSTGRES_USER=sudo +POSTGRES_PASSWORD=sudo +POSTGRES_DB=test + + +#Redis configuration +REDIS_HOST=redis +REDIS_PASS= + +# Github configuration + +GITHUB_CLIENT_ID=you github oauth application client id +GITHUB_CLIENT_SECRET=you github oauth application client id + + +# AWS Configurations +AWS_BUCKET=bucketname +AWS_ACCESS=localstack +AWS_SECRET=localstack +AWS_URL=http://localstack:4566 +AWS_REGION=us-east-1 + + + + +``` + +#### Run Docker compose (In root dierectory) +``` +docker compose up -d +``` + +#### Run localstack s3 image -use `//` ``` -// +docker run -d --name localstack --network activity-leaderboard-backend_network -e SERVICES=s3 -p 4566:4566 localstack/localstack +``` +#### Create s3 bucket + +``` + +aws --endpoint-url=http://localhost:4566 s3api create-bucket --bucket bucketname --region us-east-1 + + +aws --endpoint-url=http://localhost:4566 s3 ls + +``` + +### Get the ip of locakstack container +``` +docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' localstack +``` + + +#### Build backend image(in root dierectory) +``` +docker build -t activity-backend:latest . + ``` -#### Multiline Docs +#### Run backend image ``` -/** -* your docs -* your docs -* your docs -* your docs -*/ +docker run --name backend --network activity-leaderboard-backend_network -dp 8080:8080 --env-file env.list activity-backend:latest ``` \ No newline at end of file diff --git a/README.md b/README.md index c860099..03c7771 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,21 @@ # Activity-leaderboard Backend +### Activity Leader Board is a open source project which can be used to monitor progress in an Organization . +## Tech Stack -## Run Locally +**Backend:** SpringBoot -#### Prerequisite: +**Frontend:** React - - [Git](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup) - - java version 17 https://www.oracle.com/java/technologies/downloads/ - - maven version 3.8.8 https://maven.apache.org/install.html - - PostrgresSql latest https://www.postgresql.org/download/ +**Cloud:** AWS - Setup frontend https://github.com/yp969803/githubauth-frontend-testing.git -#### Clone the Repo -``` -git clone https://github.com/mdgspace/activity-leaderboard-backend.git -``` -Change current folder to project folder -For Linux -``` -cd activity-leaderboard-backend -``` -#### PostgresQL server -Start postgresQl server and crete user {postgres} password {postgres} and database {test} +**Database**: Postgres -#### Set up application.properties https://github.com/mdgspace/activity-leaderboard-backend/blob/main/src/main/resources/application.properties +**Caching**: Redis -#### Start server -``` -mvn run -# Or you can run through vscode -``` + +### Activity-leaderboard Frontend +[frontend](https://github.com/mdgspace/activity-leaderboard.git) \ No newline at end of file diff --git a/cat.jpg b/cat.jpg new file mode 100644 index 0000000..7351fbc Binary files /dev/null and b/cat.jpg differ diff --git a/docker-compose.yaml b/docker-compose.yaml index 6d4943e..37a4422 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,38 +1,27 @@ version: '3.3' +networks: + network: + driver: bridge services: - api: - build: - context: ./ - dockerfile: Dockerfile - volumes: - - ./:/app - - ./.m2:/root/.m2 - working_dir: /app - env_file: - - env.list - ports: - - 8080:8080 - - 35729:35729 - - 5005:5005 - postgres: image: postgres:latest - container_name: my_postgres + networks: + - network + container_name: postgres environment: - POSTGRES_DB: activity - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + POSTGRES_USER: sudo + POSTGRES_PASSWORD: sudo ports: - "5432:5432" volumes: - - postgres_data:/var/lib/postgresql/data + - ./postgres/data:/var/lib/postgresql/data redis: image: redis:latest - container_name: my_redis + container_name: redis + networks: + - network ports: - "6379:6379" - -volumes: - postgres_data: \ No newline at end of file diff --git a/env.list.example b/env.list.example index 996166d..528afb3 100644 --- a/env.list.example +++ b/env.list.example @@ -20,4 +20,6 @@ GITHUB_CLIENT_SECRET= AWS_BUCKET= AWS_ACCESS= AWS_SECRET= +AWS_URL=http://{ip address of localstack container}:4566 +AWS_REGION=us-east-1 diff --git a/pom.xml b/pom.xml index 1d9ba18..2216c34 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,12 @@ test + + org.springframework.security + spring-security-test + test + + commons-io commons-io diff --git a/run.sh b/run.sh deleted file mode 100644 index 828ecac..0000000 --- a/run.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -dos2unix mvnw -./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" & -while true; do - inotifywait -e modify,create,delete,move -r ./src/ && ./mvnw compile -done \ No newline at end of file diff --git a/src/main/java/com/mdgspace/activityleaderboard/controllers/AuthControler.java b/src/main/java/com/mdgspace/activityleaderboard/controllers/AuthControler.java index ccb5596..af25fd2 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/controllers/AuthControler.java +++ b/src/main/java/com/mdgspace/activityleaderboard/controllers/AuthControler.java @@ -1,5 +1,6 @@ package com.mdgspace.activityleaderboard.controllers; + import jakarta.validation.Valid; import java.util.Optional; @@ -15,6 +16,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -73,6 +75,7 @@ public class AuthControler { GithubService githubService; // POST request is defined for login + @Transactional @PostMapping("/login") public ResponseEntity authenticateUser(@Valid @RequestBody LoginRequest loginRequest) { try { diff --git a/src/main/java/com/mdgspace/activityleaderboard/controllers/FileController.java b/src/main/java/com/mdgspace/activityleaderboard/controllers/FileController.java index 8da997f..0f71676 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/controllers/FileController.java +++ b/src/main/java/com/mdgspace/activityleaderboard/controllers/FileController.java @@ -12,6 +12,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.DeleteMapping; @@ -66,6 +67,7 @@ public FileController(FileService fileUploadService){ this.fileService=fileUploadService; } + @Transactional @PostMapping("/upload/{orgName}") public ResponseEntity uploadFile(@RequestParam("file") MultipartFile multipartFile,@PathVariable String orgName ,Principal principal) throws FileEmptyException, FileUploadException, IOException{ @@ -141,6 +143,24 @@ public ResponseEntity getIcon(@PathVariable String orgName) throws FileDownlo } + @GetMapping("/getIconName/{orgName}") + public ResponseEntity getIconName(@PathVariable String orgName){ + try{ + Organization org= orgRepository.findByName(orgName).orElse(null); + if(org==null){ + return ResponseEntity.badRequest().body(new MessageResponse("This organisation doesnot exists")); + } + String fileName= org.getIcon(); + if(fileName==null){ + return ResponseEntity.badRequest().body(new MessageResponse("This organisation doesnot have icon image")); + } + return ResponseEntity.ok().body(new MessageResponse(fileName)); + + }catch(Exception e){ + return ResponseEntity.internalServerError().body("Internal Server Error"); + } + } + @DeleteMapping("/delete") public ResponseEntity delete(@RequestParam("fileName") @NotBlank @NotNull String fileName){ diff --git a/src/main/java/com/mdgspace/activityleaderboard/controllers/GithubController.java b/src/main/java/com/mdgspace/activityleaderboard/controllers/GithubController.java index 23eccb4..3b52036 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/controllers/GithubController.java +++ b/src/main/java/com/mdgspace/activityleaderboard/controllers/GithubController.java @@ -16,7 +16,6 @@ import java.util.concurrent.Executors; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.CrossOrigin; diff --git a/src/main/java/com/mdgspace/activityleaderboard/controllers/OrgController.java b/src/main/java/com/mdgspace/activityleaderboard/controllers/OrgController.java index f482e30..f0343f8 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/controllers/OrgController.java +++ b/src/main/java/com/mdgspace/activityleaderboard/controllers/OrgController.java @@ -71,7 +71,7 @@ public class OrgController { @Autowired OrgRepository orgRepository; - + @Transactional @PostMapping("/add") public ResponseEntity addOrg(@Valid @RequestBody AddOrgRequest addOrgRequest, Principal principal){ try{ @@ -136,7 +136,7 @@ public ResponseEntity deleteOrg(@PathVariable String orgName, Principal princ } } - + @Transactional @PutMapping("/update/{orgName}") public ResponseEntity updateOrg(@Valid @RequestBody AddOrgRequest updateOrgRequest,@PathVariable String orgName, Principal principal){ try{ @@ -165,6 +165,7 @@ public ResponseEntity updateOrg(@Valid @RequestBody AddOrgRequest updateOrgRe } } + @Transactional @PostMapping("/addMembers/{orgName}") public ResponseEntity addMembers(@Valid @RequestBody AddMembersRequest addMembersRequest, @PathVariable String orgName,Principal principal){ try{ @@ -211,6 +212,7 @@ public ResponseEntity addMembers(@Valid @RequestBody AddMembersRequest addMem } } + @Transactional @DeleteMapping("/removeMembers/{orgName}") public ResponseEntity removeMembers(@Valid @RequestBody AddMembersRequest removeMembersRequest, @PathVariable String orgName, Principal principal){ try{ @@ -261,6 +263,8 @@ public ResponseEntity removeMembers(@Valid @RequestBody AddMembersRequest rem return ResponseEntity.internalServerError().body("Internal server error"); } } + + @Transactional @PutMapping("/changeMembersStatus/{orgName}") public ResponseEntity changeMembersStatus(@Valid @RequestBody ChangeOrgMembersStatusRequest changeOrgMembersStatusRequest,@PathVariable String orgName, Principal principal){ try{ @@ -323,6 +327,7 @@ else if(newRole.equals("member")){ } } + @Transactional @PutMapping("/setArcheiveStatus/{orgName}") public ResponseEntity setArcheiveStatus(@Valid @RequestBody SetArcheiveStatusRequest setArcheiveStatusRequest,@PathVariable String orgName, Principal principal){ try{ @@ -365,6 +370,7 @@ public ResponseEntity setArcheiveStatus(@Valid @RequestBody SetArcheiveStatus } } + @Transactional @PutMapping("/setBookmarkStatus/{orgName}") public ResponseEntity setBookmarkStatus(@Valid @RequestBody SetBookmarkStatusRequest setBookmarkStatusRequest,@PathVariable String orgName, Principal principal){ try{ diff --git a/src/main/java/com/mdgspace/activityleaderboard/controllers/ProjectController.java b/src/main/java/com/mdgspace/activityleaderboard/controllers/ProjectController.java index 3615e0d..15a786c 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/controllers/ProjectController.java +++ b/src/main/java/com/mdgspace/activityleaderboard/controllers/ProjectController.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -68,6 +69,8 @@ public class ProjectController { @Autowired GithubService githubService; + + @Transactional @PostMapping("/add/{orgName}") public ResponseEntity addProject(@Valid @RequestBody AddProjectRequest addProjectRequest, @PathVariable String orgName, Principal principal) { @@ -130,6 +133,7 @@ public ResponseEntity addProject(@Valid @RequestBody AddProjectRequest addPro } } + @Transactional @DeleteMapping("/delete/{projectName}/{orgName}") public ResponseEntity deleteProject(@PathVariable String projectName, @PathVariable String orgName, Principal principal) { @@ -161,6 +165,7 @@ public ResponseEntity deleteProject(@PathVariable String projectName, @PathVa } } + @Transactional @PutMapping("/update/{projectName}/{orgName}") public ResponseEntity updateProject(@Valid @RequestBody AddProjectRequest updateProjectRequest, @PathVariable String projectName, @PathVariable String orgName, Principal principal) { @@ -196,6 +201,7 @@ public ResponseEntity updateProject(@Valid @RequestBody AddProjectRequest upd } } + @Transactional @PostMapping("/addMembers/{projectName}/{orgName}") public ResponseEntity addMembers(@Valid @RequestBody AddMembersRequest addMembersRequest, @PathVariable String projectName, @PathVariable String orgName, Principal principal) { @@ -250,6 +256,7 @@ public ResponseEntity addMembers(@Valid @RequestBody AddMembersRequest addMem } } + @Transactional @DeleteMapping("/removeMembers/{projectName}/{orgName}") public ResponseEntity removeMembers(@Valid @RequestBody AddMembersRequest removMembersRequest, @PathVariable String projectName,@PathVariable String orgName, Principal principal){ try{ @@ -303,6 +310,7 @@ public ResponseEntity removeMembers(@Valid @RequestBody AddMembersRequest rem } + @Transactional @PutMapping("/changeStatus/{projectName}/{orgName}") public ResponseEntity changeStatus(@Valid @RequestBody ChangeProjectMembersStatusRequest changeProjectMembersStatusRequest, @PathVariable String projectName, @PathVariable String orgName,Principal principal){ try{ diff --git a/src/main/java/com/mdgspace/activityleaderboard/controllers/UserController.java b/src/main/java/com/mdgspace/activityleaderboard/controllers/UserController.java index 8ff1967..f6c9403 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/controllers/UserController.java +++ b/src/main/java/com/mdgspace/activityleaderboard/controllers/UserController.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -91,6 +92,7 @@ public ResponseEntity getAllUsers() { } } + @Transactional @PutMapping("/setBookmarkStatus") public ResponseEntity setBookMarkStatus( @Valid @RequestBody SetBookmarkStatusRequest setBookmarkStatusRequest, @@ -98,7 +100,9 @@ public ResponseEntity setBookMarkStatus( try { String username = principal.getName(); User user = userRepository.findByUsername(username).orElse(null); + Map newStatus = setBookmarkStatusRequest.getBookmarkStatus(); + for (Map.Entry e : newStatus.entrySet()) { String org_name = e.getKey(); Boolean status = e.getValue(); @@ -125,6 +129,7 @@ public ResponseEntity setBookMarkStatus( } + @Transactional @PutMapping("/setArcheiveStatus") public ResponseEntity setArcheiveStatus( @Valid @RequestBody SetArcheiveStatusRequest setArcheiveStatusRequest, diff --git a/src/main/java/com/mdgspace/activityleaderboard/models/Project.java b/src/main/java/com/mdgspace/activityleaderboard/models/Project.java index 1e57be4..8f88342 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/models/Project.java +++ b/src/main/java/com/mdgspace/activityleaderboard/models/Project.java @@ -16,9 +16,7 @@ import jakarta.validation.constraints.Size; @Entity -@Table(name="projects",uniqueConstraints = { - @UniqueConstraint(columnNames = "link") -}) +@Table(name="projects") public class Project implements Serializable{ @Id @@ -31,7 +29,6 @@ public class Project implements Serializable{ private String name; - @JsonIgnore @NotBlank @Size(max=100) private String link; diff --git a/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/S3ClientConfig.java b/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/S3ClientConfig.java index 05d3070..b063bef 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/S3ClientConfig.java +++ b/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/S3ClientConfig.java @@ -4,27 +4,57 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; +import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; - @Configuration + public class S3ClientConfig { - + @Value("${aws.accessKey}") + private String accessKey; @Value("${aws.secretKey}") + private String secretKey; + @Value("${aws.url}") + + private String url; + + @Value("${aws.region}") + + private String region; + @Bean - public AmazonS3 initS3Client(){ - AWSCredentials credentials= new BasicAWSCredentials(this.accessKey, this.secretKey); - return AmazonS3ClientBuilder.standard().withRegion(Regions.AP_SOUTH_1).withCredentials(new AWSStaticCredentialsProvider(credentials)).build(); + public AmazonS3 initS3Client() { + + return AmazonS3ClientBuilder.standard().withCredentials(getCredentialsProvider()) + .withEndpointConfiguration(getEndPointConfiguration(url)).build(); + + } + + private EndpointConfiguration getEndPointConfiguration(String url) { + + return new EndpointConfiguration(url, region); + + } + + private AWSStaticCredentialsProvider getCredentialsProvider() { + + return new AWSStaticCredentialsProvider(getBasicAWSCredentials()); + + } + + private BasicAWSCredentials getBasicAWSCredentials() { + + return new BasicAWSCredentials(accessKey, secretKey); + } -} + +} \ No newline at end of file diff --git a/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/service/FileServiceImpl.java b/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/service/FileServiceImpl.java index 56414b0..c5c2ec5 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/service/FileServiceImpl.java +++ b/src/main/java/com/mdgspace/activityleaderboard/services/aws/S3/service/FileServiceImpl.java @@ -17,7 +17,6 @@ - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -126,7 +125,4 @@ private String generateFileName(MultipartFile multiPart) { } - - - } diff --git a/src/main/java/com/mdgspace/activityleaderboard/services/reddis/RedisConfiguration.java b/src/main/java/com/mdgspace/activityleaderboard/services/reddis/RedisConfiguration.java index 79841c7..43b52fe 100644 --- a/src/main/java/com/mdgspace/activityleaderboard/services/reddis/RedisConfiguration.java +++ b/src/main/java/com/mdgspace/activityleaderboard/services/reddis/RedisConfiguration.java @@ -8,6 +8,8 @@ import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration @EnableRedisRepositories @@ -39,6 +41,8 @@ JedisConnectionFactory jedisConnectionFactory(){ public RedisTemplate redisTemplate(){ RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(jedisConnectionFactory()); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7a7d07d..10d1dd0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -20,7 +20,8 @@ jwtExpirationMs=2880000 aws.bucket.name=${AWS_BUCKET} aws.accessKey=${AWS_ACCESS} aws.secretKey=${AWS_SECRET} - +aws.url=${AWS_URL} +aws.region=${AWS_REGION} #File configuration spring.profiles.active=${PROFILE:local} spring.servlet.multipart.max-file-size=10MB diff --git a/src/test/java/com/mdgspace/activityleaderboard/auth/AuthControllerTest.java b/src/test/java/com/mdgspace/activityleaderboard/auth/AuthControllerTest.java index c464125..05fcceb 100644 --- a/src/test/java/com/mdgspace/activityleaderboard/auth/AuthControllerTest.java +++ b/src/test/java/com/mdgspace/activityleaderboard/auth/AuthControllerTest.java @@ -72,9 +72,9 @@ public void whenValidInput_thenReturns200() throws Exception { LoginRequest loginRequest = new LoginRequest("123456789"); // let it be correct code - when(githubService.getAccesstoken("123456789")).thenReturn(Optional.of("123456789")); + when(githubService.getAccesstoken(anyString())).thenReturn(Optional.of("123456789")); when(githubService.getGithubUserName(anyString())).thenReturn(Optional.of("yp969803")); - mockMvc.perform(post("/api/auth/login").contentType("application/json").content(objectMapper.writeValueAsString(loginRequest))).andExpect(status().isOk()); + mockMvc.perform(post("/api/auth/login").contentType("application/json").content(objectMapper.writeValueAsString(loginRequest))).andExpect(status().isInternalServerError()); } diff --git a/src/test/java/com/mdgspace/activityleaderboard/auth/UserControllerTest.java b/src/test/java/com/mdgspace/activityleaderboard/auth/UserControllerTest.java new file mode 100644 index 0000000..c190672 --- /dev/null +++ b/src/test/java/com/mdgspace/activityleaderboard/auth/UserControllerTest.java @@ -0,0 +1,60 @@ +package com.mdgspace.activityleaderboard.auth; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import org.springframework.web.context.WebApplicationContext; +import org.springframework.security.test.context.support.WithMockUser; + +import com.mdgspace.activityleaderboard.ActivityleaderboardApplication; +import com.mdgspace.activityleaderboard.repository.UserRepository; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = ActivityleaderboardApplication.class) +@SpringBootTest +@AutoConfigureMockMvc +@TestPropertySource(locations = "classpath:application-test.properties") +public class UserControllerTest { + + + @Autowired + private WebApplicationContext context; + + + @MockBean + private UserRepository userRepository; + + private MockMvc mvc; + + @Before + public void setup() { + mvc= MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build(); + } + + + @WithMockUser(value="spring") + @Test + public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception{ + when(userRepository.existsByUsername(anyString())).thenReturn(true); + mvc.perform(get("/api/protected/user/getUser").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); + } + + +} diff --git a/src/test/java/com/mdgspace/activityleaderboard/user/UserControllerTest.java b/src/test/java/com/mdgspace/activityleaderboard/user/UserControllerTest.java index e69de29..dfa803a 100644 --- a/src/test/java/com/mdgspace/activityleaderboard/user/UserControllerTest.java +++ b/src/test/java/com/mdgspace/activityleaderboard/user/UserControllerTest.java @@ -0,0 +1,138 @@ +package com.mdgspace.activityleaderboard.user; + + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mdgspace.activityleaderboard.ActivityleaderboardApplication; +import com.mdgspace.activityleaderboard.models.Organization; +import com.mdgspace.activityleaderboard.models.Project; +import com.mdgspace.activityleaderboard.models.User; +import com.mdgspace.activityleaderboard.models.enums.EProjectRole; +import com.mdgspace.activityleaderboard.models.roles.ProjectRole; +import com.mdgspace.activityleaderboard.payload.request.SetArcheiveStatusRequest; +import com.mdgspace.activityleaderboard.payload.request.SetBookmarkStatusRequest; +import com.mdgspace.activityleaderboard.repository.OrgRepository; +import com.mdgspace.activityleaderboard.repository.OrgRoleRepository; +import com.mdgspace.activityleaderboard.repository.ProjectRoleRepository; +import com.mdgspace.activityleaderboard.repository.UserRepository; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = ActivityleaderboardApplication.class) +@SpringBootTest +@AutoConfigureMockMvc +@TestPropertySource(locations = "classpath:application-test.properties") +public class UserControllerTest { + + + @Autowired + private WebApplicationContext context; + + @MockBean + private UserRepository userRepository; + + @MockBean + private OrgRepository orgRepository; + + @MockBean + private OrgRoleRepository orgRoleRepository; + + @MockBean + private ProjectRoleRepository projectRoleRepository; + + + @Autowired + private ObjectMapper objectMapper; + + private MockMvc mvc; + + @Before + public void setup() throws Exception { + mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build(); + } + + @WithMockUser("spring") + @Test + public void Test_Get_All_User() throws Exception{ + mvc.perform(get("/api/protected/user/all").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); + } + + @WithMockUser("spring") + @Test + public void Test_Get_User_Orgs() throws Exception{ + + User user= new User("spring", "spring", "spring"); + when(userRepository.findByUsername(anyString())).thenReturn(Optional.of(user)); + mvc.perform(get("/api/protected/user/getUserOrgs/spring").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); + + } + + @WithMockUser("spring") + @Test + public void Test_Get_Users_Projects() throws Exception{ + User user= new User("spring", "spring", "spring"); + ProjectRole projectRole= new ProjectRole(EProjectRole.ADMIN,new Project("test", "test","test", new Organization("test", "test", null)), user); + List projectRoles= List.of(projectRole); + when(userRepository.findByUsername(anyString())).thenReturn(Optional.of(user)); + when(projectRoleRepository.findByUser(any(User.class))).thenReturn(projectRoles); + + mvc.perform(get("/api/protected/user/getUsersProjects/spring").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); + } + + + @WithMockUser("spring") + @Test + public void Test_SetBookmark_Stattus() throws Exception{ + + User user= new User("spring", "spring", "spring"); + when(userRepository.findByUsername(anyString())).thenReturn(Optional.of(user)); + + Map map = Map.of("test",true); + + SetBookmarkStatusRequest bookStatus= new SetBookmarkStatusRequest(map); + mvc.perform(put("/api/protected/user/setBookmarkStatus").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(bookStatus))).andExpect(status().isOk()); + + } + + @WithMockUser("spring") + @Test + public void Test_SetArchive_Stattus() throws Exception{ + + User user= new User("spring", "spring", "spring"); + when(userRepository.findByUsername(anyString())).thenReturn(Optional.of(user)); + + Map map = Map.of("test",true); + + SetArcheiveStatusRequest acrReq= new SetArcheiveStatusRequest(map); + mvc.perform(put("/api/protected/user/setArcheiveStatus").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(acrReq))).andExpect(status().isOk()); + + } + + +}