Compare commits

...

9 Commits

Author SHA1 Message Date
TakahashiNguyen e77edb0e74 fix: update ci script (#18)
Release package / release (push) Successful in 35m0s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #18
2026-04-08 13:28:35 +00:00
TakahashiNguyen be8bdde6cf ci: better script (#17)
Release package / release (push) Failing after 15s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #17
2026-04-08 08:48:56 +00:00
TakahashiNguyen cb9096dd1b ci: update dependencies (#16)
Release package / release (push) Failing after 49s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #16
2026-04-08 08:35:50 +00:00
TakahashiNguyen 837f5f595a feat: init k8s and customer service (#15)
Release package / release (push) Failing after 2m10s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #15
2026-04-08 08:24:00 +00:00
gitea-actions dd3c09865f chore: release [ci skip] 2026-04-01 08:29:21 +00:00
TranHuuDanh 5a7b70145c feature/danh-dev-new-branch-yeu-cau-viet-anh (#14)
Release package / release (push) Successful in 10m45s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Co-authored-by: TranHuuDanh <tranhuudanh@demonkernel.io.vn>
Co-authored-by: TakahashiNguyen <takahashi.ng@icloud.com>
Reviewed-on: #14
Reviewed-by: TakahashiNguyen <takahashi.ng@icloud.com>
Co-authored-by: TranHuuDanh <tranhuudanh@noreply.localhost>
Co-committed-by: TranHuuDanh <tranhuudanh@noreply.localhost>
2026-04-01 08:20:41 +00:00
TakahashiNguyen bcbda39ed4 feat(k8s): init (#13)
Release package / release (push) Failing after 16m12s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #13
2026-03-31 13:15:39 +00:00
gitea-actions 554e8767d8 chore: release [ci skip] 2026-03-31 10:10:39 +00:00
TakahashiNguyen 6938b764fc chore: add test (#11)
Release package / release (push) Successful in 3m37s
Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Co-authored-by: TranHuuDanh <tranhuudanh@demonkernel.io.vn>
Reviewed-on: #11
2026-03-31 10:07:49 +00:00
38 changed files with 1097 additions and 178 deletions
+34 -8
View File
@@ -1,18 +1,44 @@
FROM alpine:3.22
FROM ubuntu:26.04
RUN apk update && apk add --no-cache \
# Tránh các câu hỏi tương tác trong quá trình cài đặt
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ca-certificates && apt-get clean
RUN sed -i 's|http://archive.ubuntu.com|https://apt.demonkernel.io.vn|g' /etc/apt/sources.list.d/ubuntu.sources && \
sed -i 's|http://security.ubuntu.com|https://apt.demonkernel.io.vn|g' /etc/apt/sources.list.d/ubuntu.sources
# 1. Cài đặt các công cụ cơ bản
RUN apt-get update --fix-missing && apt-get install --no-install-recommends --no-install-suggests -y \
curl \
bash \
openjdk21-jdk \
maven \
build-essential \
docker-buildx \
git \
ca-certificates \
pnpm
docker.io \
maven \
libz-dev
# git trust all directories
# 5. Cấu hình Git
RUN git config --global --add safe.directory '*'
# Install quarkus
# 2. Cài đặt Node.js & PNPM (thay thế cho apk pnpm)
RUN curl -fsSL https://get.pnpm.io/install.sh | bash -
# 3. Cài đặt Kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& install -m 0755 kubectl /usr/local/bin/kubectl
# 4. Cài đặt Mandrel 25
# Lưu ý: Dùng bản linux-amd64 (glibc) tiêu chuẩn cho Ubuntu
ENV JAVA_HOME=/usr/lib/jvm/mandrel
ENV GRAALVM_HOME=/usr/lib/jvm/mandrel
ENV PATH="${JAVA_HOME}/bin:${PATH}"
RUN mkdir -p ${JAVA_HOME} && \
curl -L https://github.com/graalvm/mandrel/releases/download/mandrel-25.0.2.0-Final/mandrel-java25-linux-amd64-25.0.2.0-Final.tar.gz | tar -xz -C ${JAVA_HOME} --strip-components=1
# 6. Cài đặt JBang & Quarkus CLI
ENV JBANG_DIR="/root/.jbang"
ENV PATH="${JBANG_DIR}/bin:${PATH}"
+6 -3
View File
@@ -3,7 +3,8 @@
{
"dockerComposeFile": "docker-compose.main.yaml",
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind",
"source=${localEnv:USERPROFILE}/.kube,target=/root/.kube,type=bind"
],
"remoteUser": "root",
"service": "devcontainer",
@@ -21,6 +22,8 @@
}
},
"containerEnv": {
"TESTCONTAINERS_RYUK_DISABLED": "true"
}
"TESTCONTAINERS_RYUK_DISABLED": "true",
"QUARKUS_DEBUG_HOST": "0.0.0.0"
},
"forwardPorts": [5005, 8080]
}
-2
View File
@@ -1,6 +1,4 @@
include:
- ./docker-compose.kafka.yaml
- ./docker-compose.postgres.yaml
- ./docker-compose.redis.yaml
services:
+8 -36
View File
@@ -11,14 +11,9 @@ jobs:
permissions:
contents: write
steps:
- name: Calculate and Export Target IP
run: |
# 1. Lấy IP hiện tại và tính toán IP đích (đổi octet cuối thành .1)
RUNNER_IP=$(hostname -I | awk '{print $1}')
CALCULATED_IP=$(echo $RUNNER_IP | cut -d'.' -f1-3).1
# 2. Đưa vào biến môi trường toàn cục của Job
echo "TARGET_IP=${CALCULATED_IP}" >> $GITHUB_ENV
- uses: gerlero/apt-install@v1
with:
packages: docker.io
- name: Setup SSH Key
run: |
@@ -27,7 +22,7 @@ jobs:
echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -p 222 -t ed25519 $TARGET_IP >> ~/.ssh/known_hosts
ssh-keyscan -t ed25519 vps.demonkernel.io.vn >> ~/.ssh/known_hosts
- uses: actions/checkout@v6
with:
@@ -36,8 +31,9 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: "temurin"
distribution: "graalvm"
java-version: "25"
cache: "maven"
- name: Log in to Gitea Container Registry
uses: docker/login-action@v3
@@ -46,35 +42,11 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.ACCESS_TOKEN }}
- uses: actions/setup-node@v6
with:
node-version: latest
- uses: pnpm/action-setup@v3
with:
version: latest
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- uses: actions/cache@v4
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
cache: true
- name: Run Semantic Release
env:
@@ -93,7 +65,7 @@ jobs:
REPO_NAME="${{ gitea.repository }}"
git remote set-url origin ssh://git@$TARGET_IP:222/${REPO_NAME}.git
git remote set-url origin ssh://git@vps.demonkernel.io.vn/${REPO_NAME}.git
git rm -r --cached .
git add .
+15 -8
View File
@@ -5,6 +5,10 @@ on:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build-and-test:
runs-on: ubuntu-latest
@@ -14,22 +18,25 @@ jobs:
with:
fetch-depth: 0
- uses: shogo82148/actions-setup-redis@v1
with:
redis-version: "7.x"
- name: Set up JDK
uses: actions/setup-java@v5
with:
distribution: "temurin"
distribution: "graalvm"
java-version: "25"
cache: "maven"
- name: Cache Maven packages
uses: actions/cache@v4
- uses: gerlero/apt-install@v1
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
packages: build-essential zlib1g-dev docker.io
- name: Build and Test all modules
run: ./mvnw -B clean verify -Dquarkus.container-image.build=false -Dquarkus.container-image.push=false
run: |
./mvnw -B install \
-Dquarkus.container-image.push=false \
- name: Publish Test Report
uses: scacap/action-surefire-report@v1
+1 -1
View File
@@ -1,4 +1,4 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip
distributionSha256Sum=305773a68d6ddfd413df58c82b3f8050e89778e777f3a745c8e5b8cbea4018ef
distributionSha256Sum=
+2 -2
View File
@@ -14,8 +14,8 @@
[
"@semantic-release/exec",
{
"prepareCmd": "./mvnw versions:set -DnewVersion=${nextRelease.version}",
"publishCmd": "if [ \"${branch.name}\" = \"main\" ]; then ./mvnw clean package -Dquarkus.container-image.tag=${nextRelease.version} -DskipTests; fi"
"prepareCmd": "./mvnw versions:set -DnewVersion=${nextRelease.version} && sed -i \"/-service:/ s|:[^:]*$|:${nextRelease.version}|\" k8s.yaml",
"publishCmd": "if [ \"${branch.name}\" = \"main\" ]; then ./mvnw package -Dquarkus.container-image.tag=${nextRelease.version} -DskipTests; fi"
}
],
[
+1 -1
View File
@@ -18,7 +18,7 @@
<properties>
<compiler-plugin.version>3.15.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding
>UTF-8</project.reporting.outputEncoding>
@@ -2,6 +2,7 @@ package com.drinkool.models;
import com.drinkool.entities.BaseEntity;
import com.drinkool.utils.PhoneValidator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.password4j.Password;
import jakarta.persistence.*;
import jakarta.transaction.*;
@@ -20,6 +21,7 @@ public abstract class UserModel extends BaseEntity {
public String phone;
@Column(nullable = false, length = 1024)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
public String hashedPassword;
@Transactional
@@ -1,5 +1,8 @@
package com.drinkool.services;
import com.drinkool.Jwt;
import com.drinkool.Role;
import com.drinkool.Url;
import com.drinkool.dtos.*;
import com.drinkool.entities.CustomerEntity;
import jakarta.inject.Inject;
@@ -7,54 +10,96 @@ import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.*;
@Path("/api")
@Path("")
public class AuthenticationService {
@Inject
OtpService otpService;
@POST
@Path("/signup")
@Path(Url.Signup)
@Transactional
public Response signup(Signup input) {
CustomerEntity newCustomer = new CustomerEntity();
newCustomer.signup(input.name, input.phone, input.password);
return Response.status(Response.Status.CREATED).build();
return Response.status(Response.Status.CREATED)
.header(Jwt.userId, newCustomer.id.toString())
.header(Jwt.role, Role.Customer)
.build();
}
@POST
@Path("/quickSignup")
@Path(Url.QuickSignup)
@Transactional
public Response quickSignup(QuickSignup input) {
CustomerEntity newCustomer = new CustomerEntity();
newCustomer.signup(input.phone);
return Response.status(Response.Status.CREATED).build();
return Response.status(Response.Status.CREATED)
.header(Jwt.userId, newCustomer.id.toString())
.header(Jwt.role, Role.Customer)
.build();
}
@POST
@Path("/login")
@Path(Url.Login)
public Response login(Login input) {
CustomerEntity customer = CustomerEntity.find(
"phone",
input.phone
).firstResult();
if (customer == null) throw new BadRequestException("InvalidPhoneNumber");
if (customer == null) return Response.status(Response.Status.BAD_REQUEST)
.entity("InvalidPhoneNumber")
.build();
if (!customer.login(input.password)) throw new BadRequestException(
"InvalidPassword"
);
if (!customer.login(input.password)) return Response.status(
Response.Status.BAD_REQUEST
)
.entity("InvalidPassword")
.build();
return Response.accepted().build();
return Response.accepted()
.header(Jwt.userId, customer.id.toString())
.header(Jwt.role, Role.Customer)
.build();
}
@POST
@Path("/sms_otp")
@Path(Url.QuickLogin)
public Response quickLogin(QuickLogin input) {
if (!otpService.verifyOtp(input.phone, input.otp)) {
return Response.status(Response.Status.UNAUTHORIZED)
.entity("InvalidOTP")
.build();
}
CustomerEntity customer = CustomerEntity.find(
"phone",
input.phone
).firstResult();
return Response.accepted()
.header(Jwt.userId, customer.id.toString())
.header(Jwt.role, Role.Customer)
.build();
}
@POST
@Path(Url.SmsOtp)
public Response smsOtp(SmsOtp input) {
CustomerEntity customer = CustomerEntity.find(
"phone",
input.phone
).firstResult();
if (customer == null) return Response.status(Response.Status.BAD_REQUEST)
.entity("InvalidPhoneNumber")
.build();
String otp = otpService.generateAndSaveOtp(input.phone);
// Ở đây bạn sẽ gọi Kafka để gửi SMS thực tế
@@ -62,15 +107,4 @@ public class AuthenticationService {
return Response.accepted().build();
}
@POST
@Path("/quicklogin")
public Response quickLogin(QuickLogin input) {
if (otpService.verifyOtp(input.phone, input.otp)) {
return Response.accepted().build();
}
return Response.status(Response.Status.UNAUTHORIZED)
.entity("InvalidOTP")
.build();
}
}
@@ -0,0 +1,24 @@
package com.drinkool.services;
import com.drinkool.Jwt;
import com.drinkool.Url;
import com.drinkool.models.UserModel;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
import java.util.UUID;
@Path("")
public class UserService {
@POST
@Path(Url.Me)
@Transactional
public Response me(@HeaderParam(Jwt.userId) UUID id) {
if (id == null) return Response.status(Response.Status.BAD_REQUEST)
.entity("InvalidUserId")
.build();
return Response.ok(UserModel.find("id", id).firstResult()).build();
}
}
@@ -7,13 +7,13 @@ quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/postgres
quarkus.hibernate-orm.database.generation=update
# Docker
## URL của Gitea Registry (thường là gitea.yourdomain.com)
quarkus.container-image.registry=git.demonkernel.io.vn
quarkus.container-image.group=foodsurf
quarkus.container-image.name=account-service
quarkus.container-image.push=true
quarkus.container-image.build=true
quarkus.container-image.builder=docker
quarkus.container-image.additional-tags=latest
# Redis
quarkus.redis.hosts=redis://localhost:6379
@@ -0,0 +1,56 @@
package com.drinkool.entities;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class CustomerEntityTest {
@Inject
EntityManager entityManager;
@Test
@Transactional
public void testCustomerPersistence() {
// 1. Khởi tạo đúng Entity (CustomerEntity chứ không phải CustomerEntityTest)
CustomerEntity customer = new CustomerEntity();
// Gán đúng biến name, phone và hashedPassword (các trường kế thừa từ UserModel)
customer.name = "Nguyen Van A";
customer.phone = "+84987654321";
customer.hashedPassword = "dummy_hashed_password";
// 2. Lưu vào DB
entityManager.persist(customer);
entityManager.flush();
entityManager.clear();
// 3. Truy vấn lại để kiểm tra (Sửa lại class map của query thành CustomerEntity)
var query = entityManager.createQuery(
"SELECT c FROM CustomerEntity c WHERE c.phone = :phone",
CustomerEntity.class
);
query.setParameter("phone", "+84987654321");
// Nhận kết quả về đúng kiểu CustomerEntity
CustomerEntity savedCustomer = query.getSingleResult();
// 4. Assert (Kiểm chứng)
Assertions.assertNotNull(savedCustomer, "Customer không được null");
Assertions.assertEquals(
"Nguyen Van A",
savedCustomer.name,
"Tên không khớp"
);
Assertions.assertEquals(
"+84987654321",
savedCustomer.phone,
"Số điện thoại không khớp"
);
Assertions.assertNotNull(savedCustomer.id, "ID chưa được sinh ra");
}
}
@@ -2,79 +2,149 @@ package com.drinkool.models;
import static org.junit.jupiter.api.Assertions.*;
import com.drinkool.entities.CustomerEntity;
import io.quarkus.test.TestTransaction;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.BadRequestException;
import java.util.*;
import java.util.Random;
import org.junit.jupiter.api.Test;
@Entity
@Table
@Table(name = "test_users")
class TestUserEntity extends UserModel {}
@QuarkusTest
public class UserModelTest {
// Helper method để tạo số điện thoại ngẫu nhiên hợp lệ
private String generateValidPhone() {
return "+8477" + String.format("%07d", (new Random()).nextInt(10000000));
}
// 1. Test case: Đăng ký thành công (đầy đủ tham số)
@Test
@Transactional
public void testSignupSuccess() {
//dang nhap thanh cong
TestUserEntity user = new TestUserEntity();
String phone =
"+8477" + String.format("%07d", (new Random()).nextInt(10000000));
String phone = generateValidPhone();
String password = "02092006Danh";
user.signup("Tran Huu Danh", phone, password);
assertNotNull(user.id, "ID not null after persist");
assertEquals("Tran Huu Danh", user.name);
assertEquals(phone, user.phone);
// assertNotNull(user.hashedPassword, "password phai hash");
assertNotNull(user.hashedPassword, "Password phải được hash");
TestUserEntity savedUser = TestUserEntity.find(
"phone",
phone
).firstResult();
assertNotNull(savedUser);
assertNotNull(savedUser, "Phải tìm thấy user trong database");
}
// 2. Test case: Đăng ký thất bại do số điện thoại đã tồn tại
// 2. Test case: Đăng ký thành công (chỉ dùng số điện thoại)
@Test
@Transactional
public void testSignupOneParamSuccess() {
TestUserEntity user = new TestUserEntity();
String phone = generateValidPhone();
user.signup(phone);
assertNotNull(user.id, "ID not null after persist");
assertEquals(phone, user.name, "Tên mặc định phải là số điện thoại");
assertEquals(phone, user.phone);
assertNotNull(
user.hashedPassword,
"Password tự động phải được tạo và hash"
);
}
// 3. Test case: Đăng ký thất bại do số điện thoại đã tồn tại
@Test
@Transactional
public void testSignupFailExistedUser() {
TestUserEntity existUser = new TestUserEntity();
String phone =
"+8477" + String.format("%07d", (new Random()).nextInt(10000000));
String phone = generateValidPhone();
String password = "tungtungtungshahua";
// Tạo user đầu tiên
TestUserEntity existUser = new TestUserEntity();
existUser.signup("Nguyen Thanh Quy", phone, password);
CustomerEntity newCustomer = new CustomerEntity();
// Tạo user thứ hai với cùng số điện thoại
TestUserEntity newUser = new TestUserEntity();
BadRequestException exception = assertThrows(
BadRequestException.class,
() -> {
newCustomer.signup("Nguyen Viet Anh", phone, "02092006Anh");
newUser.signup("Nguyen Viet Anh", phone, "02092006Anh");
}
);
assertEquals("ExistedUser", exception.getMessage());
}
// 3. Test case: Đăng ký thất bại do số điện thoại sai định dạng
// 4. Test case: Đăng ký thất bại do số điện thoại sai định dạng
@Test
@TestTransaction
@Transactional
public void testSignupFailInvalidPhoneNumber() {
TestUserEntity customer = new TestUserEntity();
TestUserEntity user = new TestUserEntity();
String invalidPhone = "12345";
BadRequestException exception = assertThrows(
BadRequestException.class,
() -> {
customer.signup("Lam Vi Hoang", invalidPhone, "Pass123");
user.signup("Lam Vi Hoang", invalidPhone, "Pass123");
}
);
assertEquals("InvalidPhoneNumber", exception.getMessage());
}
// 5. Test case: Đăng nhập thành công
@Test
@Transactional
public void testLoginSuccess() {
TestUserEntity user = new TestUserEntity();
String phone = generateValidPhone();
String password = "02092006Danh";
user.signup("Tran Huu Danh", phone, password);
boolean loginResult = user.login(password);
assertTrue(loginResult, "Đăng nhập phải thành công với mật khẩu đúng");
}
// 6. Test case: Đăng nhập thất bại do sai mật khẩu
@Test
@Transactional
public void testLoginFailWrongPassword() {
TestUserEntity user = new TestUserEntity();
String phone = generateValidPhone();
String truePassword = "02092006Danh";
String wrongPassword = "02092006danhh";
user.signup("Tran Huu Danh", phone, truePassword);
boolean loginResult = user.login(wrongPassword);
assertFalse(loginResult, "Đăng nhập phải thất bại với mật khẩu sai");
}
// 7. Test case: Đăng nhập thất bại do hashedPassword bị null
@Test
@Transactional
public void testLoginFailNullHashedPassword() {
TestUserEntity user = new TestUserEntity();
user.hashedPassword = null; // Cố tình set null để test lỗi
boolean loginResult = user.login("anhdomixi");
assertFalse(
loginResult,
"Đăng nhập phải thất bại nếu hashedPassword là null"
);
}
}
@@ -0,0 +1,165 @@
package com.drinkool.services;
import static io.restassured.RestAssured.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.jupiter.api.Assertions.*;
import com.drinkool.Jwt;
import com.drinkool.Role;
import com.drinkool.Url;
import com.drinkool.dtos.*;
import com.drinkool.entities.CustomerEntity;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import java.util.Random;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class AuthenticationServiceTest {
public static Random random = new Random();
public static String generateRandomPhone() {
return "+8477" + String.format("%07d", random.nextInt(10000000));
}
@Test
void testSignup() {
String phone = generateRandomPhone();
Signup input = new Signup();
input.name = "Test User";
input.phone = phone;
input.password = "password123";
given()
.contentType(ContentType.JSON)
.body(input)
.when()
.post(Url.Signup)
.then()
.statusCode(201);
// Kiểm tra database: Phải tìm thấy 1 user với số điện thoại này
assertEquals(1, CustomerEntity.find("phone", phone).count());
}
@Test
void testQuickSignup() {
String phone = generateRandomPhone();
QuickSignup input = new QuickSignup();
input.phone = phone;
given()
.contentType(ContentType.JSON)
.body(input)
.when()
.post(Url.QuickSignup)
.then()
.header(Jwt.userId, notNullValue())
.header(Jwt.role, is(Role.Customer))
.statusCode(201);
assertEquals(1, CustomerEntity.find("phone", phone).count());
}
@Test
void testLoginSuccess() {
// BƯỚC 1: Tạo user trước bằng signup
String phone = generateRandomPhone();
Signup signupData = new Signup();
signupData.name = "Login User";
signupData.phone = phone;
signupData.password = "secure_pass";
given()
.contentType(ContentType.JSON)
.body(signupData)
.post(Url.Signup)
.then()
.statusCode(201);
// BƯỚC 2: Thử đăng nhập
Login loginInput = new Login();
loginInput.phone = phone;
loginInput.password = "secure_pass";
given()
.contentType(ContentType.JSON)
.body(loginInput)
.when()
.post(Url.Login)
.then()
.statusCode(202);
}
@Test
void testLoginFailWrongPassword() {
String phone = generateRandomPhone();
Signup signupData = new Signup();
signupData.name = "Wrong Pass User";
signupData.phone = phone;
signupData.password = "correct_password";
given()
.contentType(ContentType.JSON)
.body(signupData)
.post(Url.Signup)
.then()
.statusCode(201);
Login loginInput = new Login();
loginInput.phone = phone;
loginInput.password = "wrong_password";
given()
.contentType(ContentType.JSON)
.body(loginInput)
.when()
.post(Url.Login)
.then()
.statusCode(400); // BadRequestException
}
@Test
void testSmsOtp() {
String phone = generateRandomPhone();
SmsOtp input = new SmsOtp();
input.phone = phone;
Signup signup = new Signup();
signup.phone = phone;
signup.name = "sms user";
signup.password = "password123";
given()
.contentType(ContentType.JSON)
.body(signup)
.when()
.post(Url.Signup)
.then();
given()
.contentType(ContentType.JSON)
.body(input)
.when()
.post(Url.SmsOtp)
.then()
.statusCode(202);
}
@Test
void testQuickLoginFailInvalidOtp() {
String phone = generateRandomPhone();
QuickLogin input = new QuickLogin();
input.phone = phone;
input.otp = "000000"; // Giả sử mã này luôn sai vì chưa được tạo
given()
.contentType(ContentType.JSON)
.body(input)
.when()
.post(Url.QuickLogin)
.then()
.statusCode(401);
}
}
@@ -0,0 +1,86 @@
package com.drinkool.services;
import static org.junit.jupiter.api.Assertions.*;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import java.util.Random;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class OtpServiceTest {
@Inject
OtpService otpService;
// 1. Test case: Tạo và lưu OTP thành công
@Test
public void testGenerateAndSaveOtp() {
String phone =
"+8477" + String.format("%07d", new Random().nextInt(10000000));
String otp = otpService.generateAndSaveOtp(phone);
assertNotNull(otp, "OTP sinh ra không được null");
assertEquals(6, otp.length(), "OTP phải có độ dài đúng 6 ký tự");
assertTrue(otp.matches("\\d{6}"), "OTP chỉ được chứa các chữ số");
}
// 2. Test case: Xác thực OTP thành công
@Test
public void testVerifyOtpSuccess() {
String phone =
"+8477" + String.format("%07d", new Random().nextInt(10000000));
String generatedOtp = otpService.generateAndSaveOtp(phone);
// Xác thực với OTP vừa tạo ra
boolean verifyResult = otpService.verifyOtp(phone, generatedOtp);
assertTrue(verifyResult, "Xác thực phải thành công với OTP đúng");
}
// 3. Test case: Xác thực thất bại do sai mã OTP
@Test
public void testVerifyOtpFailWrongOtp() {
String phone =
"+8477" + String.format("%07d", new Random().nextInt(10000000));
otpService.generateAndSaveOtp(phone); // Tạo OTP nhưng không dùng
String wrongOtp = "999999"; // Giả sử mã sai
boolean verifyResult = otpService.verifyOtp(phone, wrongOtp);
assertFalse(verifyResult, "Xác thực phải thất bại khi truyền sai mã OTP");
}
// 4. Test case: Xác thực thất bại do OTP không tồn tại (chưa tạo hoặc đã hết hạn)
@Test
public void testVerifyOtpFailNotExists() {
String unverifiedPhone =
"+8499" + String.format("%07d", new Random().nextInt(10000000));
// Cố tình xác thực cho một số điện thoại chưa từng gọi generateAndSaveOtp
boolean verifyResult = otpService.verifyOtp(unverifiedPhone, "123456");
assertFalse(
verifyResult,
"Xác thực phải thất bại với SĐT không có OTP trong Redis"
);
}
// 5. Test case: Đảm bảo OTP chỉ được sử dụng 1 lần (đã bị xóa sau khi verify thành công bằng lệnh getdel)
@Test
public void testVerifyOtpConsumedAfterSuccess() {
String phone =
"+8477" + String.format("%07d", new Random().nextInt(10000000));
String generatedOtp = otpService.generateAndSaveOtp(phone);
// Lần 1: Xác thực thành công
assertTrue(otpService.verifyOtp(phone, generatedOtp));
// Lần 2: Xác thực lại cùng mã đó sẽ thất bại vì key đã bị getdel xóa khỏi Redis
boolean secondVerifyResult = otpService.verifyOtp(phone, generatedOtp);
assertFalse(
secondVerifyResult,
"OTP không được phép tái sử dụng sau khi đã verify thành công"
);
}
}
@@ -0,0 +1,50 @@
package com.drinkool.services;
import static io.restassured.RestAssured.*;
import static org.hamcrest.CoreMatchers.*;
import com.drinkool.Jwt;
import com.drinkool.Url;
import com.drinkool.dtos.QuickSignup;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class UserServiceTest {
@Test
public void testMeEndpointWithHeader() {
String phone = AuthenticationServiceTest.generateRandomPhone();
QuickSignup input = new QuickSignup();
input.phone = phone;
String testUserId = given()
.contentType(ContentType.JSON)
.body(input)
.when()
.post(Url.QuickSignup)
.then()
.extract()
.header(Jwt.userId);
given()
.header(Jwt.userId, testUserId)
.contentType(ContentType.JSON)
.when()
.post(Url.Me)
.then()
.statusCode(200)
.body("id", is(testUserId));
}
@Test
public void testMeEndpointWithoutHeader() {
given()
.when()
.post(Url.Me)
.then()
.statusCode(400);
}
}
@@ -0,0 +1,53 @@
package com.drinkool.utils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class PhoneValidatorTest {
@Test
public void testValidVietnamesePhoneNumbers() {
// Số điện thoại VN hợp lệ (có mã vùng hoặc số 0 ở đầu đều được)
Assertions.assertTrue(
PhoneValidator.isValidInternationalPhone("0987654321")
);
Assertions.assertTrue(
PhoneValidator.isValidInternationalPhone("+84987654321")
);
Assertions.assertTrue(
PhoneValidator.isValidInternationalPhone("84987654321")
);
}
@Test
public void testValidInternationalPhoneNumbers() {
// Số điện thoại quốc tế hợp lệ (Ví dụ: Mỹ +1)
Assertions.assertTrue(
PhoneValidator.isValidInternationalPhone("+14155552671")
);
}
@Test
public void testInvalidPhoneNumbers() {
// Chuỗi không phải số điện thoại
Assertions.assertFalse(
PhoneValidator.isValidInternationalPhone("not-a-phone-number")
);
// Số điện thoại quá ngắn hoặc sai định dạng
Assertions.assertFalse(PhoneValidator.isValidInternationalPhone("123"));
Assertions.assertFalse(
PhoneValidator.isValidInternationalPhone("099999999999999")
);
// Chuỗi rỗng
Assertions.assertFalse(PhoneValidator.isValidInternationalPhone(""));
}
@Test
public void testNullPhoneNumber() {
// Cố tình truyền null để xem hàm xử lý thế nào
// Lưu ý: Đọc thêm phần "Mẹo nhỏ" bên dưới để pass được test này
Assertions.assertFalse(PhoneValidator.isValidInternationalPhone(null));
}
}
@@ -1,9 +1,10 @@
# Quarkus
quarkus.http.host=0.0.0.0
# Database
## Datasource
%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:test_db;DB_CLOSE_DELAY=-1
## Orm
%test.quarkus.hibernate-orm.database.generation=drop-and-create
# Docker
%test.quarkus.container-image.build=false
%test.quarkus.container-image.push=false
+1 -1
View File
@@ -18,7 +18,7 @@
<properties>
<compiler-plugin.version>3.15.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding
>UTF-8</project.reporting.outputEncoding>
@@ -19,8 +19,6 @@ public class MenuItemEntity extends BaseEntity {
)
public List<MenuItemIngredientEntity> ingredients = new ArrayList<>();
private MenuItemEntity() {}
/**
* Thêm nguyên liệu vào món ăn với định lượng cụ thể
*/
@@ -0,0 +1,50 @@
package com.drinkool.entities;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class InventoryItemEntityTest {
@Test
@Transactional
public void testCreateInventoryItem() {
// 1. Chuẩn bị dữ liệu (Lưu ý: Không còn biến quantity nữa)
String name = "Trà sữa truyền thống";
String unit = "Ly";
// 2. Gọi hàm static create (Không dùng new hay hàm add nữa)
// Hàm này vừa tạo object, vừa gán data, vừa gọi persist() luôn
InventoryItemEntity item = InventoryItemEntity.create(name, unit);
// 3. Kiểm chứng
Assertions.assertNotNull(item, "Entity tạo ra không được null");
Assertions.assertEquals(name, item.name, "Tên không khớp");
Assertions.assertEquals(unit, item.unit, "Đơn vị không khớp");
Assertions.assertNotNull(
item.id,
"ID phải được sinh ra tự động sau khi persist"
);
}
@Test
@Transactional
public void testCreateWithDefaultUnit() {
// 1. Chuẩn bị dữ liệu
String name = "Trân châu đen";
// 2. Gọi hàm static create rút gọn (chỉ truyền name, unit sẽ tự là "unit")
InventoryItemEntity item = InventoryItemEntity.create(name);
// 3. Kiểm chứng
Assertions.assertNotNull(item, "Entity tạo ra không được null");
Assertions.assertEquals(name, item.name, "Tên không khớp");
Assertions.assertEquals("unit", item.unit, "Unit mặc định phải là 'unit'");
Assertions.assertNotNull(
item.id,
"ID phải được sinh ra tự động sau khi persist"
);
}
}
@@ -0,0 +1,90 @@
package com.drinkool.entities;
import static org.junit.jupiter.api.Assertions.*;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class MenuItemEntityTest {
@Test
@Transactional
public void testCreateMenuItemSuccessfully() {
// 1. Chuẩn bị dữ liệu (Arrange)
String name = "Cà phê sữa đá";
double price = 29000.0;
// 2. Thực thi (Act) - Gọi hàm tĩnh create
MenuItemEntity menuItem = MenuItemEntity.create(name, price);
// 3. Kiểm chứng (Assert)
assertNotNull(menuItem, "Thực thể MenuItem không được null");
assertEquals(name, menuItem.name, "Tên món ăn không khớp");
assertEquals(price, menuItem.price, "Giá món ăn không khớp");
assertNotNull(menuItem.id, "ID phải được tự động sinh ra sau khi persist");
assertTrue(
menuItem.ingredients.isEmpty(),
"Danh sách nguyên liệu ban đầu phải rỗng"
);
}
@Test
@Transactional
public void testAddIngredientSuccessfully() {
// 1. Chuẩn bị dữ liệu (Arrange)
// Tạo món ăn
MenuItemEntity menuItem = MenuItemEntity.create(
"Trà sữa trân châu",
45000.0
);
// Tạo nguyên liệu trong kho (Dùng đúng hàm add() của EateryInventoryItemEntity như đã fix)
EateryInventoryItemEntity inventoryItem = EateryInventoryItemEntity.create(
"Trân châu đen",
50,
"kg"
);
double requiredQty = 0.2; // Cần 0.2 kg trân châu cho 1 ly
// 2. Thực thi (Act) - Thêm nguyên liệu vào món ăn
menuItem.addIngredient(inventoryItem, requiredQty);
// 3. Kiểm chứng (Assert)
// Kiểm tra danh sách nguyên liệu của món ăn
assertFalse(
menuItem.ingredients.isEmpty(),
"Danh sách nguyên liệu không được rỗng sau khi thêm"
);
assertEquals(
1,
menuItem.ingredients.size(),
"Phải có đúng 1 nguyên liệu trong danh sách"
);
// Lấy phần tử nguyên liệu đầu tiên ra để kiểm tra chi tiết các liên kết
MenuItemIngredientEntity addedIngredient = menuItem.ingredients.get(0);
assertNotNull(
addedIngredient.id,
"ID của Entity trung gian phải được sinh ra"
);
assertEquals(
menuItem.id,
addedIngredient.menuItem.id,
"Khóa ngoại MenuItem bị sai"
);
assertEquals(
inventoryItem.id,
addedIngredient.inventoryItem.id,
"Khóa ngoại InventoryItem bị sai"
);
assertEquals(
requiredQty,
addedIngredient.requiredQuantity,
"Định lượng (requiredQty) không khớp"
);
}
}
@@ -23,14 +23,16 @@ public class MenuItemIngredientEntityTest {
);
String inventoryItemName = "Water";
double inventoryItemQuantity = 10;
int inventoryItemQuantity = 10; // Đổi thành int cho khớp với kiểu của EateryInventoryItemEntity
String inventoryItemUnit = "l";
// SỬA Ở ĐÂY: Khởi tạo bằng new và dùng hàm add() đúng như cấu trúc class của bạn
EateryInventoryItemEntity inventoryItem = EateryInventoryItemEntity.create(
inventoryItemName,
inventoryItemQuantity,
inventoryItemUnit
);
// Lưu ý: Hàm add() của bạn đã có sẵn lệnh this.persist() bên trong nên không cần gọi lại nữa!
double requiredQuantity = 0.5;
@@ -0,0 +1,57 @@
package com.drinkool.entities;
import com.drinkool.models.ReviewModel;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.transaction.Transactional;
import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class ReviewEntityTest {
@Test
@Transactional
public void testCreateReview() {
// 1. Chuẩn bị dữ liệu (Arrange)
UUID testReviewerId = UUID.randomUUID();
UUID testEateryId = UUID.randomUUID();
// Truyền trực tiếp rating và comment vào constructor của ReviewModel
ReviewModel inputModel = new ReviewModel(5, "Món ăn tuyệt vời!");
// 2. Thực thi (Act)
ReviewEntity savedReview = ReviewEntity.create(
testReviewerId,
testEateryId,
inputModel
);
// 3. Kiểm chứng (Assert)
Assertions.assertNotNull(
savedReview,
"Thực thể Review sau khi tạo không được null"
);
Assertions.assertEquals(
testReviewerId,
savedReview.reviewerId,
"Reviewer ID không khớp"
);
Assertions.assertEquals(
testEateryId,
savedReview.eateryId,
"Eatery ID không khớp"
);
Assertions.assertEquals(5, savedReview.rating, "Rating không khớp");
Assertions.assertEquals(
"Món ăn tuyệt vời!",
savedReview.comment,
"Comment không khớp"
);
Assertions.assertNotNull(
savedReview.id,
"ID phải được tự động sinh ra sau khi persist"
);
}
}
@@ -35,7 +35,8 @@ public class ReviewServiceTest {
.body(input)
.when()
.post("/api/review/create")
.then();
.then()
.statusCode(201);
assertEquals(1, ReviewEntity.find("reviewerId", reviewerId).count());
}
@@ -2,8 +2,9 @@
quarkus.http.host=0.0.0.0
# Database
# Database
## Datasource
%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:test_db;DB_CLOSE_DELAY=-1
## Orm
%test.quarkus.hibernate-orm.database.generation=drop-and-create
+16 -33
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion>
@@ -17,14 +17,15 @@
<packaging>quarkus</packaging>
<properties>
<quarkus.package.jar.enabled>false</quarkus.package.jar.enabled>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
<compiler-plugin.version>3.15.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding
>UTF-8</project.reporting.outputEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id
>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.32.4</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.4</surefire-plugin.version>
@@ -48,10 +49,6 @@
<artifactId>lib</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jackson</artifactId>
@@ -64,6 +61,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-docker</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
@@ -101,8 +102,7 @@
<configuration>
<argLine>@{argLine}</argLine>
<systemPropertyVariables>
<java.util.logging.manager
>org.jboss.logmanager.LogManager</java.util.logging.manager>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
@@ -123,28 +123,11 @@
<systemPropertyVariables>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager
>org.jboss.logmanager.LogManager</java.util.logging.manager>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<quarkus.package.jar.enabled>false</quarkus.package.jar.enabled>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
</profiles>
</project>
@@ -2,7 +2,6 @@ package com.drinkool;
import com.drinkool.dtos.*;
import com.drinkool.services.AccountService;
import io.quarkus.redis.datasource.RedisDataSource;
import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
@@ -16,28 +15,14 @@ public class CustomerGatewayResource {
@RestClient
AccountService accountService;
@Inject
RedisDataSource redisDataSource;
@POST
@Path("/signup")
@Path(Url.Signup)
public Uni<Response> proxySignup(Signup input) {
String otpVerifiedKey = "otp:verified:" + input.phone;
var valueCmd = redisDataSource.value(String.class);
if (valueCmd.get(otpVerifiedKey) == null) {
return Uni.createFrom().item(
Response.status(Response.Status.FORBIDDEN)
.entity("Phone not verified")
.build()
);
}
return accountService.signup(input);
}
@POST
@Path("/login")
@Path(Url.Login)
public Uni<Response> proxyLogin(Login input) {
return accountService.login(input);
}
@@ -1,5 +1,6 @@
package com.drinkool.services;
import com.drinkool.Url;
import com.drinkool.dtos.*;
import io.smallrye.mutiny.Uni;
import jakarta.ws.rs.*;
@@ -7,17 +8,25 @@ import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@RegisterRestClient(configKey = "account")
@Path("/api")
@Path("")
public interface AccountService {
@POST
@Path("/signup")
@Path(Url.Signup)
Uni<Response> signup(Signup input);
@POST
@Path("/quickSignup")
@Path(Url.QuickSignup)
Uni<Response> quickSignup(QuickSignup input);
@POST
@Path("/login")
@Path(Url.Login)
Uni<Response> login(Login input);
@POST
@Path(Url.QuickLogin)
Uni<Response> quickLogin(QuickSignup input);
@POST
@Path(Url.SmsOtp)
Uni<Response> smsOtp(SmsOtp input);
}
@@ -1 +1,11 @@
quarkus.rest-client.account.url=http://localhost:502
# Docker
quarkus.container-image.registry=git.demonkernel.io.vn
quarkus.container-image.group=foodsurf
quarkus.container-image.name=gateway-service
quarkus.container-image.push=true
quarkus.container-image.build=true
quarkus.container-image.builder=docker
quarkus.container-image.additional-tags=latest
# Build
quarkus.native.container-build=false
+163
View File
@@ -0,0 +1,163 @@
# 1. ACCOUNT SERVICE
apiVersion: apps/v1
kind: Deployment
metadata:
name: account-deploy
spec:
replicas: 1
selector:
matchLabels:
app: account
template:
metadata:
labels:
app: account
spec:
containers:
- name: account-pod
image: git.demonkernel.io.vn/foodsurf/account-service:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: QUARKUS_REDIS_HOST
value: "redis-service"
- name: QUARKUS_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
- name: QUARKUS_DATASOURCE_USERNAME
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: QUARKUS_DATASOURCE_JDBC_URL
valueFrom:
secretKeyRef:
name: postgres-credentials
key: url
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "256Mi"
volumeMounts:
- name: keys-volume
mountPath: "/etc/keys"
readOnly: true
volumes:
- name: keys-volume
secret:
secretName: jwt-keys
---
apiVersion: v1
kind: Service
metadata:
name: account-service
spec:
selector:
app: account
ports:
- port: 80
targetPort: 8080
---
# 2. GATEWAY SERVICE
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway-deploy
spec:
replicas: 1
selector:
matchLabels:
app: gateway
template:
metadata:
labels:
app: gateway
spec:
containers:
- name: gateway-pod
image: git.demonkernel.io.vn/foodsurf/gateway-service:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
env:
- name: QUARKUS_REST_CLIENT_ACCOUNT_URL
value: "http://account-service"
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "256Mi"
volumeMounts:
- name: keys-volume
mountPath: "/etc/keys"
readOnly: true
volumes:
- name: keys-volume
secret:
secretName: jwt-keys
---
apiVersion: v1
kind: Service
metadata:
name: gateway-service
spec:
type: NodePort
selector:
app: gateway
ports:
- port: 80
targetPort: 8080
nodePort: 32080
---
# 3. REDIS
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-deploy
spec:
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis-pod
image: redis:alpine
ports:
- containerPort: 6379
resources:
limits:
cpu: "100m"
memory: "128Mi"
requests:
cpu: "20m"
memory: "64Mi"
command:
[
"redis-server",
"--maxmemory",
"96mb",
"--maxmemory-policy",
"allkeys-lru",
]
---
apiVersion: v1
kind: Service
metadata:
name: redis-service
spec:
selector:
app: redis
ports:
- port: 6379
+2 -2
View File
@@ -15,8 +15,8 @@
<artifactId>lib</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
+7
View File
@@ -0,0 +1,7 @@
package com.drinkool;
public class Jwt {
public static final String headerId = "X-Internal-";
public static final String userId = headerId + "UserId";
public static final String role = headerId + "Role";
}
+5
View File
@@ -0,0 +1,5 @@
package com.drinkool;
public class Role {
public static final String Customer = "customer";
}
+11
View File
@@ -0,0 +1,11 @@
package com.drinkool;
public class Url {
public static final String Signup = "/signup";
public static final String QuickSignup = "/quick_signup";
public static final String Login = "/login";
public static final String QuickLogin = "/quick_login";
public static final String SmsOtp = "/sms_otp";
public static final String Me = "/me";
}
@@ -13,13 +13,13 @@ public class ReviewModel extends BaseEntity {
@Column
public String comment;
public ReviewModel() {}
public ReviewModel(int rating, String comment) {
this.rating = rating;
this.comment = comment;
}
public ReviewModel() {}
public ReviewModel(ReviewModel input) {
this(input.rating, input.comment);
}
+1 -1
View File
@@ -10,7 +10,7 @@
<version>1.1.0-dev.1</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.source>25</maven.compiler.source>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.32.3</quarkus.platform.version>