diff --git a/.env.example b/.env.example index d392240..3b35e1d 100644 --- a/.env.example +++ b/.env.example @@ -11,9 +11,8 @@ JWT_REFRESH_SECRET=change_me_refresh # Telegram bot TG_BOT_TOKEN=123456:ABC-DEF TEACHER_CODE=SECRET - -# Platform address used by bot to create links (inside docker-compose use web service) -PLATFORM_ADDRESS=http://web:80 +PLATFORM_ADDRESS_SERVER=http://server:3000 +PLATFORM_ADDRESS_CLIENT=http://localhost:8080 # CORS CORS_ORIGIN=* diff --git a/.github/workflows/DEV.yml b/.github/workflows/DEV.yml deleted file mode 100644 index a39feb5..0000000 --- a/.github/workflows/DEV.yml +++ /dev/null @@ -1,170 +0,0 @@ -name: DEV workflow - -on: - push: - branches: - - DEV -jobs: - build_and_push_front_to_docker_hub: - name: Push Docker frontend image to DockerHub - runs-on: ubuntu-latest - steps: - - name: Check out the repo - uses: actions/checkout@v4 - with: - ref: "DEV" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - name: Login to Docker - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Push to DockerHub - uses: docker/build-push-action@v5.3.0 - with: - context: ./ - file: client/Dockerfile - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/frontend:DEV - - build_and_push_users_to_docker_hub: - name: Push Docker Users image to DockerHub - runs-on: ubuntu-latest - steps: - - name: Check out the repo - uses: actions/checkout@v4 - with: - ref: "DEV" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - name: Login to Docker - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Push to DockerHub - uses: docker/build-push-action@v5.3.0 - with: - context: ./users - file: users/Dockerfile - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/backend-users:DEV - - build_and_push_tests_to_docker_hub: - name: Push Docker tests image to DockerHub - runs-on: ubuntu-latest - steps: - - name: Check out the repo - uses: actions/checkout@v4 - with: - ref: "DEV" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - name: Login to Docker - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Push to DockerHub - uses: docker/build-push-action@v5.3.0 - with: - context: ./tests - file: tests/Dockerfile - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/backend-tests:DEV - - build_and_push_subjects_to_docker_hub: - name: Push Docker subjects image to DockerHub - runs-on: ubuntu-latest - steps: - - name: Check out the repo - uses: actions/checkout@v4 - with: - ref: "DEV" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - name: Login to Docker - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Push to DockerHub - uses: docker/build-push-action@v5.3.0 - with: - context: ./subjects - file: subjects/docker/dev/Dockerfile - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/backend-subjects:DEV - - build_and_push_analytics_to_docker_hub: - name: Push Docker analytics image to DockerHub - runs-on: ubuntu-latest - steps: - - name: Check out the repo - uses: actions/checkout@v4 - with: - ref: "DEV" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - name: Login to Docker - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Push to DockerHub - uses: docker/build-push-action@v5.3.0 - with: - context: ./analytics - file: analytics/Dockerfile - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/backend-analytics:DEV - - deploy: - name: Деплой на сервер - runs-on: ubuntu-latest - needs: - - build_and_push_subjects_to_docker_hub - - build_and_push_users_to_docker_hub - - build_and_push_tests_to_docker_hub - - build_and_push_analytics_to_docker_hub - - build_and_push_front_to_docker_hub - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - name: Executing remote ssh commands to stop docker, clean up - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST }} - username: ${{ secrets.USER }} - password: ${{ secrets.SSH_PASSPHRASE }} - script: | - docker compose -f DEV/compose/docker-compose-DH-DEV.yml down || true - docker volume rm compose-dev_static || true - cp -r DEV/compose/env ./env || true - rm -rf DEV || true - mkdir -p DEV/compose - mv ./env DEV/compose || true - - name: Copy compose via ssh - uses: appleboy/scp-action@master - with: - host: ${{ secrets.HOST }} - username: ${{ secrets.USER }} - password: ${{ secrets.SSH_PASSPHRASE }} - source: "compose" - target: "DEV" - - name: Executing remote ssh commands to deploy - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOST }} - username: ${{ secrets.USER }} - password: ${{ secrets.SSH_PASSPHRASE }} - script: | - mkdir DEV/dbs - touch DEV/dbs/users_db.sqlite3 - touch DEV/dbs/tests_db.sqlite3 - touch DEV/dbs/subjects_db.sqlite3 - touch DEV/dbs/analytics_db.sqlite3 - docker compose -f DEV/compose/docker-compose-DH-DEV.yml pull - docker compose -f DEV/compose/docker-compose-DH-DEV.yml up --build -d - docker system prune -af diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 691bfbf..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,28 +0,0 @@ - -name: MAIN workflow - -on: - push: - branches: - - main -jobs: - build_and_push_front_to_docker_hub: - name: Push Docker frontend image to DockerHub - runs-on: ubuntu-latest - steps: - - name: Check out the repo - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - name: Login to Docker - uses: docker/login-action@v3.1.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Push to DockerHub - uses: docker/build-push-action@v5.3.0 - with: - context: ./ - file: client/Dockerfile - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/frontend:PROD \ No newline at end of file diff --git a/.github/workflows/practika.yml b/.github/workflows/practika.yml index c384f02..2a6be8e 100644 --- a/.github/workflows/practika.yml +++ b/.github/workflows/practika.yml @@ -2,64 +2,125 @@ name: Build and Publish on: push: - branches: [ "practika-develop" ] + branches: ["practika-develop", "develop"] jobs: build-server: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push Server - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: ./server push: true tags: ${{ secrets.DOCKER_USERNAME }}/eduplatform-server:latest + cache-from: type=gha + cache-to: type=gha,mode=max build-web: + needs: build-server runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push Web - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: ./frontend file: frontend/packages/web/Dockerfile push: true tags: ${{ secrets.DOCKER_USERNAME }}/eduplatform-web:latest + cache-from: type=gha + cache-to: type=gha,mode=max build-admin: + needs: build-web runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v3 - + - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Build and Push Admin - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: ./frontend file: frontend/packages/admin/Dockerfile push: true - tags: ${{ secrets.DOCKER_USERNAME }}/eduplatform-admin:latest \ No newline at end of file + tags: ${{ secrets.DOCKER_USERNAME }}/eduplatform-admin:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + build-tgbot: + needs: build-admin + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Build and Push Bot + uses: docker/build-push-action@v5 + with: + context: ./tgbot + push: true + tags: ${{ secrets.DOCKER_USERNAME }}/eduplatform-tgbot:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + deploy-to-new-vm: + needs: build-tgbot + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Copy compose via ssh + uses: appleboy/scp-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USER }} + password: ${{ secrets.SSH_PASSPHRASE }} + source: "docker-compose.yml" + target: "eduplatform/" + - name: Deploy via SSH + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USER }} + password: ${{ secrets.SSH_PASSPHRASE }} + script: | + cd ~/eduplatform + + docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} + + export DOCKER_USERNAME=${{ secrets.DOCKER_USERNAME }} + + docker compose down || true + + docker compose pull + + docker compose up -d --remove-orphans + + docker system prune -af diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index a08331a..0000000 --- a/Dockerfile +++ /dev/null @@ -1,64 +0,0 @@ -# Multi-stage Dockerfile -# Builder: build frontends (pnpm) and server (npm) -FROM node:18-bullseye AS builder -WORKDIR /build - -# Install pnpm (via corepack) for frontend workspace builds -RUN corepack enable && corepack prepare pnpm@latest --activate - -# Copy frontend workspace and build -COPY frontend ./frontend -WORKDIR /build/frontend -RUN pnpm install --frozen-lockfile --network-concurrency 1 || pnpm install -RUN pnpm run build:all - -# Build server -WORKDIR /build -COPY server ./server -WORKDIR /build/server -RUN npm ci --no-audit --no-fund -RUN npm run build - -# Keep server node_modules to avoid re-install in final image - -# Final image: runtime with node + python for bot -FROM node:18-bullseye-slim - -ENV NODE_ENV=production - -WORKDIR /app - -# Install python for bot -RUN apt-get update && apt-get install -y --no-install-recommends \ - python3 python3-pip ca-certificates curl \ - && rm -rf /var/lib/apt/lists/* - -# Install static server "serve" globally -RUN npm install -g serve@14.2.0 - -# Copy built frontends from builder -COPY --from=builder /build/frontend/packages/web/dist /app/web -COPY --from=builder /build/frontend/packages/admin/dist /app/admin - -# Copy server build and node_modules from builder -COPY --from=builder /build/server/dist /app/server/dist -COPY --from=builder /build/server/node_modules /app/server/node_modules -COPY --from=builder /build/server/package.json /app/server/package.json - -# Copy bot sources -COPY tgbot /app/tgbot - -# Install python dependencies for bot -RUN pip3 install --no-cache-dir pytelegrambotapi requests python-dotenv - -# Copy entrypoint script -COPY docker-entrypoint.sh /app/docker-entrypoint.sh -RUN chmod +x /app/docker-entrypoint.sh - -# Expose ports: web (8888), admin (9999), server (3000) -EXPOSE 8888 9999 3000 - -HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ - CMD curl -f http://localhost:3000/graphql || exit 1 - -ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/Dockerfile.bot b/Dockerfile.bot deleted file mode 100644 index e9f295a..0000000 --- a/Dockerfile.bot +++ /dev/null @@ -1,10 +0,0 @@ -FROM python:3.11-slim -WORKDIR /app/tgbot - -RUN pip3 install --no-cache-dir pytelegrambotapi requests python-dotenv || true - -COPY tgbot ./ - -ENV PYTHONUNBUFFERED=1 - -CMD ["python3", "uni_eduplatform_bot.py"] diff --git a/Dockerfile.frontend b/Dockerfile.frontend deleted file mode 100644 index 02c3679..0000000 --- a/Dockerfile.frontend +++ /dev/null @@ -1,29 +0,0 @@ -ARG APP=web -FROM node:20-bullseye AS builder -WORKDIR /build - -RUN corepack enable && corepack prepare pnpm@latest --activate - -COPY frontend ./frontend -WORKDIR /build/frontend -# Create pnpm workspace file so pnpm recognizes workspaces in the frontend monorepo -RUN printf "packages:\n - 'packages/*'\n" > pnpm-workspace.yaml -# Run pnpm in CI mode inside the container to avoid TTY removal errors -ENV CI=true -# Allow installing even if lockfile is out of date inside the container. In CI you may want to keep frozen-lockfile=true -# but building directly from the repo may require updating lockfile here. -RUN pnpm install --no-frozen-lockfile --network-concurrency 1 --link-workspace-packages=true - -# Build only the requested app (web or admin) -ARG APP -RUN pnpm --filter ${APP} build - -FROM nginx:stable-alpine -ARG APP -COPY --from=builder /build/frontend/packages/${APP}/dist /usr/share/nginx/html - -# Default nginx conf (serve static) -COPY nginx/${APP}.conf /etc/nginx/conf.d/default.conf - -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] diff --git a/Dockerfile.server b/Dockerfile.server deleted file mode 100644 index a8e9583..0000000 --- a/Dockerfile.server +++ /dev/null @@ -1,32 +0,0 @@ -### Builder stage: install deps and build server -FROM node:18-bullseye AS builder -WORKDIR /build/server - -# Install dependencies (including dev deps so prisma CLI is available) -COPY server/package.json server/package-lock.json* ./ -RUN npm ci --no-audit --no-fund || npm install - -COPY server ./ -# generate prisma client from schema so types (models) are available during build -RUN npx prisma generate - -RUN npm run build - -### Final runtime image -FROM node:18-bullseye-slim -WORKDIR /app/server - -# copy built app and node_modules from builder -COPY --from=builder /build/server/dist ./dist -COPY --from=builder /build/server/node_modules ./node_modules -COPY --from=builder /build/server/package.json ./package.json - -# copy prisma schema and migrations so `prisma migrate deploy` can find them -COPY --from=builder /build/server/prisma ./prisma - -# entrypoint to run migrations then start server -COPY docker-entrypoint-server.sh /app/server/docker-entrypoint-server.sh -RUN chmod +x /app/server/docker-entrypoint-server.sh - -EXPOSE 3000 -CMD ["/app/server/docker-entrypoint-server.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 06ff7f9..cf34693 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,35 +3,47 @@ version: "3.8" services: db: image: postgres:15-alpine - environment: - POSTGRES_DB: ${POSTGRES_DB:-quiz} - POSTGRES_USER: ${POSTGRES_USER:-quiz} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-quiz} + container_name: edu_postgres + env_file: + - .env volumes: - - db-data:/var/lib/postgresql/data + - postgres_data:/var/lib/postgresql/data ports: - "5432:5432" networks: - quiznet healthcheck: - test: - [ - "CMD-SHELL", - "pg_isready -U ${POSTGRES_USER:-quiz} -d ${POSTGRES_DB:-quiz}", - ] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-quizuser} -d ${POSTGRES_DB:-quiz}"] interval: 5s timeout: 5s retries: 5 restart: unless-stopped - server: - build: - context: . - dockerfile: Dockerfile.server + pgbackups: + image: prodrigestivill/postgres-backup-local + container_name: edu_pgbackups + restart: unless-stopped env_file: - .env environment: - - NODE_ENV=production + POSTGRES_HOST: db + SCHEDULE: "@daily" + BACKUP_KEEP_DAYS: 7 + BACKUP_KEEP_WEEKS: 3 + BACKUP_KEEP_MONTHS: 6 + networks: + - quiznet + volumes: + - ./backups:/backups + depends_on: + db: + condition: service_healthy + + server: + image: ${DOCKER_USERNAME}/eduplatform-server:latest + container_name: edu_server + env_file: + - .env ports: - "3000:3000" networks: @@ -39,14 +51,13 @@ services: depends_on: db: condition: service_healthy + command: > + sh -c "npx prisma migrate deploy && node dist/main.js" restart: unless-stopped web: - build: - context: . - dockerfile: Dockerfile.frontend - args: - APP: web + image: ${DOCKER_USERNAME}/eduplatform-web:latest + container_name: edu_web ports: - "8888:80" networks: @@ -56,11 +67,8 @@ services: restart: unless-stopped admin: - build: - context: . - dockerfile: Dockerfile.frontend - args: - APP: admin + image: ${DOCKER_USERNAME}/eduplatform-admin:latest + container_name: edu_admin ports: - "9999:80" networks: @@ -70,13 +78,10 @@ services: restart: unless-stopped bot: - build: - context: . - dockerfile: Dockerfile.bot + image: ${DOCKER_USERNAME}/eduplatform-tgbot:latest + container_name: edu_tgbot env_file: - .env - environment: - - PLATFORM_ADDRESS=http://web:80 networks: - quiznet depends_on: @@ -88,4 +93,4 @@ networks: driver: bridge volumes: - db-data: + postgres_data: \ No newline at end of file diff --git a/docker-entrypoint-server.sh b/docker-entrypoint-server.sh deleted file mode 100644 index 58e4d1e..0000000 --- a/docker-entrypoint-server.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "Running prisma migrations (deploy) if DATABASE_URL is set..." -if [ -n "${DATABASE_URL:-}" ]; then - # run migrations (requires prisma available in node_modules from builder) - echo "DATABASE_URL present, running: npx prisma migrate deploy" - npx prisma migrate deploy || echo "prisma migrate deploy exit code $?"; -else - echo "DATABASE_URL not set, skipping migrations" -fi - -echo "Starting server..." -node dist/main.js diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh deleted file mode 100644 index ab15d4c..0000000 --- a/docker-entrypoint.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Start server, static frontends and telegram bot in background and wait. -# This is a simple supervisor; for production consider using a proper process manager. - -echo "Starting services..." - -# Start Node server -if [ -f /app/server/dist/main.js ]; then - echo "Starting Node server (server)..." - node /app/server/dist/main.js & - PID_SERVER=$! -else - echo "Warning: server dist not found at /app/server/dist/main.js" - PID_SERVER=0 -fi - -# Start web frontend (serve) -if [ -d /app/web ]; then - echo "Starting web frontend on :8888" - serve -s /app/web -l 8888 & - PID_WEB=$! -else - echo "Warning: web build not found at /app/web" - PID_WEB=0 -fi - -# Start admin frontend (serve) -if [ -d /app/admin ]; then - echo "Starting admin frontend on :9999" - serve -s /app/admin -l 9999 & - PID_ADMIN=$! -else - echo "Warning: admin build not found at /app/admin" - PID_ADMIN=0 -fi - -# Start Telegram bot -if [ -f /app/tgbot/uni_eduplatform_bot.py ]; then - echo "Starting Telegram bot" - python3 /app/tgbot/uni_eduplatform_bot.py & - PID_BOT=$! -else - echo "Warning: bot script not found at /app/tgbot/uni_eduplatform_bot.py" - PID_BOT=0 -fi - -shutdown() { - echo "Shutting down..." - set +e - if [ "$PID_BOT" != "0" ]; then kill -TERM "$PID_BOT" 2>/dev/null || true; fi - if [ "$PID_ADMIN" != "0" ]; then kill -TERM "$PID_ADMIN" 2>/dev/null || true; fi - if [ "$PID_WEB" != "0" ]; then kill -TERM "$PID_WEB" 2>/dev/null || true; fi - if [ "$PID_SERVER" != "0" ]; then kill -TERM "$PID_SERVER" 2>/dev/null || true; fi - wait - exit 0 -} - -trap shutdown SIGINT SIGTERM - -echo "All services started. Waiting..." - -# Wait indefinitely while background processes run -while true; do - # If any background process died, exit with non-zero to allow container restart - if [ "$PID_SERVER" != "0" ] && ! kill -0 "$PID_SERVER" 2>/dev/null; then echo "Server exited"; exit 1; fi - if [ "$PID_WEB" != "0" ] && ! kill -0 "$PID_WEB" 2>/dev/null; then echo "Web server exited"; exit 1; fi - if [ "$PID_ADMIN" != "0" ] && ! kill -0 "$PID_ADMIN" 2>/dev/null; then echo "Admin server exited"; exit 1; fi - if [ "$PID_BOT" != "0" ] && ! kill -0 "$PID_BOT" 2>/dev/null; then echo "Bot exited"; exit 1; fi - sleep 5 -done diff --git a/frontend/packages/admin/Dockerfile b/frontend/packages/admin/Dockerfile index ecd0492..94bfd2b 100644 --- a/frontend/packages/admin/Dockerfile +++ b/frontend/packages/admin/Dockerfile @@ -4,11 +4,6 @@ WORKDIR /app COPY package.json ./ -RUN echo "packages:" > pnpm-workspace.yaml && \ - echo " - 'packages/*'" >> pnpm-workspace.yaml - -COPY package.json ./ - RUN echo "packages:" > pnpm-workspace.yaml && \ echo " - 'packages/*'" >> pnpm-workspace.yaml @@ -20,6 +15,7 @@ COPY packages ./packages RUN pnpm install +ENV NODE_OPTIONS="--max-old-space-size=4096" RUN pnpm --filter admin build FROM nginx:alpine diff --git a/frontend/packages/ui/src/hooks/useApollo.ts b/frontend/packages/ui/src/hooks/useApollo.ts index 1c7e2f8..01115d3 100644 --- a/frontend/packages/ui/src/hooks/useApollo.ts +++ b/frontend/packages/ui/src/hooks/useApollo.ts @@ -6,13 +6,16 @@ import { onError } from '@apollo/client/link/error'; // Single-flight refresh promise to avoid concurrent refresh requests let refreshPromise: Promise | null = null; +const { protocol, hostname } = window.location; +const graphqlUrl = `http://${hostname}:3000/graphql`; + export const refreshAccessTokenViaCookie = async (): Promise => { if (refreshPromise) return refreshPromise; refreshPromise = (async () => { try { - const clientId = import.meta.env.VITE_CLIENT_ID || 'web'; - const res = await fetch(import.meta.env.VITE_GRAPHQL_URL || 'http://localhost:3000/graphql', { + const clientId = 'web'; + const res = await fetch(graphqlUrl, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', 'x-client-id': clientId }, @@ -34,13 +37,13 @@ export const refreshAccessTokenViaCookie = async (): Promise => { }; const httpLink = createHttpLink({ - uri: import.meta.env.VITE_GRAPHQL_URL || 'http://localhost:3000/graphql', + uri: graphqlUrl, credentials: 'include', // send cookies (refresh token) with requests }); const authLink = setContext((_, { headers }) => { const token = getAccessToken(); - const clientId = import.meta.env.VITE_CLIENT_ID || 'web'; + const clientId = 'web'; return { headers: { ...headers, diff --git a/frontend/packages/web/Dockerfile b/frontend/packages/web/Dockerfile index 7067573..7d920d9 100644 --- a/frontend/packages/web/Dockerfile +++ b/frontend/packages/web/Dockerfile @@ -13,10 +13,9 @@ RUN echo "link-workspace-packages=true" > .npmrc && \ COPY packages ./packages -RUN ls -la packages/ui/package.json - RUN pnpm install +ENV NODE_OPTIONS="--max-old-space-size=4096" RUN pnpm --filter web build FROM nginx:alpine diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index add93b1..fbb0329 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -3,6 +3,7 @@ generator client { provider = "prisma-client-js" + binaryTargets = ["native", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-3.0.x"] } datasource db { diff --git a/tgbot/Dockerfile b/tgbot/Dockerfile new file mode 100644 index 0000000..565f40c --- /dev/null +++ b/tgbot/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.10-slim + +WORKDIR /app + +COPY uni_eduplatform_bot.py . + +RUN pip install pyTelegramBotAPI requests[socks] python-dotenv PySocks + +CMD ["python", "uni_eduplatform_bot.py"] diff --git a/tgbot/uni_eduplatform_bot.py b/tgbot/uni_eduplatform_bot.py index 0bd197d..8993969 100644 --- a/tgbot/uni_eduplatform_bot.py +++ b/tgbot/uni_eduplatform_bot.py @@ -4,12 +4,28 @@ from typing import Dict, Any import telebot +import telebot.apihelper as apihelper from telebot import types from dotenv import load_dotenv # Load .env load_dotenv() +SOCKS5_PROXY = os.getenv('SOCKS5_PROXY') + +proxies = None +# if SOCKS5_PROXY: +# proxies = { +# 'http': SOCKS5_PROXY, +# 'https': SOCKS5_PROXY, +# } + +if SOCKS5_PROXY: + apihelper.proxy = { + 'http': SOCKS5_PROXY, + 'https': SOCKS5_PROXY, + } + TOKEN = os.getenv('TG_BOT_TOKEN') TEACHER_CODE = os.getenv('TEACHER_CODE') PLATFORM_ADDRESS_SERVER = os.getenv('PLATFORM_ADDRESS_SERVER') @@ -115,7 +131,7 @@ def graphql_query(query: str, variables: dict = None) -> dict: if variables is not None: payload['variables'] = variables try: - r = requests.post(url, json=payload, headers=headers, timeout=10) + r = requests.post(url, json=payload, headers=headers, timeout=10, proxies=proxies) try: r.raise_for_status() except requests.HTTPError as http_err: