Prepare for deployment
This commit is contained in:
15
.idea/.idea.T120B165-ImgBoard/.idea/workspace.xml
generated
15
.idea/.idea.T120B165-ImgBoard/.idea/workspace.xml
generated
@@ -8,19 +8,7 @@
|
|||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="4e14f3e6-3f4d-450c-8a9e-273b19823ca0" name="Changes" comment="">
|
<list default="true" id="4e14f3e6-3f4d-450c-8a9e-273b19823ca0" name="Changes" comment="" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.T120B165-ImgBoard/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.T120B165-ImgBoard/.idea/workspace.xml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard.sln.DotSettings.user" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard.sln.DotSettings.user" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Controllers/PostController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Controllers/PostController.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Controllers/TagController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Controllers/TagController.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Dtos/Comment/CommentDto.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Dtos/Comment/CommentDto.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Dtos/Post/PostDto.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Dtos/Post/PostDto.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Dtos/Tag/CreateTagDto.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Dtos/Tag/CreateTagDto.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Models/Tag.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Models/Tag.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Program.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/T120B165-ImgBoard/Services/PostService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/T120B165-ImgBoard/Services/PostService.cs" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
@@ -179,6 +167,7 @@
|
|||||||
<workItem from="1761063773513" duration="10000" />
|
<workItem from="1761063773513" duration="10000" />
|
||||||
<workItem from="1762152955053" duration="832000" />
|
<workItem from="1762152955053" duration="832000" />
|
||||||
<workItem from="1762243840092" duration="121000" />
|
<workItem from="1762243840092" duration="121000" />
|
||||||
|
<workItem from="1762453453806" duration="822000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
FROM node:20-alpine AS development-dependencies-env
|
FROM node:20-alpine AS development-dependencies-env
|
||||||
COPY . /app
|
COPY Client /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
FROM node:20-alpine AS production-dependencies-env
|
FROM node:20-alpine AS production-dependencies-env
|
||||||
COPY ./package.json package-lock.json /app/
|
COPY Client/package.json Client/package-lock.json /app/
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm ci --omit=dev
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
FROM node:20-alpine AS build-env
|
FROM node:20-alpine AS build-env
|
||||||
COPY . /app/
|
COPY Client /app/
|
||||||
COPY --from=development-dependencies-env /app/node_modules /app/node_modules
|
COPY --from=development-dependencies-env /app/node_modules /app/node_modules
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine
|
||||||
COPY ./package.json package-lock.json /app/
|
COPY Client/package.json Client/package-lock.json /app/
|
||||||
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
|
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
|
||||||
COPY --from=build-env /app/build /app/build
|
COPY --from=build-env /app/build /app/build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { PaginatedResponse } from "~/types/PaginatedResponse";
|
|||||||
import type { Post } from "~/types/post";
|
import type { Post } from "~/types/post";
|
||||||
import type { Tag } from "~/types/tag";
|
import type { Tag } from "~/types/tag";
|
||||||
|
|
||||||
const ENDPOINT = 'http://localhost:5259/api';
|
const API_URL = import.meta.env.PROD ? '/api' : 'http://localhost:5259/api';
|
||||||
|
|
||||||
// This is a simplified session renewal handler. It's outside the class
|
// This is a simplified session renewal handler. It's outside the class
|
||||||
// to avoid circular dependencies or complex context passing.
|
// to avoid circular dependencies or complex context passing.
|
||||||
@@ -14,7 +14,7 @@ const renewSessionAndRetry = async (failedRequest: () => Promise<Response>): Pro
|
|||||||
if (!refreshToken) return failedRequest();
|
if (!refreshToken) return failedRequest();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const renewResponse = await fetch(`${ENDPOINT}/auth/renew`, {
|
const renewResponse = await fetch(`${API_URL}/auth/renew`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ refreshToken }),
|
body: JSON.stringify({ refreshToken }),
|
||||||
@@ -129,31 +129,31 @@ export class API {
|
|||||||
|
|
||||||
/* Tag APIs */
|
/* Tag APIs */
|
||||||
public static async fetchTags(page: number): Promise<PaginatedResponse<Tag>> {
|
public static async fetchTags(page: number): Promise<PaginatedResponse<Tag>> {
|
||||||
const data = await API.get(`${ENDPOINT}/tags?page=${page}`);
|
const data = await API.get(`${API_URL}/tags?page=${page}`);
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async createTag(name: string, tagType: string, user: User): Promise<Response> {
|
public static async createTag(name: string, tagType: string, user: User): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/tags`, { name, type: tagType });
|
return await API.post(`${API_URL}/tags`, { name, type: tagType });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async updateTag(name: string, newType: string, user: User): Promise<Response> {
|
public static async updateTag(name: string, newType: string, user: User): Promise<Response> {
|
||||||
return await API.patch(`${ENDPOINT}/tags/${encodeURIComponent(name)}`, { type: newType });
|
return await API.patch(`${API_URL}/tags/${encodeURIComponent(name)}`, { type: newType });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async deleteTag(name: string, user: User): Promise<Response> {
|
public static async deleteTag(name: string, user: User): Promise<Response> {
|
||||||
return await API.delete(`${ENDPOINT}/tags/${encodeURIComponent(name)}`, {});
|
return await API.delete(`${API_URL}/tags/${encodeURIComponent(name)}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Post APIs */
|
/* Post APIs */
|
||||||
public static async fetchPostById(id: number): Promise<Post|null> {
|
public static async fetchPostById(id: number): Promise<Post|null> {
|
||||||
const data = await API.get(`${ENDPOINT}/posts/${id}`);
|
const data = await API.get(`${API_URL}/posts/${id}`);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fetchPosts(page: number, filter: string = ""): Promise<PaginatedResponse<Post>> {
|
public static async fetchPosts(page: number, filter: string = ""): Promise<PaginatedResponse<Post>> {
|
||||||
const data = await API.get(`${ENDPOINT}/posts?page=${page}&query=${encodeURIComponent(filter)}`);
|
const data = await API.get(`${API_URL}/posts?page=${page}&query=${encodeURIComponent(filter)}`);
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ export class API {
|
|||||||
fileMimeType: string, fileSize: number,
|
fileMimeType: string, fileSize: number,
|
||||||
user: User
|
user: User
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/posts`, {
|
return await API.post(`${API_URL}/posts`, {
|
||||||
title, description, tags, filename,
|
title, description, tags, filename,
|
||||||
fileMimeType, fileSize
|
fileMimeType, fileSize
|
||||||
});
|
});
|
||||||
@@ -183,48 +183,48 @@ export class API {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async updatePost(postId: number, title: string, description: string, tags: string[], user: User): Promise<Response> {
|
public static async updatePost(postId: number, title: string, description: string, tags: string[], user: User): Promise<Response> {
|
||||||
return await API.patch(`${ENDPOINT}/posts/${postId}`, { title, description, tags });
|
return await API.patch(`${API_URL}/posts/${postId}`, { title, description, tags });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async deletePost(postId: number, user: User): Promise<Response> {
|
public static async deletePost(postId: number, user: User): Promise<Response> {
|
||||||
return await API.delete(`${ENDPOINT}/posts/${postId}`, {});
|
return await API.delete(`${API_URL}/posts/${postId}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Comment APIs */
|
/* Comment APIs */
|
||||||
public static async fetchCommentsByPostId(postId: number, page: number): Promise<PaginatedResponse<Comment>> {
|
public static async fetchCommentsByPostId(postId: number, page: number): Promise<PaginatedResponse<Comment>> {
|
||||||
const data = await API.get(`${ENDPOINT}/posts/${postId}/comments?page=${page}`);
|
const data = await API.get(`${API_URL}/posts/${postId}/comments?page=${page}`);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async postComment(postId: number, text: string, user: User): Promise<Response> {
|
public static async postComment(postId: number, text: string, user: User): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/posts/${postId}/comments`, { text });
|
return await API.post(`${API_URL}/posts/${postId}/comments`, { text });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async updateComment(postId: number, commentId: number, newText: string, user: User): Promise<Response> {
|
public static async updateComment(postId: number, commentId: number, newText: string, user: User): Promise<Response> {
|
||||||
return await API.patch(`${ENDPOINT}/posts/${postId}/comments/${commentId}`, { text: newText });
|
return await API.patch(`${API_URL}/posts/${postId}/comments/${commentId}`, { text: newText });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async deleteComment(postId: number, commentId: number, user: User): Promise<Response> {
|
public static async deleteComment(postId: number, commentId: number, user: User): Promise<Response> {
|
||||||
return await API.delete(`${ENDPOINT}/posts/${postId}/comments/${commentId}`, {});
|
return await API.delete(`${API_URL}/posts/${postId}/comments/${commentId}`, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Auth APIs */
|
/* Auth APIs */
|
||||||
public static async register(username: string, email: string, password: string): Promise<Response> {
|
public static async register(username: string, email: string, password: string): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/auth/register`, { username, email, password });
|
return await API.post(`${API_URL}/auth/register`, { username, email, password });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async login(email: string, password: string): Promise<Response> {
|
public static async login(email: string, password: string): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/auth/login`, { email, password });
|
return await API.post(`${API_URL}/auth/login`, { email, password });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async renewToken(refreshToken: string): Promise<Response> {
|
public static async renewToken(refreshToken: string): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/auth/renew`, { refreshToken });
|
return await API.post(`${API_URL}/auth/renew`, { refreshToken });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async revokeToken(refreshToken: string): Promise<Response> {
|
public static async revokeToken(refreshToken: string): Promise<Response> {
|
||||||
return await API.post(`${ENDPOINT}/auth/revoke`, { refreshToken });
|
return await API.post(`${API_URL}/auth/revoke`, { refreshToken });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
compose.yaml
14
compose.yaml
@@ -12,6 +12,20 @@
|
|||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- app_data:/app/Storage
|
- app_data:/app/Storage
|
||||||
|
|
||||||
|
t120b165-imgboard-client:
|
||||||
|
image: t120b165-imgboard-client
|
||||||
|
container_name: t120b165_app_client
|
||||||
|
restart: unless-stopped
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Client/Dockerfile
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- t120b165-imgboard
|
||||||
|
ports:
|
||||||
|
- "8000:3000"
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: mariadb:lts
|
image: mariadb:lts
|
||||||
container_name: t120b165_db
|
container_name: t120b165_db
|
||||||
|
|||||||
Reference in New Issue
Block a user