Skip to content

Commit

Permalink
Merge pull request #10 from ADPRO-C11/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
asteriskzie authored May 18, 2024
2 parents 55bb53d + cc9c970 commit 95a1320
Show file tree
Hide file tree
Showing 23 changed files with 388 additions and 373 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,24 @@ jobs:
./gradlew check --info --stacktrace
./gradlew test
./gradlew jacocoTestReport
env:
PRODUCTION: test
# (Optional) Add steps for generating coverage report and other post-test tasks

publish:
name: Publish Docker Image
runs-on: ubuntu-latest
needs: test
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: snackscription_review
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Checkout Repository
uses: actions/checkout@v4
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ jobs:
distribution: "temurin"
java-version: "21"
cache: "gradle"

- name: Make gradlew executable
run: chmod +x ./gradlew

- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
Expand All @@ -85,4 +87,6 @@ jobs:
./gradlew check --info --stacktrace
./gradlew test
./gradlew jacocoTestReport
# (Optional) Add steps for generating coverage report and other post-test tasks
env:
PRODUCTION: test
# (Optional) Add steps for generating coverage report and other post-test tasks
19 changes: 19 additions & 0 deletions .monitoring/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: '3.7'

services:
prometheus:
image: prom/prometheus:v2.44.0
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml

grafana:
image: grafana/grafana:9.5.2
container_name: grafana
ports:
- "3000:3000"
restart: unless-stopped
volumes:
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
7 changes: 7 additions & 0 deletions .monitoring/grafana/provisioning/datasources/datasources.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
8 changes: 8 additions & 0 deletions .monitoring/prometheus/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
scrape_configs:
- job_name: 'MyAppMetrics'
metrics_path: '/actuator/prometheus'
scrape_interval: 3s
static_configs:
- targets: ['host.docker.internal:8080']
labels:
application: 'Snackscription Review'
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ ENV JDBC_DATABASE_URL ${JDBC_DATABASE_URL}
ENV JDBC_DATABASE_USERNAME ${JDBC_DATABASE_USERNAME}

WORKDIR /app
COPY ./review-0.0.1-SNAPSHOT.jar /app
RUN ls -la
COPY build/libs/review-0.0.1-SNAPSHOT.jar /app/review-0.0.1-SNAPSHOT.jar
EXPOSE 8080
CMD ["java","-jar","review-0.0.1-SNAPSHOT.jar"]
5 changes: 5 additions & 0 deletions application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
management:
endpoints:
web:
exposure:
include: [ "prometheus" ]
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
runtimeOnly("io.micrometer:micrometer-registry-prometheus")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
Expand Down
22 changes: 22 additions & 0 deletions deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: snackscription-review-deployment
spec:
replicas: 3
selector:
matchLabels:
app: snackscription-review
template:
metadata:
labels:
app: snackscription-review
spec:
containers:
- name: snackscription-review
image: asteriskzie/snackscription-review:latest
ports:
- containerPort: 8080
env:
- name: PRODUCTION
value: prod
2 changes: 1 addition & 1 deletion gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# * For example: A author cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.

set -- \
Expand Down
11 changes: 11 additions & 0 deletions service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: snackscription-review-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: snackscription-review
14 changes: 14 additions & 0 deletions src/main/java/snackscription/review/ReviewAppConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package snackscription.review;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ReviewAppConfig {
@Bean
public MeterRegistry getMeterRegistry() {
return new CompositeMeterRegistry();
}
}
103 changes: 39 additions & 64 deletions src/main/java/snackscription/review/controller/ReviewController.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,18 @@
package snackscription.review.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.catalina.connector.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import snackscription.review.model.Review;
import snackscription.review.repository.ReviewRepository;
import snackscription.review.service.ReviewService;

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PutMapping;




