Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2450977e61
|
||
|
|
afc18b555a
|
||
|
|
9699127739
|
||
|
|
938d8bde7b
|
||
|
|
65c7096f46
|
||
|
|
57c00ad4d1
|
||
|
|
39618f7708
|
||
|
|
e84e4a5a9d
|
||
|
|
e74973a9d0
|
||
|
|
9233c1bf89
|
||
|
|
88c7f45a2c
|
||
|
|
9af72156f5
|
@@ -1,36 +0,0 @@
|
||||
name: Backend Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'backend/**'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> "${GITEA_OUTPUT:-$GITHUB_OUTPUT}"
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile --prefer-offline
|
||||
- name: Run Backend Tests
|
||||
run: pnpm -F @memegoat/backend test
|
||||
@@ -1,13 +1,18 @@
|
||||
name: Deploy to Production
|
||||
# Pipeline CI/CD pour Gitea Actions (Forgejo)
|
||||
# Compatible avec GitHub Actions pour la portabilité
|
||||
name: CI/CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- '**'
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: Validate Build & Lint
|
||||
name: Valider ${{ matrix.component }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -16,23 +21,23 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
- name: Installer pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
- name: Configurer Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Get pnpm store directory
|
||||
- name: Obtenir le chemin du store pnpm
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> "${GITEA_OUTPUT:-$GITHUB_OUTPUT}"
|
||||
|
||||
- name: Setup pnpm cache
|
||||
- name: Configurer le cache pnpm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
@@ -40,26 +45,43 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Installer les dépendances
|
||||
run: pnpm install --frozen-lockfile --prefer-offline
|
||||
|
||||
- name: Lint ${{ matrix.component }}
|
||||
run: pnpm -F @memegoat/${{ matrix.component }} lint
|
||||
|
||||
- name: Tester ${{ matrix.component }}
|
||||
if: matrix.component == 'backend' || matrix.component == 'frontend'
|
||||
run: |
|
||||
if pnpm -F @memegoat/${{ matrix.component }} run | grep -q "test"; then
|
||||
pnpm -F @memegoat/${{ matrix.component }} test
|
||||
else
|
||||
echo "Pas de script de test trouvé pour ${{ matrix.component }}, passage."
|
||||
fi
|
||||
|
||||
- name: Build ${{ matrix.component }}
|
||||
run: pnpm -F @memegoat/${{ matrix.component }} build
|
||||
env:
|
||||
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
|
||||
|
||||
deploy:
|
||||
name: Deploy to Production
|
||||
name: Déploiement en Production
|
||||
needs: validate
|
||||
# Déclenchement uniquement sur push sur main ou tag de version
|
||||
# Gitea supporte le contexte 'github' pour la compatibilité
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy with Docker Compose
|
||||
- name: Vérifier l'environnement Docker
|
||||
run: |
|
||||
docker version
|
||||
docker compose version
|
||||
|
||||
- name: Déployer avec Docker Compose
|
||||
run: |
|
||||
docker compose -f docker-compose.prod.yml up -d --build
|
||||
env:
|
||||
@@ -1,43 +0,0 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'frontend/**'
|
||||
- 'backend/**'
|
||||
- 'documentation/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'frontend/**'
|
||||
- 'backend/**'
|
||||
- 'documentation/**'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
component: [backend, frontend, documentation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> "${GITEA_OUTPUT:-$GITHUB_OUTPUT}"
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile --prefer-offline
|
||||
- name: Lint ${{ matrix.component }}
|
||||
run: pnpm -F @memegoat/${{ matrix.component }} lint
|
||||
225
.output.txt
225
.output.txt
@@ -1,225 +0,0 @@
|
||||
{
|
||||
"name": "@memegoat/source",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "pnpm run build:back && pnpm run build:front && pnpm run build:docs",
|
||||
"build:front": "pnpm run -F @memegoat/frontend build",
|
||||
"build:back": "pnpm run -F @memegoat/backend build",
|
||||
"build:docs": "pnpm run -F @memegoat/documentation build",
|
||||
"lint": "pnpm run lint:back && pnpm run lint:front && pnpm run lint:docs",
|
||||
"lint:back": "pnpm run -F @memegoat/backend lint",
|
||||
"lint:front": "pnpm run -F @memegoat/frontend lint",
|
||||
"lint:docs": "pnpm run -F @memegoat/documentation lint",
|
||||
"test": "pnpm run test:back && pnpm run test:front",
|
||||
"test:back": "pnpm run -F @memegoat/backend test",
|
||||
"test:front": "pnpm run -F @memegoat/frontend test",
|
||||
"format": "pnpm run format:back && pnpm run format:front && pnpm run format:docs",
|
||||
"format:back": "pnpm run -F @memegoat/backend format",
|
||||
"format:front": "pnpm run -F @memegoat/frontend format",
|
||||
"format:docs": "pnpm run -F @memegoat/documentation format",
|
||||
"upgrade": "pnpm dlx taze minor"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": {
|
||||
"name": "Mathis HERRIOT",
|
||||
"email": "mherriot.pro@proton.me",
|
||||
"role": "Author"
|
||||
},
|
||||
"license": "AGPL-3.0-only",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.11"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "@memegoat/backend",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"files": [
|
||||
"dist",
|
||||
".migrations",
|
||||
"drizzle.config.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"lint": "biome check",
|
||||
"lint:write": "biome check --write",
|
||||
"format": "biome format --write",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate",
|
||||
"db:studio": "drizzle-kit studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs-modules/mailer": "^2.0.2",
|
||||
"@nestjs/cache-manager": "^3.1.0",
|
||||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/config": "^4.0.2",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/mapped-types": "^2.1.0",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/schedule": "^6.1.0",
|
||||
"@nestjs/throttler": "^6.5.0",
|
||||
"@noble/post-quantum": "^0.5.4",
|
||||
"@node-rs/argon2": "^2.0.2",
|
||||
"@sentry/nestjs": "^10.32.1",
|
||||
"@sentry/profiling-node": "^10.32.1",
|
||||
"cache-manager": "^7.2.7",
|
||||
"cache-manager-redis-yet": "^5.1.5",
|
||||
"clamscan": "^2.4.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.3",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"helmet": "^8.1.0",
|
||||
"iron-session": "^8.0.4",
|
||||
"jose": "^6.1.3",
|
||||
"minio": "^8.0.6",
|
||||
"nodemailer": "^7.0.12",
|
||||
"otplib": "^12.0.1",
|
||||
"pg": "^8.16.3",
|
||||
"qrcode": "^1.5.4",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"sharp": "^0.34.5",
|
||||
"uuid": "^13.0.0",
|
||||
"zod": "^4.3.5",
|
||||
"drizzle-kit": "^0.31.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"jest": "^30.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-loader": "^9.5.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.20.0",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/fluent-ffmpeg": "^2.1.28",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/multer": "^2.0.0",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/nodemailer": "^7.0.4",
|
||||
"@types/pg": "^8.16.0",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"@types/sharp": "^0.32.0",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@types/uuid": "^11.0.0",
|
||||
"drizzle-kit": "^0.31.8"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node",
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules/(?!(.pnpm/)?(jose|@noble|uuid)/)"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.(t|j)sx?$": "ts-jest"
|
||||
},
|
||||
"moduleNameMapper": {
|
||||
"^@noble/post-quantum/(.*)$": "<rootDir>/../node_modules/@noble/post-quantum/$1",
|
||||
"^@noble/hashes/(.*)$": "<rootDir>/../node_modules/@noble/hashes/$1"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "@memegoat/frontend",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "biome check",
|
||||
"format": "biome format --write"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
||||
"@radix-ui/react-avatar": "^1.1.11",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-context-menu": "^2.2.16",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-hover-card": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
"@radix-ui/react-menubar": "^1.1.16",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.14",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.8",
|
||||
"@radix-ui/react-radio-group": "^1.3.8",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slider": "^1.3.6",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.2.6",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-toggle": "^1.1.10",
|
||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"axios": "^1.13.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"input-otp": "^1.4.2",
|
||||
"lucide-react": "^0.562.0",
|
||||
"next": "16.1.1",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.3",
|
||||
"react-day-picker": "^9.13.0",
|
||||
"react-dom": "19.2.3",
|
||||
"react-hook-form": "^7.71.1",
|
||||
"react-resizable-panels": "^4.4.1",
|
||||
"recharts": "2.15.4",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"vaul": "^1.1.2",
|
||||
"zod": "^4.3.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.3.11",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"babel-plugin-react-compiler": "1.0.0",
|
||||
"tailwindcss": "^4",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@memegoat/backend",
|
||||
"version": "0.0.0",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -82,6 +82,11 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
Récupère les informations détaillées de l'utilisateur connecté. Requiert l'authentification.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="GET /users/public/:username">
|
||||
Récupère le profil public d'un utilisateur par son nom d'utilisateur.
|
||||
**Réponse :** `id`, `username`, `displayName`, `avatarUrl`, `createdAt`.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="GET /users/me/export">
|
||||
Extrait l'intégralité des données de l'utilisateur au format JSON (Conformité RGPD).
|
||||
Contient le profil, les contenus et les favoris.
|
||||
@@ -89,7 +94,22 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
|
||||
<Accordion title="PATCH /users/me">
|
||||
Met à jour les informations du profil.
|
||||
**Corps :**
|
||||
- `displayName` (string)
|
||||
- `bio` (string)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="POST /users/me/avatar">
|
||||
Met à jour l'avatar de l'utilisateur.
|
||||
**Type :** `multipart/form-data`
|
||||
**Champ :** `file` (Image)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="PATCH /users/me/consent">
|
||||
Met à jour les consentements légaux de l'utilisateur.
|
||||
**Corps :**
|
||||
- `termsVersion` (string)
|
||||
- `privacyVersion` (string)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="DELETE /users/me">
|
||||
@@ -105,9 +125,9 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
- `POST /users/me/2fa/disable` : Désactive avec jeton.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Administration (GET /users/admin)">
|
||||
Liste tous les utilisateurs. Réservé aux administrateurs.
|
||||
**Params :** `limit`, `offset`.
|
||||
<Accordion title="Administration (Admin uniquement)">
|
||||
- `GET /users/admin` : Liste tous les utilisateurs (avec pagination `limit`, `offset`).
|
||||
- `DELETE /users/:uuid` : Supprime définitivement un utilisateur par son UUID.
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
@@ -118,12 +138,15 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
Recherche et filtre les contenus. Ces endpoints sont mis en cache (Redis + Navigateur).
|
||||
|
||||
**Query Params :**
|
||||
- `limit` (number) : Défaut 10.
|
||||
- `offset` (number) : Défaut 0.
|
||||
- `sort` : `trend` | `recent` (uniquement sur `/explore`)
|
||||
- `tag` (string)
|
||||
- `category` (slug ou id)
|
||||
- `author` (username)
|
||||
- `query` (titre)
|
||||
- `favoritesOnly` (bool)
|
||||
- `tag` (string) : Filtrer par tag.
|
||||
- `category` (slug ou id) : Filtrer par catégorie.
|
||||
- `author` (username) : Filtrer par auteur.
|
||||
- `query` (titre) : Recherche textuelle.
|
||||
- `favoritesOnly` (bool) : Ne montrer que les favoris de l'utilisateur connecté.
|
||||
- `userId` (uuid) : Filtrer les contenus d'un utilisateur spécifique.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="GET /contents/:idOrSlug">
|
||||
@@ -133,8 +156,13 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
Si l'User-Agent correspond à un robot d'indexation (Googlebot, Twitterbot, etc.), l'API retourne un rendu HTML minimal contenant les méta-tags **OpenGraph** et **Twitter Cards** pour un partage optimal. Pour les autres clients, les données sont retournées en JSON.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="POST /contents">
|
||||
Crée une entrée de contenu (sans upload de fichier direct). Utile pour référencer des URLs externes.
|
||||
**Corps :** `title`, `description`, `url`, `type`, `categoryId`, `tags`.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="POST /contents/upload">
|
||||
Upload un fichier avec traitement automatique.
|
||||
Upload un fichier avec traitement automatique par le serveur.
|
||||
**Type :** `multipart/form-data`
|
||||
|
||||
**Champs :**
|
||||
@@ -145,6 +173,11 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
- `tags`? : string[]
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="POST /contents/upload-url">
|
||||
Génère une URL présignée pour un upload direct vers S3.
|
||||
**Query Param :** `fileName` (string).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="POST /contents/:id/view | /use">
|
||||
Incrémente les statistiques de vue ou d'utilisation.
|
||||
</Accordion>
|
||||
@@ -152,6 +185,10 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
<Accordion title="DELETE /contents/:id">
|
||||
Supprime un contenu (Soft Delete). Doit être l'auteur.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="DELETE /contents/:id/admin">
|
||||
Supprime définitivement un contenu. **Réservé aux administrateurs.**
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
### 📂 Catégories, ⭐ Favoris, 🚩 Signalements
|
||||
@@ -159,19 +196,23 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
<Accordions>
|
||||
<Accordion title="Catégories (/categories)">
|
||||
- `GET /categories` : Liste toutes les catégories.
|
||||
- `GET /categories/:id` : Détails d'une catégorie.
|
||||
- `POST /categories` : Création (Admin uniquement).
|
||||
- `PATCH /categories/:id` : Mise à jour (Admin uniquement).
|
||||
- `DELETE /categories/:id` : Suppression (Admin uniquement).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Favoris (/favorites)">
|
||||
- `GET /favorites` : Liste les favoris de l'utilisateur.
|
||||
Requiert l'authentification.
|
||||
- `GET /favorites` : Liste les favoris de l'utilisateur (avec pagination `limit`, `offset`).
|
||||
- `POST /favorites/:contentId` : Ajoute un favori.
|
||||
- `DELETE /favorites/:contentId` : Retire un favori.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Signalements (/reports)">
|
||||
- `POST /reports` : Signale un contenu ou un tag.
|
||||
- `GET /reports` : Liste (Modérateurs).
|
||||
- `PATCH /reports/:id/status` : Gère le workflow.
|
||||
- `GET /reports` : Liste des signalements (Pagination `limit`, `offset`). **Admin/Modérateurs**.
|
||||
- `PATCH /reports/:id/status` : Change le statut (`pending`, `resolved`, `dismissed`). **Admin/Modérateurs**.
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
@@ -185,7 +226,23 @@ Cette page documente tous les points de terminaison disponibles sur l'API Memego
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Tags (/tags)">
|
||||
- `GET /tags` : Recherche de tags populaires ou récents.
|
||||
**Params :** `query`, `sort`, `limit`.
|
||||
- `GET /tags` : Recherche de tags.
|
||||
- **Params :** `query` (recherche), `sort` (`popular` | `recent`), `limit`, `offset`.
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
### 🛠️ Système & Médias
|
||||
|
||||
<Accordions>
|
||||
<Accordion title="Santé (/health)">
|
||||
- `GET /health` : Vérifie l'état de l'API et de la connexion à la base de données.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Médias (/media)">
|
||||
- `GET /media/*key` : Accès direct aux fichiers stockés sur S3. Supporte la mise en cache agressive.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Administration (/admin)">
|
||||
- `GET /admin/stats` : Récupère les statistiques globales de la plateforme. **Admin uniquement**.
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
@@ -20,6 +20,13 @@ Le système utilise plusieurs méthodes d'authentification sécurisées pour ré
|
||||
<Card title="Double Authentification" description="Support TOTP natif avec secret chiffré PGP pour une sécurité maximale." />
|
||||
</Cards>
|
||||
|
||||
### Webhooks / Services Externes
|
||||
### Stockage & Médias (S3)
|
||||
|
||||
Liste des intégrations tierces.
|
||||
Memegoat utilise une architecture de stockage d'objets compatible S3 (MinIO). Les interactions se font de deux manières :
|
||||
|
||||
1. **Proxification Backend** : Pour l'accès public via `/media/*`.
|
||||
2. **URLs Présignées** : Pour l'upload sécurisé direct depuis le client (via `/contents/upload-url`).
|
||||
|
||||
### Notifications (Mail)
|
||||
|
||||
Le système intègre un service d'envoi d'emails (SMTP) pour les notifications critiques et la gestion des comptes.
|
||||
|
||||
@@ -35,10 +35,13 @@ erDiagram
|
||||
string username
|
||||
string email
|
||||
string display_name
|
||||
string avatar_url
|
||||
string bio
|
||||
string status
|
||||
}
|
||||
CONTENT {
|
||||
string title
|
||||
string slug
|
||||
string type
|
||||
string storage_key
|
||||
}
|
||||
@@ -82,6 +85,8 @@ erDiagram
|
||||
bytea email
|
||||
varchar email_hash
|
||||
varchar display_name
|
||||
varchar avatar_url
|
||||
varchar bio
|
||||
varchar password_hash
|
||||
user_status status
|
||||
bytea two_factor_secret
|
||||
@@ -100,6 +105,7 @@ erDiagram
|
||||
uuid category_id FK
|
||||
content_type type
|
||||
varchar title
|
||||
varchar slug
|
||||
varchar storage_key
|
||||
varchar mime_type
|
||||
integer file_size
|
||||
@@ -233,6 +239,8 @@ erDiagram
|
||||
varchar email_hash "UNIQUE, INDEXED"
|
||||
varchar username "UNIQUE, NOT NULL"
|
||||
varchar password_hash "NOT NULL"
|
||||
varchar avatar_url "NULLABLE"
|
||||
varchar bio "NULLABLE"
|
||||
bytea two_factor_secret "ENCRYPTED"
|
||||
boolean is_two_factor_enabled "DEFAULT false"
|
||||
timestamp gdpr_accepted_at "NULLABLE"
|
||||
@@ -241,6 +249,7 @@ erDiagram
|
||||
contents {
|
||||
uuid id "DEFAULT gen_random_uuid()"
|
||||
uuid user_id "REFERENCES users(uuid)"
|
||||
varchar slug "UNIQUE, NOT NULL"
|
||||
varchar storage_key "UNIQUE, NOT NULL"
|
||||
integer file_size "NOT NULL"
|
||||
timestamp deleted_at "SOFT DELETE"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@memegoat/documentation",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@memegoat/frontend",
|
||||
"version": "0.0.0",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
{
|
||||
"name": "@memegoat/source",
|
||||
"version": "0.0.0",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"version:get": "cmake -P version.cmake GET",
|
||||
"version:set": "cmake -P version.cmake SET",
|
||||
"v:patch": "cmake -P version.cmake PATCH",
|
||||
"v:minor": "cmake -P version.cmake MINOR",
|
||||
"v:major": "cmake -P version.cmake MAJOR",
|
||||
"build": "pnpm run build:back && pnpm run build:front && pnpm run build:docs",
|
||||
"build:front": "pnpm run -F @memegoat/frontend build",
|
||||
"build:back": "pnpm run -F @memegoat/backend build",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# version.cmake - Script pour gérer la version SemVer de manière centralisée
|
||||
|
||||
# Usage: cmake -P version.cmake [GET|SET] [new_version]
|
||||
# Usage: cmake -P version.cmake [GET|SET|PATCH|MINOR|MAJOR] [new_version]
|
||||
|
||||
set(PACKAGE_JSON_FILES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/package.json"
|
||||
@@ -15,6 +15,30 @@ function(get_current_version OUT_VAR)
|
||||
set(${OUT_VAR} ${CURRENT_VERSION} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Fonction pour incrémenter la version SemVer
|
||||
function(increment_version CURRENT_VERSION TYPE OUT_VAR)
|
||||
if(CURRENT_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
||||
set(MAJOR ${CMAKE_MATCH_1})
|
||||
set(MINOR ${CMAKE_MATCH_2})
|
||||
set(PATCH ${CMAKE_MATCH_3})
|
||||
else()
|
||||
message(FATAL_ERROR "Format de version invalide: ${CURRENT_VERSION}. Attendu: X.Y.Z")
|
||||
endif()
|
||||
|
||||
if("${TYPE}" STREQUAL "MAJOR")
|
||||
math(EXPR MAJOR "${MAJOR} + 1")
|
||||
set(MINOR 0)
|
||||
set(PATCH 0)
|
||||
elseif("${TYPE}" STREQUAL "MINOR")
|
||||
math(EXPR MINOR "${MINOR} + 1")
|
||||
set(PATCH 0)
|
||||
elseif("${TYPE}" STREQUAL "PATCH")
|
||||
math(EXPR PATCH "${PATCH} + 1")
|
||||
endif()
|
||||
|
||||
set(${OUT_VAR} "${MAJOR}.${MINOR}.${PATCH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Fonction pour créer un tag git
|
||||
function(create_git_tag VERSION)
|
||||
find_package(Git QUIET)
|
||||
@@ -49,36 +73,42 @@ function(set_new_version NEW_VERSION)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Demander à l'utilisateur s'il veut tagger (ou le faire par défaut si spécifié)
|
||||
# Créer le tag git
|
||||
create_git_tag(${NEW_VERSION})
|
||||
endfunction()
|
||||
|
||||
# Logique principale
|
||||
set(ARG_OFFSET 0)
|
||||
while(ARG_OFFSET LESS CMAKE_ARGC)
|
||||
if("${CMAKE_ARGV${ARG_OFFSET}}" STREQUAL "-P")
|
||||
math(EXPR COMMAND_INDEX "${ARG_OFFSET} + 2")
|
||||
math(EXPR VERSION_INDEX "${ARG_OFFSET} + 3")
|
||||
break()
|
||||
if(CMAKE_SCRIPT_MODE_FILE STREQUAL CMAKE_CURRENT_LIST_FILE)
|
||||
set(ARG_OFFSET 0)
|
||||
while(ARG_OFFSET LESS CMAKE_ARGC)
|
||||
if("${CMAKE_ARGV${ARG_OFFSET}}" STREQUAL "-P")
|
||||
math(EXPR COMMAND_INDEX "${ARG_OFFSET} + 2")
|
||||
math(EXPR VERSION_INDEX "${ARG_OFFSET} + 3")
|
||||
break()
|
||||
endif()
|
||||
math(EXPR ARG_OFFSET "${ARG_OFFSET} + 1")
|
||||
endwhile()
|
||||
|
||||
if(NOT DEFINED COMMAND_INDEX OR COMMAND_INDEX GREATER_EQUAL CMAKE_ARGC)
|
||||
message(FATAL_ERROR "Usage: cmake -P version.cmake [GET|SET|PATCH|MINOR|MAJOR] [new_version]")
|
||||
endif()
|
||||
math(EXPR ARG_OFFSET "${ARG_OFFSET} + 1")
|
||||
endwhile()
|
||||
|
||||
if(NOT DEFINED COMMAND_INDEX OR COMMAND_INDEX GREATER_EQUAL CMAKE_ARGC)
|
||||
message(FATAL_ERROR "Usage: cmake -P version.cmake [GET|SET] [new_version]")
|
||||
endif()
|
||||
|
||||
set(COMMAND "${CMAKE_ARGV${COMMAND_INDEX}}")
|
||||
|
||||
if("${COMMAND}" STREQUAL "GET")
|
||||
get_current_version(VERSION)
|
||||
message("${VERSION}")
|
||||
elseif("${COMMAND}" STREQUAL "SET")
|
||||
if(VERSION_INDEX GREATER_EQUAL CMAKE_ARGC)
|
||||
message(FATAL_ERROR "Veuillez spécifier la nouvelle version: cmake -P version.cmake SET 0.0.0")
|
||||
|
||||
set(COMMAND "${CMAKE_ARGV${COMMAND_INDEX}}")
|
||||
|
||||
if("${COMMAND}" STREQUAL "GET")
|
||||
get_current_version(VERSION)
|
||||
message("${VERSION}")
|
||||
elseif("${COMMAND}" STREQUAL "SET")
|
||||
if(VERSION_INDEX GREATER_EQUAL CMAKE_ARGC)
|
||||
message(FATAL_ERROR "Veuillez spécifier la nouvelle version: cmake -P version.cmake SET 0.0.0")
|
||||
endif()
|
||||
set(NEW_VERSION "${CMAKE_ARGV${VERSION_INDEX}}")
|
||||
set_new_version("${NEW_VERSION}")
|
||||
elseif("${COMMAND}" MATCHES "^(PATCH|MINOR|MAJOR)$")
|
||||
get_current_version(CURRENT_VERSION)
|
||||
increment_version("${CURRENT_VERSION}" "${COMMAND}" NEW_VERSION)
|
||||
set_new_version("${NEW_VERSION}")
|
||||
else()
|
||||
message(FATAL_ERROR "Commande inconnue: ${COMMAND}. Utilisez GET, SET, PATCH, MINOR ou MAJOR.")
|
||||
endif()
|
||||
set(NEW_VERSION "${CMAKE_ARGV${VERSION_INDEX}}")
|
||||
set_new_version("${NEW_VERSION}")
|
||||
else()
|
||||
message(FATAL_ERROR "Commande inconnue: ${COMMAND}. Utilisez GET ou SET.")
|
||||
endif()
|
||||
|
||||
Reference in New Issue
Block a user