Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
3aeec4d23e
|
|||
debfcf7226
|
|||
15bbc27238
|
|||
16bd44c599
|
|||
d13b16c032
|
|||
d144f7385b
|
|||
0283c293ef
|
|||
8d75849c55 |
0
.dockerignore
Normal file → Executable file
0
.dockerignore
Normal file → Executable file
0
.editorconfig
Normal file → Executable file
0
.editorconfig
Normal file → Executable file
0
.env.example
Normal file → Executable file
0
.env.example
Normal file → Executable file
30
.gitea/workflows/ci-dev.yml
Executable file
30
.gitea/workflows/ci-dev.yml
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
version: "1"
|
||||||
|
name: Publish Development Docker Image
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v[0-9]+\\.[0-9]+\\.[0-9]+-dev"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Publish Development Docker Image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- name: Login to Registry
|
||||||
|
run: echo "${{ secrets.ACCESS_TOKEN }}" | docker login git.altaiar.dev -u "${{ secrets.USERNAME }}" --password-stdin
|
||||||
|
|
||||||
|
- name: Build & Tag Image
|
||||||
|
run: |
|
||||||
|
docker build --build-arg APP_VERSION=${{ gitea.ref_name }} -t git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }} .
|
||||||
|
docker tag git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }} git.altaiar.dev/${{ gitea.repository }}:dev
|
||||||
|
|
||||||
|
- name: Push Images
|
||||||
|
run: |
|
||||||
|
docker push git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }}
|
||||||
|
docker push git.altaiar.dev/${{ gitea.repository }}:dev
|
5
.gitea/workflows/ci.yml
Normal file → Executable file
5
.gitea/workflows/ci.yml
Normal file → Executable file
@ -1,10 +1,9 @@
|
|||||||
version: "1"
|
version: "1"
|
||||||
name: Publish Docker Image
|
name: Publish Docker Image
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- "v[0-9]+\\.[0-9]+\\.[0-9]+"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -22,7 +21,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build & Tag Image
|
- name: Build & Tag Image
|
||||||
run: |
|
run: |
|
||||||
docker build -t git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }} .
|
docker build --build-arg APP_VERSION=${{ gitea.ref_name }} -t git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }} .
|
||||||
docker tag git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }} git.altaiar.dev/${{ gitea.repository }}:latest
|
docker tag git.altaiar.dev/${{ gitea.repository }}:${{ gitea.ref_name }} git.altaiar.dev/${{ gitea.repository }}:latest
|
||||||
|
|
||||||
- name: Push Images
|
- name: Push Images
|
||||||
|
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
.redwood/README.md
Normal file → Executable file
0
.redwood/README.md
Normal file → Executable file
0
.vscode/extensions.json
vendored
Normal file → Executable file
0
.vscode/extensions.json
vendored
Normal file → Executable file
0
.vscode/launch.json
vendored
Normal file → Executable file
0
.vscode/launch.json
vendored
Normal file → Executable file
0
.vscode/settings.json
vendored
Normal file → Executable file
0
.vscode/settings.json
vendored
Normal file → Executable file
0
.vscode/tasks.json
vendored
Normal file → Executable file
0
.vscode/tasks.json
vendored
Normal file → Executable file
0
.yarnrc.yml
Normal file → Executable file
0
.yarnrc.yml
Normal file → Executable file
27
Dockerfile
Normal file → Executable file
27
Dockerfile
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
# base
|
# base
|
||||||
# ----
|
# ----
|
||||||
FROM node:20-bookworm-slim as base
|
FROM node:20-bookworm-slim AS base
|
||||||
|
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ COPY --chown=node:node graphql.config.js .
|
|||||||
|
|
||||||
# api build
|
# api build
|
||||||
# ---------
|
# ---------
|
||||||
FROM base as api_build
|
FROM base AS api_build
|
||||||
|
|
||||||
# If your api side build relies on build-time environment variables,
|
# If your api side build relies on build-time environment variables,
|
||||||
# specify them here as ARGs. (But don't put secrets in your Dockerfile!)
|
# specify them here as ARGs. (But don't put secrets in your Dockerfile!)
|
||||||
@ -51,13 +51,14 @@ ARG EMAIL_FROM
|
|||||||
ARG EMAIL_TO
|
ARG EMAIL_TO
|
||||||
ARG FIRST_NAME
|
ARG FIRST_NAME
|
||||||
ARG LAST_NAME
|
ARG LAST_NAME
|
||||||
|
ARG APP_VERSION
|
||||||
|
|
||||||
COPY --chown=node:node api api
|
COPY --chown=node:node api api
|
||||||
RUN yarn rw build api
|
RUN yarn rw build api
|
||||||
|
|
||||||
# web prerender build
|
# web prerender build
|
||||||
# -------------------
|
# -------------------
|
||||||
FROM api_build as web_build_with_prerender
|
FROM api_build AS web_build_with_prerender
|
||||||
|
|
||||||
ARG FIRST_NAME
|
ARG FIRST_NAME
|
||||||
ARG LAST_NAME
|
ARG LAST_NAME
|
||||||
@ -67,13 +68,16 @@ ARG CITY
|
|||||||
ARG DEFAULT_THEME
|
ARG DEFAULT_THEME
|
||||||
ARG API_ADDRESS_PROD
|
ARG API_ADDRESS_PROD
|
||||||
ARG API_ADDRESS_DEV
|
ARG API_ADDRESS_DEV
|
||||||
|
ARG APP_VERSION
|
||||||
|
|
||||||
|
ENV APP_VERSION=$APP_VERSION
|
||||||
|
|
||||||
COPY --chown=node:node web web
|
COPY --chown=node:node web web
|
||||||
RUN yarn rw build web
|
RUN yarn rw build web
|
||||||
|
|
||||||
# web build
|
# web build
|
||||||
# ---------
|
# ---------
|
||||||
FROM base as web_build
|
FROM base AS web_build
|
||||||
|
|
||||||
ARG FIRST_NAME
|
ARG FIRST_NAME
|
||||||
ARG LAST_NAME
|
ARG LAST_NAME
|
||||||
@ -83,13 +87,16 @@ ARG CITY
|
|||||||
ARG DEFAULT_THEME
|
ARG DEFAULT_THEME
|
||||||
ARG API_ADDRESS_PROD
|
ARG API_ADDRESS_PROD
|
||||||
ARG API_ADDRESS_DEV
|
ARG API_ADDRESS_DEV
|
||||||
|
ARG APP_VERSION
|
||||||
|
|
||||||
|
ENV APP_VERSION=$APP_VERSION
|
||||||
|
|
||||||
COPY --chown=node:node web web
|
COPY --chown=node:node web web
|
||||||
RUN yarn rw build web --no-prerender
|
RUN yarn rw build web --no-prerender
|
||||||
|
|
||||||
# api serve
|
# api serve
|
||||||
# ---------
|
# ---------
|
||||||
FROM node:20-bookworm-slim as api_serve
|
FROM node:20-bookworm-slim AS api_serve
|
||||||
|
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
@ -119,7 +126,10 @@ COPY --chown=node:node --from=api_build /home/node/app/api/dist /home/node/app/a
|
|||||||
COPY --chown=node:node --from=api_build /home/node/app/api/db /home/node/app/api/db
|
COPY --chown=node:node --from=api_build /home/node/app/api/db /home/node/app/api/db
|
||||||
COPY --chown=node:node --from=api_build /home/node/app/node_modules/.prisma /home/node/app/node_modules/.prisma
|
COPY --chown=node:node --from=api_build /home/node/app/node_modules/.prisma /home/node/app/node_modules/.prisma
|
||||||
|
|
||||||
|
ARG APP_VERSION
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
ENV APP_VERSION=$APP_VERSION
|
||||||
|
|
||||||
# default api serve command
|
# default api serve command
|
||||||
# ---------
|
# ---------
|
||||||
@ -132,7 +142,7 @@ CMD [ "./api/dist/server.js" ]
|
|||||||
|
|
||||||
# web serve
|
# web serve
|
||||||
# ---------
|
# ---------
|
||||||
FROM node:20-bookworm-slim as web_serve
|
FROM node:20-bookworm-slim AS web_serve
|
||||||
|
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
@ -156,6 +166,9 @@ COPY --chown=node:node graphql.config.js .
|
|||||||
|
|
||||||
COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist
|
COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist
|
||||||
|
|
||||||
|
ARG APP_VERSION
|
||||||
|
ENV APP_VERSION=$APP_VERSION
|
||||||
|
|
||||||
ENV NODE_ENV=production \
|
ENV NODE_ENV=production \
|
||||||
API_PROXY_TARGET=http://api:8911
|
API_PROXY_TARGET=http://api:8911
|
||||||
|
|
||||||
@ -164,7 +177,7 @@ CMD "node_modules/.bin/rw-web-server" "--api-proxy-target" "$API_PROXY_TARGET"
|
|||||||
|
|
||||||
# console
|
# console
|
||||||
# -------
|
# -------
|
||||||
FROM base as console
|
FROM base AS console
|
||||||
|
|
||||||
# To add more packages:
|
# To add more packages:
|
||||||
#
|
#
|
||||||
|
13
README.md
Normal file → Executable file
13
README.md
Normal file → Executable file
@ -16,6 +16,7 @@ services:
|
|||||||
portfolio:
|
portfolio:
|
||||||
container_name: portfolio
|
container_name: portfolio
|
||||||
image: git.altaiar.dev/ahmed/portfolio:latest
|
image: git.altaiar.dev/ahmed/portfolio:latest
|
||||||
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- API_PROXY_TARGET=http://localhost:8911
|
- API_PROXY_TARGET=http://localhost:8911
|
||||||
@ -44,7 +45,8 @@ services:
|
|||||||
- 8910:8910 # Web
|
- 8910:8910 # Web
|
||||||
- 8911:8911 # API
|
- 8911:8911 # API
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
db:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- files:/home/node/app/api/files_prod
|
- files:/home/node/app/api/files_prod
|
||||||
command: >
|
command: >
|
||||||
@ -54,14 +56,19 @@ services:
|
|||||||
yarn rw prisma db seed &&
|
yarn rw prisma db seed &&
|
||||||
yarn rw serve"
|
yarn rw serve"
|
||||||
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
container_name: portfolio-db
|
container_name: portfolio-db
|
||||||
image: postgres:16-bookworm
|
image: postgres:16-bookworm
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=redwood
|
- POSTGRES_USER=redwood
|
||||||
- POSTGRES_PASSWORD=changeme
|
- POSTGRES_PASSWORD=changeme # Change to a more secure password
|
||||||
- POSTGRES_DB=portfolio
|
- POSTGRES_DB=portfolio
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -d DATABASE_URL"] # Replace DATABASE_URL with the database URL from the portfolio container
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
volumes:
|
volumes:
|
||||||
- postgres:/var/lib/postgresql/data
|
- postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
0
api/db/migrations/20240810184713_user/migration.sql
Normal file → Executable file
0
api/db/migrations/20240810184713_user/migration.sql
Normal file → Executable file
0
api/db/migrations/20240819213158_social/migration.sql
Normal file → Executable file
0
api/db/migrations/20240819213158_social/migration.sql
Normal file → Executable file
0
api/db/migrations/20240821020900_portrait/migration.sql
Normal file → Executable file
0
api/db/migrations/20240821020900_portrait/migration.sql
Normal file → Executable file
0
api/db/migrations/20240824001030_project/migration.sql
Normal file → Executable file
0
api/db/migrations/20240824001030_project/migration.sql
Normal file → Executable file
0
api/db/migrations/20240921164727_project_date_is_mandatory_default_today_12_am/migration.sql
Normal file → Executable file
0
api/db/migrations/20240921164727_project_date_is_mandatory_default_today_12_am/migration.sql
Normal file → Executable file
0
api/db/migrations/20240921181721_more_socials/migration.sql
Normal file → Executable file
0
api/db/migrations/20240921181721_more_socials/migration.sql
Normal file → Executable file
0
api/db/migrations/20240921183021_even_more_socials/migration.sql
Normal file → Executable file
0
api/db/migrations/20240921183021_even_more_socials/migration.sql
Normal file → Executable file
0
api/db/migrations/20240927031102_/migration.sql
Normal file → Executable file
0
api/db/migrations/20240927031102_/migration.sql
Normal file → Executable file
0
api/db/migrations/20240929164343_/migration.sql
Normal file → Executable file
0
api/db/migrations/20240929164343_/migration.sql
Normal file → Executable file
0
api/db/migrations/20241001005227_title_and_resume/migration.sql
Normal file → Executable file
0
api/db/migrations/20241001005227_title_and_resume/migration.sql
Normal file → Executable file
0
api/db/migrations/20241005014130_/migration.sql
Normal file → Executable file
0
api/db/migrations/20241005014130_/migration.sql
Normal file → Executable file
0
api/db/migrations/20241015183037_matrix/migration.sql
Normal file → Executable file
0
api/db/migrations/20241015183037_matrix/migration.sql
Normal file → Executable file
0
api/db/migrations/migration_lock.toml
Normal file → Executable file
0
api/db/migrations/migration_lock.toml
Normal file → Executable file
0
api/db/schema.prisma
Normal file → Executable file
0
api/db/schema.prisma
Normal file → Executable file
0
api/jest.config.js
Normal file → Executable file
0
api/jest.config.js
Normal file → Executable file
4
api/package.json
Normal file → Executable file
4
api/package.json
Normal file → Executable file
@ -9,8 +9,8 @@
|
|||||||
"@redwoodjs/api-server": "8.4.0",
|
"@redwoodjs/api-server": "8.4.0",
|
||||||
"@redwoodjs/auth-dbauth-api": "8.4.0",
|
"@redwoodjs/auth-dbauth-api": "8.4.0",
|
||||||
"@redwoodjs/graphql-server": "8.4.0",
|
"@redwoodjs/graphql-server": "8.4.0",
|
||||||
"@tus/file-store": "^1.4.0",
|
"@tus/file-store": "^2.0.0",
|
||||||
"@tus/server": "^1.7.0",
|
"@tus/server": "^2.0.0",
|
||||||
"countries-list": "^3.1.1",
|
"countries-list": "^3.1.1",
|
||||||
"graphql-scalars": "^1.23.0",
|
"graphql-scalars": "^1.23.0",
|
||||||
"nodemailer": "^6.9.14"
|
"nodemailer": "^6.9.14"
|
||||||
|
0
api/quick-lint-js.config
Normal file → Executable file
0
api/quick-lint-js.config
Normal file → Executable file
0
api/src/directives/requireAuth/requireAuth.ts
Normal file → Executable file
0
api/src/directives/requireAuth/requireAuth.ts
Normal file → Executable file
0
api/src/directives/skipAuth/skipAuth.ts
Normal file → Executable file
0
api/src/directives/skipAuth/skipAuth.ts
Normal file → Executable file
0
api/src/functions/auth.ts
Normal file → Executable file
0
api/src/functions/auth.ts
Normal file → Executable file
0
api/src/functions/graphql.ts
Normal file → Executable file
0
api/src/functions/graphql.ts
Normal file → Executable file
0
api/src/graphql/.keep
Normal file → Executable file
0
api/src/graphql/.keep
Normal file → Executable file
0
api/src/graphql/portrait.sdl.ts
Normal file → Executable file
0
api/src/graphql/portrait.sdl.ts
Normal file → Executable file
0
api/src/graphql/projects.sdl.ts
Normal file → Executable file
0
api/src/graphql/projects.sdl.ts
Normal file → Executable file
0
api/src/graphql/resume.sdl.ts
Normal file → Executable file
0
api/src/graphql/resume.sdl.ts
Normal file → Executable file
0
api/src/graphql/scalars.sdl.ts
Normal file → Executable file
0
api/src/graphql/scalars.sdl.ts
Normal file → Executable file
0
api/src/graphql/socials.sdl.ts
Normal file → Executable file
0
api/src/graphql/socials.sdl.ts
Normal file → Executable file
0
api/src/graphql/tags.sdl.ts
Normal file → Executable file
0
api/src/graphql/tags.sdl.ts
Normal file → Executable file
0
api/src/graphql/title.sdl.ts
Normal file → Executable file
0
api/src/graphql/title.sdl.ts
Normal file → Executable file
0
api/src/lib/auth.ts
Normal file → Executable file
0
api/src/lib/auth.ts
Normal file → Executable file
0
api/src/lib/cors.ts
Normal file → Executable file
0
api/src/lib/cors.ts
Normal file → Executable file
0
api/src/lib/db.ts
Normal file → Executable file
0
api/src/lib/db.ts
Normal file → Executable file
0
api/src/lib/email.ts
Normal file → Executable file
0
api/src/lib/email.ts
Normal file → Executable file
0
api/src/lib/logger.ts
Normal file → Executable file
0
api/src/lib/logger.ts
Normal file → Executable file
6
api/src/lib/tus.ts
Normal file → Executable file
6
api/src/lib/tus.ts
Normal file → Executable file
@ -19,7 +19,7 @@ interface User {
|
|||||||
resetTokenExpiresAt: Date | null
|
resetTokenExpiresAt: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleTusUpload = (
|
export const handleTusUpload = async (
|
||||||
req: FastifyRequest,
|
req: FastifyRequest,
|
||||||
res: FastifyReply,
|
res: FastifyReply,
|
||||||
tusHandler: Server,
|
tusHandler: Server,
|
||||||
@ -28,7 +28,7 @@ export const handleTusUpload = (
|
|||||||
if (isProduction) {
|
if (isProduction) {
|
||||||
if (req.method === 'OPTIONS') handleOptionsRequest(res)
|
if (req.method === 'OPTIONS') handleOptionsRequest(res)
|
||||||
else if (isPublicEndpoint && req.method === 'GET')
|
else if (isPublicEndpoint && req.method === 'GET')
|
||||||
tusHandler.handle(req.raw, res.raw)
|
await tusHandler.handle(req.raw, res.raw)
|
||||||
else if (['GET', 'POST', 'HEAD', 'PATCH'].includes(req.method)) {
|
else if (['GET', 'POST', 'HEAD', 'PATCH'].includes(req.method)) {
|
||||||
if (req.headers.cookie) handleAuthenticatedRequest(req, res, tusHandler)
|
if (req.headers.cookie) handleAuthenticatedRequest(req, res, tusHandler)
|
||||||
else {
|
else {
|
||||||
@ -41,7 +41,7 @@ export const handleTusUpload = (
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setCorsHeaders(res)
|
setCorsHeaders(res)
|
||||||
tusHandler.handle(req.raw, res.raw)
|
await tusHandler.handle(req.raw, res.raw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
api/src/server.ts
Normal file → Executable file
11
api/src/server.ts
Normal file → Executable file
@ -1,8 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import Cors from '@fastify/cors'
|
import Cors from '@fastify/cors'
|
||||||
import RateLimit from '@fastify/rate-limit'
|
import RateLimit from '@fastify/rate-limit'
|
||||||
import { FileStore } from '@tus/file-store'
|
|
||||||
import { Server } from '@tus/server'
|
|
||||||
|
|
||||||
import { isProduction } from '@redwoodjs/api/logger'
|
import { isProduction } from '@redwoodjs/api/logger'
|
||||||
import { createServer } from '@redwoodjs/api-server'
|
import { createServer } from '@redwoodjs/api-server'
|
||||||
@ -17,6 +15,8 @@ enum Theme {
|
|||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
const { countries } = await import('countries-list')
|
const { countries } = await import('countries-list')
|
||||||
|
const { FileStore } = await import('@tus/file-store')
|
||||||
|
const { Server } = await import('@tus/server')
|
||||||
|
|
||||||
if (!Object.keys(countries).includes(process.env.COUNTRY))
|
if (!Object.keys(countries).includes(process.env.COUNTRY))
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -28,6 +28,8 @@ enum Theme {
|
|||||||
'Invalid DEFAULT_THEME environment variable, please select either light or dark'
|
'Invalid DEFAULT_THEME environment variable, please select either light or dark'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger.info(`Portfolio ${process.env.APP_VERSION}`)
|
||||||
|
|
||||||
const server = await createServer({
|
const server = await createServer({
|
||||||
logger,
|
logger,
|
||||||
configureApiServer: async (server) => {
|
configureApiServer: async (server) => {
|
||||||
@ -52,7 +54,10 @@ enum Theme {
|
|||||||
datastore: new FileStore({
|
datastore: new FileStore({
|
||||||
directory: `./files_${isProduction ? 'prod' : 'dev'}`,
|
directory: `./files_${isProduction ? 'prod' : 'dev'}`,
|
||||||
}),
|
}),
|
||||||
onResponseError: (_req, res, _err) => logger.error(res),
|
onResponseError(_, err) {
|
||||||
|
logger.error(err)
|
||||||
|
return { status_code: 500, body: 'Internal Server Error' }
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
server.addContentTypeParser(
|
server.addContentTypeParser(
|
||||||
|
0
api/src/services/.keep
Normal file → Executable file
0
api/src/services/.keep
Normal file → Executable file
0
api/src/services/portrait/portrait.ts
Normal file → Executable file
0
api/src/services/portrait/portrait.ts
Normal file → Executable file
0
api/src/services/projects/projects.ts
Normal file → Executable file
0
api/src/services/projects/projects.ts
Normal file → Executable file
0
api/src/services/resume/resume.ts
Normal file → Executable file
0
api/src/services/resume/resume.ts
Normal file → Executable file
0
api/src/services/socials/socials.ts
Normal file → Executable file
0
api/src/services/socials/socials.ts
Normal file → Executable file
0
api/src/services/tags/tags.ts
Normal file → Executable file
0
api/src/services/tags/tags.ts
Normal file → Executable file
0
api/src/services/title/title.ts
Normal file → Executable file
0
api/src/services/title/title.ts
Normal file → Executable file
4
api/tsconfig.json
Normal file → Executable file
4
api/tsconfig.json
Normal file → Executable file
@ -4,8 +4,8 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"target": "ES2023",
|
"target": "ES2023",
|
||||||
"module": "Node16",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "Node16",
|
"moduleResolution": "nodenext",
|
||||||
"skipLibCheck": false,
|
"skipLibCheck": false,
|
||||||
"rootDirs": [
|
"rootDirs": [
|
||||||
"./src",
|
"./src",
|
||||||
|
13
docker-compose.yml
Normal file → Executable file
13
docker-compose.yml
Normal file → Executable file
@ -4,6 +4,7 @@ services:
|
|||||||
portfolio:
|
portfolio:
|
||||||
container_name: portfolio
|
container_name: portfolio
|
||||||
image: git.altaiar.dev/ahmed/portfolio:latest
|
image: git.altaiar.dev/ahmed/portfolio:latest
|
||||||
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- API_PROXY_TARGET=http://localhost:8911
|
- API_PROXY_TARGET=http://localhost:8911
|
||||||
@ -32,7 +33,8 @@ services:
|
|||||||
- 8910:8910 # Web
|
- 8910:8910 # Web
|
||||||
- 8911:8911 # API
|
- 8911:8911 # API
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
db:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- files:/home/node/app/api/files_prod
|
- files:/home/node/app/api/files_prod
|
||||||
command: >
|
command: >
|
||||||
@ -42,14 +44,19 @@ services:
|
|||||||
yarn rw prisma db seed &&
|
yarn rw prisma db seed &&
|
||||||
yarn rw serve"
|
yarn rw serve"
|
||||||
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
container_name: portfolio-db
|
container_name: portfolio-db
|
||||||
image: postgres:16-bookworm
|
image: postgres:16-bookworm
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=redwood
|
- POSTGRES_USER=redwood
|
||||||
- POSTGRES_PASSWORD=changeme
|
- POSTGRES_PASSWORD=changeme # Change to a more secure password
|
||||||
- POSTGRES_DB=portfolio
|
- POSTGRES_DB=portfolio
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -d DATABASE_URL"] # Replace DATABASE_URL with the database URL from the portfolio container
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
volumes:
|
volumes:
|
||||||
- postgres:/var/lib/postgresql/data
|
- postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
0
graphql.config.js
Normal file → Executable file
0
graphql.config.js
Normal file → Executable file
0
jest.config.js
Normal file → Executable file
0
jest.config.js
Normal file → Executable file
0
package.json
Normal file → Executable file
0
package.json
Normal file → Executable file
0
prettier.config.mjs
Normal file → Executable file
0
prettier.config.mjs
Normal file → Executable file
2
redwood.toml
Normal file → Executable file
2
redwood.toml
Normal file → Executable file
@ -9,7 +9,7 @@
|
|||||||
title = "${FIRST_NAME} ${LAST_NAME}"
|
title = "${FIRST_NAME} ${LAST_NAME}"
|
||||||
port = 8910
|
port = 8910
|
||||||
apiUrl = "/api"
|
apiUrl = "/api"
|
||||||
includeEnvironmentVariables = ["FIRST_NAME", "LAST_NAME", "COUNTRY", "STATE", "CITY", "DEFAULT_THEME", "API_ADDRESS_PROD", "API_ADDRESS_DEV"]
|
includeEnvironmentVariables = ["FIRST_NAME", "LAST_NAME", "COUNTRY", "STATE", "CITY", "DEFAULT_THEME", "API_ADDRESS_PROD", "API_ADDRESS_DEV", "APP_VERSION"]
|
||||||
[generate]
|
[generate]
|
||||||
tests = false
|
tests = false
|
||||||
stories = false
|
stories = false
|
||||||
|
0
scripts/.keep
Normal file → Executable file
0
scripts/.keep
Normal file → Executable file
0
scripts/seed.ts
Normal file → Executable file
0
scripts/seed.ts
Normal file → Executable file
0
scripts/tsconfig.json
Normal file → Executable file
0
scripts/tsconfig.json
Normal file → Executable file
0
web/config/postcss.config.js
Normal file → Executable file
0
web/config/postcss.config.js
Normal file → Executable file
0
web/config/tailwind.config.js
Normal file → Executable file
0
web/config/tailwind.config.js
Normal file → Executable file
0
web/jest.config.js
Normal file → Executable file
0
web/jest.config.js
Normal file → Executable file
3
web/package.json
Normal file → Executable file
3
web/package.json
Normal file → Executable file
@ -41,7 +41,8 @@
|
|||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-html-parser": "^2.0.2"
|
"react-html-parser": "^2.0.2",
|
||||||
|
"react-pdf": "^9.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@redwoodjs/vite": "8.4.0",
|
"@redwoodjs/vite": "8.4.0",
|
||||||
|
0
web/public/README.md
Normal file → Executable file
0
web/public/README.md
Normal file → Executable file
0
web/public/favicon.png
Normal file → Executable file
0
web/public/favicon.png
Normal file → Executable file
Before Width: | Height: | Size: 757 B After Width: | Height: | Size: 757 B |
0
web/public/no_portrait.webp
Normal file → Executable file
0
web/public/no_portrait.webp
Normal file → Executable file
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
0
web/public/no_resume.pdf
Normal file → Executable file
0
web/public/no_resume.pdf
Normal file → Executable file
0
web/public/robots.txt
Normal file → Executable file
0
web/public/robots.txt
Normal file → Executable file
0
web/quick-lint-js.config
Normal file → Executable file
0
web/quick-lint-js.config
Normal file → Executable file
0
web/src/App.tsx
Normal file → Executable file
0
web/src/App.tsx
Normal file → Executable file
0
web/src/Routes.tsx
Normal file → Executable file
0
web/src/Routes.tsx
Normal file → Executable file
0
web/src/auth.ts
Normal file → Executable file
0
web/src/auth.ts
Normal file → Executable file
0
web/src/components/.keep
Normal file → Executable file
0
web/src/components/.keep
Normal file → Executable file
0
web/src/components/Cell/CellEmpty/CellEmpty.tsx
Normal file → Executable file
0
web/src/components/Cell/CellEmpty/CellEmpty.tsx
Normal file → Executable file
0
web/src/components/Cell/CellFailure/CellFailure.tsx
Normal file → Executable file
0
web/src/components/Cell/CellFailure/CellFailure.tsx
Normal file → Executable file
0
web/src/components/Cell/CellLoading/CellLoading.tsx
Normal file → Executable file
0
web/src/components/Cell/CellLoading/CellLoading.tsx
Normal file → Executable file
0
web/src/components/ColorPicker/ColorPicker.tsx
Normal file → Executable file
0
web/src/components/ColorPicker/ColorPicker.tsx
Normal file → Executable file
0
web/src/components/ContactCard/ContactCard/ContactCard.tsx
Normal file → Executable file
0
web/src/components/ContactCard/ContactCard/ContactCard.tsx
Normal file → Executable file
0
web/src/components/ContactCard/ContactCardCell/ContactCardCell.tsx
Normal file → Executable file
0
web/src/components/ContactCard/ContactCardCell/ContactCardCell.tsx
Normal file → Executable file
0
web/src/components/DatePicker/DatePicker.tsx
Normal file → Executable file
0
web/src/components/DatePicker/DatePicker.tsx
Normal file → Executable file
0
web/src/components/FormTextList/FormTextList.tsx
Normal file → Executable file
0
web/src/components/FormTextList/FormTextList.tsx
Normal file → Executable file
50
web/src/components/PDF/PDF.tsx
Normal file → Executable file
50
web/src/components/PDF/PDF.tsx
Normal file → Executable file
@ -1,7 +1,14 @@
|
|||||||
|
import { mdiOpenInNew } from '@mdi/js';
|
||||||
|
import Icon from '@mdi/react';
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { Document, Page as PdfPage, pdfjs } from "react-pdf";
|
||||||
|
import "react-pdf/dist/Page/AnnotationLayer.css";
|
||||||
|
import "react-pdf/dist/Page/TextLayer.css";
|
||||||
|
|
||||||
import { mdiAlertOutline } from '@mdi/js'
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||||
import Icon from '@mdi/react'
|
"pdfjs-dist/build/pdf.worker.min.mjs",
|
||||||
|
import.meta.url
|
||||||
|
).toString();
|
||||||
|
|
||||||
interface PDFProps {
|
interface PDFProps {
|
||||||
url: string
|
url: string
|
||||||
@ -9,28 +16,33 @@ interface PDFProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PDF = ({ url, form = false }: PDFProps) => {
|
const PDF = ({ url, form = false }: PDFProps) => {
|
||||||
const [error, setError] = useState<boolean>(false)
|
const [numPages, setNumPages] = useState<number>(0);
|
||||||
|
function onLoadSuccess({ numPages }: { numPages: number }) {
|
||||||
|
setNumPages(numPages);
|
||||||
|
}
|
||||||
|
|
||||||
return error ? (
|
return (
|
||||||
<div role="alert" className="alert alert-warning">
|
<div
|
||||||
<Icon path={mdiAlertOutline} className="size-7" />
|
className="overflow-y-auto flex justify-center"
|
||||||
<span>
|
|
||||||
Could not load PDF, this is common in in-app browsers, try opening this
|
|
||||||
page in a regular browser
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<iframe
|
|
||||||
src={url}
|
|
||||||
title="PDF"
|
|
||||||
style={{
|
style={{
|
||||||
width: 'calc(100vw - 1rem)',
|
width: 'calc(100vw - 1rem)',
|
||||||
height: `calc(100vh - ${form ? '8.5rem' : '6rem'})`,
|
height: `calc(100vh - ${form ? '8.5rem' : '6rem'})`,
|
||||||
}}
|
}}
|
||||||
className="rounded-xl"
|
>
|
||||||
onError={() => setError(true)}
|
<a
|
||||||
onLoad={() => setError(false)}
|
href={url}
|
||||||
/>
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="fixed top-20 left-0 z-10 m-2 p-2 rounded-xl btn btn-square btn-ghost shadow-lg"
|
||||||
|
>
|
||||||
|
<Icon path={mdiOpenInNew} size={1} className="text-gray-600" />
|
||||||
|
</a>
|
||||||
|
<Document file={url} onLoadSuccess={onLoadSuccess}>
|
||||||
|
{Array.from({ length: numPages }, (_, i) => (
|
||||||
|
<PdfPage key={i} pageNumber={i + 1} width={800} />
|
||||||
|
))}
|
||||||
|
</Document>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
web/src/components/Portrait/PortraitCell/PortraitCell.tsx
Normal file → Executable file
0
web/src/components/Portrait/PortraitCell/PortraitCell.tsx
Normal file → Executable file
0
web/src/components/Portrait/PortraitForm/PortraitForm.tsx
Normal file → Executable file
0
web/src/components/Portrait/PortraitForm/PortraitForm.tsx
Normal file → Executable file
0
web/src/components/Project/AdminProject/AdminProject.tsx
Normal file → Executable file
0
web/src/components/Project/AdminProject/AdminProject.tsx
Normal file → Executable file
0
web/src/components/Project/AdminProjectCell/AdminProjectCell.tsx
Normal file → Executable file
0
web/src/components/Project/AdminProjectCell/AdminProjectCell.tsx
Normal file → Executable file
0
web/src/components/Project/EditProjectCell/EditProjectCell.tsx
Normal file → Executable file
0
web/src/components/Project/EditProjectCell/EditProjectCell.tsx
Normal file → Executable file
0
web/src/components/Project/NewProject/NewProject.tsx
Normal file → Executable file
0
web/src/components/Project/NewProject/NewProject.tsx
Normal file → Executable file
0
web/src/components/Project/Project/Project.tsx
Normal file → Executable file
0
web/src/components/Project/Project/Project.tsx
Normal file → Executable file
0
web/src/components/Project/ProjectCell/ProjectCell.tsx
Normal file → Executable file
0
web/src/components/Project/ProjectCell/ProjectCell.tsx
Normal file → Executable file
0
web/src/components/Project/ProjectForm/ProjectForm.tsx
Normal file → Executable file
0
web/src/components/Project/ProjectForm/ProjectForm.tsx
Normal file → Executable file
0
web/src/components/Project/Projects/Projects.tsx
Normal file → Executable file
0
web/src/components/Project/Projects/Projects.tsx
Normal file → Executable file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user