@RestController
@RequestMapping("/")
@RequestMapping("/reviews")
public class ReviewController {


private ReviewService reviewService;

public ReviewController(ReviewService reviewService) {
Expand All @@ -43,101 +24,95 @@ public ResponseEntity<String> reviewPage() {
return ResponseEntity.ok().body("Welcome to the review service!");
}

@PostMapping("/api/subscription-boxes/{subscriptionBoxId}")
public ResponseEntity<Review> createSubscriptionBoxReview(@RequestBody Map<String,String> body, @PathVariable String subscriptionBoxId) {

@PostMapping("/subscription-boxes/{subsbox}")
public ResponseEntity<Review> createSubsboxReview(@RequestBody Map<String,String> body, @PathVariable String subsbox) {
try {
String userId = body.get("userId");
String author = body.get("author");
int rating = Integer.parseInt(body.get("rating"));
String content = body.get("content");

Review review = reviewService.createReview(rating, content, subscriptionBoxId, userId);
Review review = reviewService.createReview(rating, content, subsbox, author);
return new ResponseEntity<>(review, HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@GetMapping("/api/subscription-boxes/{subscriptionBoxId}")
public ResponseEntity<List<Review>> getAllPublicSubscriptionBoxReview(@PathVariable String subscriptionBoxId) {
@GetMapping("/subscription-boxes/{subsbox}/public")
public ResponseEntity<List<Review>> getPublicSubsboxReview(@PathVariable String subsbox) {
try {
List<Review> reviews = reviewService.getAllSubscriptionBoxReview(subscriptionBoxId, "APPROVED");
List<Review> reviews = reviewService.getSubsboxReview(subsbox, "APPROVED");
return new ResponseEntity<>(reviews, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@GetMapping("/api/subscription-boxes/{subscriptionBoxId}/users/self")
public ResponseEntity<Review> getSelfSubscriptionBoxReview(@RequestBody Map<String,String> body, @PathVariable String subscriptionBoxId) {
@GetMapping("/subscription-boxes/{subsbox}/users/{user}")
public ResponseEntity<Review> getSelfSubsboxReview(@RequestBody Map<String,String> body, @PathVariable String subsbox, @PathVariable String user) {
try {
String userId = body.get("userId");
Review review = reviewService.getReview(subscriptionBoxId, userId);
String sender = body.get("author"); // TODO: nanti pakai JWT token untuk ambil sendernya
if (!authenticate(sender, user)) {
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
Review review = reviewService.getReview(subsbox, user);
return new ResponseEntity<>(review, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@PutMapping("/api/subscription-boxes/{subscriptionBoxId}/users/self")
public ResponseEntity<Review> editSelfSubscriptionBoxId(@RequestBody Map<String,String> body, @PathVariable String subscriptionBoxId) {
@PutMapping("/subscription-boxes/{subsbox}/users/{user}")
public ResponseEntity<Review> editReview(@RequestBody Map<String,String> body, @PathVariable String subsbox, @PathVariable String user) {
try {
String userId = body.get("userId");
String sender = body.get("author"); // TODO: nanti pakai JWT token untuk ambil sendernya
if (!authenticate(sender, user)) {
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}

int rating = Integer.parseInt(body.get("rating"));
String content = body.get("content");

Review review = reviewService.editReview(rating, content, subscriptionBoxId, userId);
Review review = reviewService.editReview(rating, content, subsbox, user);
return new ResponseEntity<>(review, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@DeleteMapping("/api/subscription-boxes/{subscriptionBoxId}/users/self")
public ResponseEntity<Review> deleteSelfSubscriptionBoxReview(@RequestBody Map<String,String> body, @PathVariable String subscriptionBoxId) {
try {
String userId = body.get("userId");
reviewService.deleteReview(subscriptionBoxId, userId);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
private boolean authenticate(String sender, String user) {
return true;
}

@DeleteMapping("/api/subscription-boxes/{subscriptionBoxId}/users/{userId}")
public ResponseEntity<Review> deleteSubscriptionBoxReview(@PathVariable String subscriptionBoxId, @PathVariable String userId) {
@DeleteMapping("/subscription-boxes/{subsbox}/users/{user}")
public ResponseEntity<Review> deleteReview(@PathVariable String subsbox, @PathVariable String user) {
try {
reviewService.deleteReview(subscriptionBoxId, userId);
reviewService.deleteReview(subsbox, user);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@GetMapping("/api/reviews/{subsboxId}")
public List<Review> getBySubscriptionBoxId(@PathVariable String subsboxId) throws Exception {
return reviewService.getAllSubscriptionBoxReview(subsboxId, null);
}

@GetMapping("/api/reviews/{reviewId}")
public Review getById(@PathVariable String reviewId) throws Exception {
return reviewService.findById(reviewId);
@GetMapping("/subscription-boxes/{subsbox}")
public List<Review> getSubsboxReview(@PathVariable String subsbox) throws Exception {
return reviewService.getSubsboxReview(subsbox, null);
}

@PutMapping("/api/reviews/{reviewId}/approve")
public ResponseEntity<Review> approveReview(@PathVariable String reviewId) {
@PutMapping("/subscription-boxes/{subsbox}/users/{user}/approve")
public ResponseEntity<Review> approveReview(@PathVariable String subsbox, @PathVariable String user) {
try {
Review review = reviewService.approveReview(reviewId);
Review review = reviewService.approveReview(subsbox, user);
return new ResponseEntity<>(review, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}

@PutMapping("/api/reviews/{reviewId}/reject")
public ResponseEntity<Review> rejectReview(@PathVariable String reviewId) {
@PutMapping("/subscription-boxes/{subsbox}/users/{user}/reject")
public ResponseEntity<Review> rejectReview(@PathVariable String subsbox, @PathVariable String user) {
try {
Review review = reviewService.rejectReview(reviewId);
Review review = reviewService.rejectReview(subsbox, user);
return new ResponseEntity<>(review, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
Expand Down
Loading

0 comments on commit 95a1320

Please sign in to comment.