31 Commits

Author SHA1 Message Date
02e84ed9d6 login okay
Some checks failed
Build Docker Image / run (push) Failing after 30s
2024-04-26 16:00:53 +02:00
06bdeff188 add PB middleware
All checks were successful
Build Docker Image / run (push) Successful in 53s
2024-04-26 14:18:46 +02:00
7a510a53a1 rm email visibility
All checks were successful
Build Docker Image / run (pull_request) Successful in 1m16s
Build Docker Image / run (push) Successful in 27s
2024-04-26 10:46:35 +02:00
063660db9d fix userObj type 2024-04-26 10:46:26 +02:00
55740b6219 fix error issue 2024-04-26 10:44:16 +02:00
459c1252e0 update package 2024-04-26 10:41:54 +02:00
cd234f5b37 rm usless thing 2024-04-26 10:41:37 +02:00
76755baa1d fix: make some build fix
Some checks failed
Build Docker Image / run (pull_request) Failing after 31s
2024-04-25 19:52:01 +02:00
2cc3219b30 add astro login page
Some checks failed
Build Docker Image / run (pull_request) Failing after 31s
2024-04-25 18:34:49 +02:00
b48c842e41 auth utile 2024-04-25 18:33:20 +02:00
313c197096 env var WIP 2024-04-25 18:33:01 +02:00
5776fe08d9 feat: user model 2024-04-25 18:32:25 +02:00
b1fce87215 add eslint config 2024-04-25 18:26:06 +02:00
4761fef61b auth WIP
Some checks failed
Build Docker Image / run (pull_request) Failing after 31s
2024-04-25 11:24:01 +02:00
eed351df0a Merge commit 'd5afe1631eb3b58207a098285c8f73f246bb2c4d' into feat/gestion-utilisateur
Some checks failed
Build Docker Image / run (pull_request) Failing after 53s
2024-04-25 10:54:12 +02:00
d5afe1631e fix: correction problème divers (#7)
All checks were successful
Build Docker Image / run (push) Successful in 24s
Reviewed-on: #7
Co-authored-by: Clement <c.boesmier@aptatio.com>
Co-committed-by: Clement <c.boesmier@aptatio.com>
2024-04-25 10:40:39 +02:00
a03c5cb3db feat: CI-CD front (#2)
All checks were successful
Build Docker Image / run (push) Successful in 22s
Reviewed-on: #2
2024-04-21 15:24:15 +02:00
db493301c8 fix: add submodule to readme (#4)
Reviewed-on: #4
Co-authored-by: Clement <c.boesmier@aptatio.com>
Co-committed-by: Clement <c.boesmier@aptatio.com>
2024-04-21 11:12:53 +02:00
746c7d493c feat: add open data to dev (#3)
Reviewed-on: #3
Co-authored-by: Clement <c.boesmier@aptatio.com>
Co-committed-by: Clement <c.boesmier@aptatio.com>
2024-04-21 11:08:56 +02:00
5a49f5beda rm some log 2024-04-20 12:09:05 +02:00
70382d7bd8 feat: login page test 2024-04-20 12:08:49 +02:00
a724c1270f fix: change register form name 2024-04-20 12:07:37 +02:00
7c68628456 add register form test 2024-04-20 11:45:39 +02:00
a2290c21e1 add astro util 2024-04-20 11:45:17 +02:00
79656cfccd fix: site output type 2024-04-20 11:15:33 +02:00
65d52eb8fa add pb dependancie 2024-04-20 11:15:12 +02:00
65ddbe976f rm default style 2024-04-20 11:14:48 +02:00
6f3b8a73f2 add suject to gitignore 2024-04-20 10:49:27 +02:00
84255ef0a6 init front 2024-04-20 10:48:50 +02:00
96aaa10f48 add dev docker compose 2024-04-20 10:48:15 +02:00
77008a97b8 add mirror link 2024-04-20 10:48:02 +02:00
38 changed files with 11376 additions and 0 deletions

53
.github/workflows/build_docker.yml vendored Normal file
View File

@ -0,0 +1,53 @@
name: Build Docker Image # nom du workflow
on: #declancheur
push:
branches:
- '*'
tags:
- v*
pull_request:
branches:
- master
jobs:
run: #jobs ID (nom du jobs)
runs-on: ubuntu-latest # environement de run
steps: # liste des étapes
- name: Checkout # rapatrie le depot
uses: actions/checkout@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
git.lab-ouest.org/Epitech/ratrapage_T-WEB_front
tags: |
type=edge
type=ref,event=pr
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=semver,pattern=latest
- name: Login to Gitea
uses: docker/login-action@v3
with:
registry: git.lab-ouest.org
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v3
- name: Build and push front
uses: docker/build-push-action@v5
with:
context: ./front
push: true
file: ./front/Dockerfile
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

1
.gitignore vendored
View File

@ -190,3 +190,4 @@ dist
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
.pb
T-WEB-800_project.pdf

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "datatourisme"]
path = datatourisme
url = https://git.lab-ouest.org/Epitech/fork-open-data-tourism

View File

@ -0,0 +1,4 @@
Original repo : https://git.lab-ouest.org/Epitech/ratrapage_T-WEB
Submodule repo : https://git.lab-ouest.org/Epitech/fork-open-data-tourism/

View File

@ -0,0 +1,5 @@
{
"version": "1",
"name": "OpenData datatourisme",
"type": "collection"
}

View File

@ -0,0 +1,3 @@
vars:secret [
app_key
]

View File

@ -0,0 +1,11 @@
meta {
name: test opendata
type: http
seq: 1
}
get {
url: https://diffuseur.datatourisme.fr/webservice/adb00e7893763e3196afe9a3da1c9e41/{{app_key}}
body: none
auth: none
}

View File

@ -0,0 +1,15 @@
meta {
name: test pays de la loire
type: graphql
seq: 2
}
post {
url: http://localhost:8080
body: graphql
auth: none
}
body:graphql {
{poi() {results{dc_identifier rdfs_label}}}
}

1
datatourisme Submodule

Submodule datatourisme added at 5175e1fdf1

29
docker-compose-dev.yml Normal file
View File

@ -0,0 +1,29 @@
services:
pocketbase:
image: ghcr.io/coollabsio/pocketbase:latest
environment:
- SERVICE_FQDN_POCKETBASE_8080
volumes:
- ./.pb/pocketbase-data:/app/pb_data
- ./.pb/pocketbase-hooks:/app/pb_hooks
ports:
- 3001:8080
blazegraph:
image: conjecto/blazegraph:2.1.5
ports:
- 9999:9999
environment:
JAVA_OPTS: "-Xms6G -Xmx6G"
volumes:
- ./datatourisme/dataset:/docker-entrypoint-initdb.d
ulimits:
nofile:
soft: 65536
hard: 65536
datatourisme:
build: datatourisme/docker
ports:
- "8080:80"
depends_on:
- blazegraph

34
docker-compose.yml Normal file
View File

@ -0,0 +1,34 @@
version: "3.8"
services:
pocketbase:
image: ghcr.io/coollabsio/pocketbase:latest
environment:
- SERVICE_FQDN_POCKETBASE_8080
volumes:
- ./.pb/pocketbase-data:/app/pb_data
- ./.pb/pocketbase-hooks:/app/pb_hooks
labels:
- traefik.enable=true
- traefik.http.routers.poketBaseTweb.rule=Host(`${POCKET_BASE_URL}`)
- traefik.http.services.poketBaseTweb.loadbalancer.server.port=${POCKET_BASE_PORT}
- traefik.http.routers.poketBaseTweb.tls.certresolver=le
networks:
- public
front:
image: git.lab-ouest.org/epitech/ratrapage_t-web_front:pr-7-head
depends_on:
- pocketbase
labels:
- traefik.enable=true
- traefik.http.routers.astroTweb.rule=Host(`${FRONT_URL}`)
- traefik.http.services.astroTweb.loadbalancer.server.port=${FRONT_BASE_PORT}
- traefik.http.routers.astroTweb.tls.certresolver=le
networks:
- public
networks:
public:
external: true
x-dockge:
urls:
- https://${POCKET_BASE_URL}/
- https://${FRONT_URL}/

8
front/.eslintignore Normal file
View File

@ -0,0 +1,8 @@
node_modules
out
.next
next-env.d.ts
*.js
__tests__

324
front/.eslintrc.json Normal file
View File

@ -0,0 +1,324 @@
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:astro/recommended",
"plugin:@typescript-eslint/strict",
"plugin:@typescript-eslint/stylistic"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"overrides": [
{
"files": [
"*.astro"
],
"parser": "astro-eslint-parser",
"parserOptions": {
"extraFileExtensions": [
".astro"
],
"parser": "@typescript-eslint/parser"
}
},
{
"files": [
"*.ts",
"*.tsx",
"*.astro"
],
"rules": {
"no-extra-parens": "off",
"no-unused-expressions": "off",
"no-shadow": "off",
"quotes": "off",
"semi": "off",
"space-before-function-paren": "off"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true,
"project": "tsconfig.json",
"sourceType": "module",
"ecmaVersion": 2018
}
},
"plugins": [
"@typescript-eslint"
],
"root": true,
"rules": {
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/space-before-function-paren": [
"error",
{
"anonymous": "never",
"asyncArrow": "always",
"named": "never"
}
],
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unified-signatures": "error",
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": [
"error",
{
"default": "generic"
}
],
"arrow-body-style": "error",
"arrow-parens": [
"error",
"always"
],
"@typescript-eslint/ban-types": [
"error",
{
"types": {
"{}": false
}
}
],
"complexity": [
"warn",
10
],
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/consistent-type-definitions": "error",
"constructor-super": "error",
"curly": "error",
"dot-notation": "error",
"eol-last": "error",
"eqeqeq": [
"error",
"smart"
],
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "explicit"
}
],
"for-direction": "error",
"getter-return": "error",
"guard-for-in": "error",
"id-blacklist": [
"error",
"any",
"Number",
"number",
"String",
"string",
"Boolean",
"boolean",
"Undefined"
],
"id-length": [
"warn",
{
"exceptions": [
"_"
]
}
],
"id-match": "error",
"indent": [
"error",
"tab",
{
"SwitchCase": 1
}
],
"linebreak-style": [
"error",
"unix"
],
"max-classes-per-file": [
"error",
1
],
"max-depth": [
"warn",
2
],
"max-len": [
"warn",
{
"code": 256
}
],
"@typescript-eslint/member-delimiter-style": [
"error",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "comma",
"requireLast": false
}
}
],
"@typescript-eslint/member-ordering": "error",
"new-parens": "error",
"no-async-promise-executor": "error",
"no-await-in-loop": "warn",
"no-bitwise": "error",
"no-caller": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-console": "off",
"no-constant-condition": "error",
"no-control-regex": "warn",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
],
"no-empty-character-class": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-empty-interface": "error",
"no-eval": "error",
"no-ex-assign": "error",
"@typescript-eslint/no-explicit-any": "off",
"no-extra-boolean-cast": "error",
"no-extra-parens": "off",
"@typescript-eslint/no-extra-parens": [
"error",
"all",
{
"ignoreJSX": "all"
}
],
"no-extra-semi": "error",
"no-fallthrough": "off",
"no-func-assign": "error",
"no-import-assign": "error",
"no-inner-declarations": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-label-var": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"@typescript-eslint/no-misused-new": "error",
"no-multiple-empty-lines": "error",
"@typescript-eslint/no-namespace": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-promise-executor-return": "error",
"@typescript-eslint/no-parameter-properties": "off",
"no-prototype-builtins": "error",
"no-regex-spaces": "error",
"no-setter-return": "error",
"@typescript-eslint/no-shadow": "error",
"no-shadow": [
"error",
{
"builtinGlobals": false,
"hoist": "all"
}
],
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "warn",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef": "error",
"no-undef-init": "error",
"no-underscore-dangle": "off",
"no-unexpected-multiline": "error",
"no-unreachable": "warn",
"no-unreachable-loop": "warn",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": "error",
"no-unused-expressions": [
"error",
{
"allowTernary": true
}
],
"@typescript-eslint/no-unused-expressions": [
"error",
{
"allowTernary": true
}
],
"no-unused-labels": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", {
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "all",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}],
"@typescript-eslint/no-non-null-assertion": ["warn"],
"no-var": "error",
"object-shorthand": [
"warn",
"methods"
],
"one-var": [
"error",
"never"
],
"prefer-const": "error",
"quote-props": [
"error",
"consistent-as-needed"
],
"quotes": "off",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true
}
],
"radix": "error",
"require-atomic-updates": "warn",
"semi": "off",
"@typescript-eslint/semi": [
"error",
"never"
],
"space-before-function-paren": [
"error",
{
"anonymous": "never",
"asyncArrow": "always",
"named": "never"
}
],
"spaced-comment": ["error", "always", { "block": { "exceptions": ["*"] } }],
"use-isnan": "error",
"valid-typeof": "warn"
}
}

24
front/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# jetbrains setting folder
.idea/

4
front/.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
front/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

9
front/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,9 @@
{
"editor.quickSuggestions": {
"strings": "on"
},
"tailwindCSS.includeLanguages": {
"astro": "html"
},
"typescript.tsdk": "node_modules/typescript/lib"
}

64
front/Dockerfile Normal file
View File

@ -0,0 +1,64 @@
# This Dockerfile allows you to run AstroJS in server mode
#########
# Build #
#########
FROM docker.io/node:20-alpine as BUILD_IMAGE
# Disable telemetry
ENV ASTRO_TELEMETRY_DISABLED=1
# External deps (for node-gyp add: "python3 make g++")
RUN apk add --no-cache git
# run as non root user
USER node
# go to user repository
WORKDIR /home/node
# Add package json
ADD --chown=node:node package.json package-lock.json ./
# install dependencies from package lock
RUN npm ci
# Add project files
ADD --chown=node:node . .
# build
RUN npm run build
# remove dev deps
RUN npm prune --omit=dev
##############
# Production #
##############
FROM docker.io/node:20-alpine as PROD_IMAGE
# inform software to be in production
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV RESOURCES_FOLDER=/home/node/.loop/uploads
ENV ASTRO_TELEMETRY_DISABLED=1
# run as non root user
USER node
# go to work folder
WORKDIR /home/node
# Expose port
EXPOSE 3000
# Add Healthcheck
HEALTHCHECK --interval=10s --timeout=10s --start-period=5s --retries=3 CMD wget --no-verbose --tries=1 --spider http://localhost:3000 || exit 1
# copy from build image
COPY --chown=node:node --from=BUILD_IMAGE /home/node/node_modules ./node_modules
COPY --chown=node:node --from=BUILD_IMAGE /home/node/dist ./dist
COPY --chown=node:node --from=BUILD_IMAGE /home/node/package.json /home/node/.env* ./
# run it !
CMD ["npm", "run", "start"]

54
front/README.md Normal file
View File

@ -0,0 +1,54 @@
# Astro Starter Kit: Basics
```sh
npm create astro@latest -- --template basics
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554)
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── public/
│ └── favicon.svg
├── src/
│ ├── components/
│ │ └── Card.astro
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

29
front/astro.config.mjs Normal file
View File

@ -0,0 +1,29 @@
import node from '@astrojs/node'
import tailwind from '@astrojs/tailwind'
import { defineConfig } from 'astro/config'
import react from '@astrojs/react'
// https://astro.build/config
export default defineConfig({
compressHTML: true,
build: {
assets: 'assets',
inlineStylesheets: 'auto'
},
server: {
host: true,
port: 3000
},
trailingSlash: 'never',
output: 'server',
adapter: node({
mode: 'standalone'
}),
integrations: [tailwind(), react()],
vite: {
optimizeDeps: {
include: ['leaflet']
}
}
})

10090
front/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

45
front/package.json Normal file
View File

@ -0,0 +1,45 @@
{
"name": "front",
"type": "module",
"version": "0.0.1",
"private": "true",
"scripts": {
"dev": "astro dev",
"start": "node ./dist/server/entry.mjs",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro",
"check:lint": "eslint src"
},
"dependencies": {
"@astrojs/node": "^8.2.5",
"@astrojs/react": "^3.3.1",
"@astrojs/tailwind": "^5.1.0",
"@tailwindcss/typography": "^0.5.12",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
"astro": "4.5.12",
"leaflet": "^1.9.4",
"lucide-astro": "^0.372.0",
"pocketbase": "^0.21.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-leaflet": "^4.2.1",
"simple-icons-astro": "^11.12.0",
"tailwindcss": "^3.4.3",
"typescript": "^5"
},
"devDependencies": {
"@astrojs/check": "^0",
"@astrojs/ts-plugin": "^1.6.1",
"@types/leaflet": "^1.9.12",
"@types/node": "^20",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitest/coverage-v8": "^1",
"eslint": "^8.57.0",
"eslint-plugin-astro": "^0.31.4",
"typescript": "^5",
"vitest": "^1"
}
}

9
front/public/favicon.svg Normal file
View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #FFF; }
}
</style>
</svg>

After

Width:  |  Height:  |  Size: 749 B

View File

@ -0,0 +1,61 @@
---
interface Props {
title: string;
body: string;
href: string;
}
const { href, title, body } = Astro.props;
---
<li class="link-card">
<a href={href}>
<h2>
{title}
<span>&rarr;</span>
</h2>
<p>
{body}
</p>
</a>
</li>
<style>
.link-card {
list-style: none;
display: flex;
padding: 1px;
background-color: #23262d;
background-image: none;
background-size: 400%;
border-radius: 7px;
background-position: 100%;
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
.link-card > a {
width: 100%;
text-decoration: none;
line-height: 1.4;
padding: calc(1.5rem - 1px);
border-radius: 8px;
color: white;
background-color: #23262d;
opacity: 0.8;
}
h2 {
margin: 0;
font-size: 1.25rem;
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
p {
margin-top: 0.5rem;
margin-bottom: 0;
}
.link-card:is(:hover, :focus-within) {
background-position: 0;
background-image: var(--accent-gradient);
}
.link-card:is(:hover, :focus-within) h2 {
color: rgb(var(--accent-light));
}
</style>

25
front/src/env.d.ts vendored Normal file
View File

@ -0,0 +1,25 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />
import PocketBase from 'pocketbase'
export interface ImportMetaEnv {
NODE_ENV: string
APP_URL: string
POCKETBASE_URL: string
GOOGLE_API_KEY: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace App {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Locals {
pb: PocketBase
}
}

View File

@ -0,0 +1,22 @@
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>

View File

@ -0,0 +1,5 @@
export default class AstroUtils {
public static async wrap<T = void>(fn: () => T | Promise<T>) {
return await fn()
}
}

107
front/src/libs/AuthUtils.ts Normal file
View File

@ -0,0 +1,107 @@
import type { AstroCookies } from 'astro'
import type UserObj from 'models/User'
import PocketBase from 'pocketbase'
import { getEnv } from 'libs/Env'
const pb = new PocketBase(getEnv('POCKETBASE_URL','https://pb-tweb.cb85.fr')) // XXX: 'https://pb-tweb.cb85.fr'
export async function clearUser(cookies: AstroCookies): Promise<void> {
const sessionID = cookies.get('session')?.value
if(!sessionID){
return
}
cookies.delete('session',{
path: '/'
})
}
export async function login(cookies: AstroCookies, user: {user: string, password: string}): Promise<boolean> {
const authData = await pb.collection('users').authWithPassword(user.user, user.password)
let secure = true
if (getEnv('NODE_ENV', 'production') !== 'production') {
secure = false
}
if(authData){
cookies.set('session', authData.token,{
httpOnly: true,
path: '/',
secure: secure,
sameSite: 'strict',
maxAge: 365000,
})
return true
}
return false
}
export async function getUser(cookies: AstroCookies): Promise<UserObj | null> {
const sessionID = cookies.get('session')?.value
const bpAuth = pb.authStore
if(!sessionID){
return null
}
if(!bpAuth.isValid){
return null
}
if(!bpAuth){
return null
}
console.log(bpAuth.model)
if(!bpAuth.model){
return null
}
const output: UserObj = {
id: bpAuth.model.id as string,
collectionId: bpAuth.model.collectionId as string,
collectionName: bpAuth.model.collectionName as string,
created: bpAuth.model.created as string,
updated: bpAuth.model.updated as string,
avatar: bpAuth.model.avatar as string,
username: bpAuth.model.username as string,
email: bpAuth.model.email as string,
emailVisibility: false,
name: bpAuth.model.name as string,
password: undefined,
passwordConfirm: undefined,
}
return output
}
export async function setUser(cookies: AstroCookies, user: UserObj): Promise<void>{
const record = await pb.collection('users').create(user)
console.log(record)
const session = pb.authStore.token
console.log(session)
let secure = true
if (getEnv('NODE_ENV', 'production') !== 'production') {
secure = false
}
cookies.set('session', session,{
httpOnly: true,
path: '/',
secure: secure,
sameSite: 'strict',
maxAge: 365000,
})
}

17
front/src/libs/Env.ts Normal file
View File

@ -0,0 +1,17 @@
import type { ImportMetaEnv } from 'env'
/**
* Get the environment variable
*
* @param key the env variable key
* @param defaultValue a default value if applicable
* @returns the environment value or undefined if not found
*/
export function getEnv(key: keyof ImportMetaEnv, defaultValue: string): string
export function getEnv(key: keyof ImportMetaEnv, defaultValue?: string | undefined): string | undefined
export function getEnv(key: keyof ImportMetaEnv, defaultValue?: string | undefined): string | undefined {
// get the env variable through Astro > NodeJS > input
const res = import.meta.env[key] ?? process.env[key] ?? defaultValue
return res ?? undefined
}

View File

@ -0,0 +1,27 @@
import PocketBase from 'pocketbase'
import { defineMiddleware } from 'astro/middleware'
import { getEnv } from 'libs/Env'
export const onRequest = defineMiddleware(async ({ locals, request }: any, next: () => any) => {
locals.pb = new PocketBase(getEnv('POCKETBASE_URL','http://localhost:8080'))
// load the store data from the request cookie string
locals.pb.authStore.loadFromCookie(request.headers.get('cookie') || '')
try {
// get an up-to-date auth store state by verifying and refreshing the loaded auth model (if any)
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
locals.pb.authStore.isValid && await locals.pb.collection('users').authRefresh()
} catch (_) {
// clear the auth store on failed refresh
locals.pb.authStore.clear()
}
const response = await next()
// send back the default 'pb_auth' cookie to the client with the latest store state
response.headers.append('set-cookie', locals.pb.authStore.exportToCookie())
return response
})

View File

@ -0,0 +1,19 @@
export interface PBData{
id?: string | null
collectionId?: string | null
collectionName?: string | null
created?: string | null // TODO: passé ca en date auto
updated?: string | null // TODO: passé ca en date auto
}
export default interface UserObj extends PBData{
avatar?: string | null
username: string
email: string
emailVisibility?: boolean
password?: string | undefined
passwordConfirm?: string | undefined
name: string | null
}

View File

@ -0,0 +1,18 @@
---
import Layout from 'layouts/Layout.astro'
import PocketBase from 'pocketbase'
const pb = Astro.locals.pb as PocketBase
const auth = pb.authStore
const user = auth.model
if(!auth.isValid){
return Astro.redirect("/account/login");
}
---
<Layout title="Account setting">
<h1>Bonjour {user!.name}</h1>
</Layout>

View File

@ -0,0 +1,43 @@
---
import Layout from "layouts/Layout.astro";
import AstroUtils from "libs/AstroUtils";
import PocketBase from 'pocketbase'
const pb = Astro.locals.pb as PocketBase
if(pb.authStore.isValid){
return Astro.redirect("/account")
}
const res = await AstroUtils.wrap(async () => {
if (Astro.request.method !== 'POST') {
return
}
// FIXME checké si utilisateur deja connecté
const locals = Astro.locals
const form = await Astro.request.formData();
const request = {
user: form.get("username") as string,
password: form.get("password") as string
}
try {
await locals.pb.collection('users').authWithPassword(request.user,request.password);
} catch (error) {
console.log(error)
}
return Astro.redirect("/account")
})
---
<Layout title="login">
<form id="account-creation" method="post" enctype="multipart/form-data">
<input required name="username" placeholder="Pseudo ou email"/>
<input required name="password" type="password" placeholder="Mot de passe" />
<button>Connection</button>
</form>
</Layout>

View File

@ -0,0 +1,43 @@
---
import Layout from 'layouts/Layout.astro';
import AstroUtils from 'libs/AstroUtils';
import PocketBase from 'pocketbase'
const pb = Astro.locals.pb as PocketBase
if(pb.authStore.isValid){
return Astro.redirect("/account")
}
await AstroUtils.wrap(async () => {
if (Astro.request.method !== 'POST'){
return
}
const form = await Astro.request.formData()
const request = {
username: form.get("username") as string,
name: form.get("name") as string,
email: form.get("email") as string,
password: form.get("password") as string,
passwordConfirm: form.get("passwordConfirm") as string,
}
try{
await pb.collection('users').create(request)
return Astro.redirect('account/login')
}catch(e){
console.log(e);
}
})
---
<Layout title="register">
<form id="account-creation" method="post" enctype="multipart/form-data">
<input required name="name" placeholder="Prénom Nom"/>
<input required name="username" placeholder="Pseudo"/>
<input required name="email" type="email" placeholder="Renseignez votre email" />
<input required name="password" type="password" placeholder="Créez un mot de passe" />
<input required name="passwordConfirm" type="password" placeholder="Confirmer votre mot de passe" />
<button>Créer un compte</button>
</form>
</Layout>

123
front/src/pages/index.astro Normal file
View File

@ -0,0 +1,123 @@
---
import Layout from 'layouts/Layout.astro';
import Card from 'components/Card.astro';
---
<Layout title="Welcome to Astro.">
<main>
<svg
class="astro-a"
width="495"
height="623"
viewBox="0 0 495 623"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M167.19 364.254C83.4786 364.254 0 404.819 0 404.819C0 404.819 141.781 19.4876 142.087 18.7291C146.434 7.33701 153.027 0 162.289 0H332.441C341.703 0 348.574 7.33701 352.643 18.7291C352.92 19.5022 494.716 404.819 494.716 404.819C494.716 404.819 426.67 364.254 327.525 364.254L264.41 169.408C262.047 159.985 255.147 153.581 247.358 153.581C239.569 153.581 232.669 159.985 230.306 169.408L167.19 364.254ZM160.869 530.172C160.877 530.18 160.885 530.187 160.894 530.195L160.867 530.181C160.868 530.178 160.868 530.175 160.869 530.172ZM136.218 411.348C124.476 450.467 132.698 504.458 160.869 530.172C160.997 529.696 161.125 529.242 161.248 528.804C161.502 527.907 161.737 527.073 161.917 526.233C165.446 509.895 178.754 499.52 195.577 500.01C211.969 500.487 220.67 508.765 223.202 527.254C224.141 534.12 224.23 541.131 224.319 548.105C224.328 548.834 224.337 549.563 224.347 550.291C224.563 566.098 228.657 580.707 237.264 593.914C245.413 606.426 256.108 615.943 270.749 622.478C270.593 621.952 270.463 621.508 270.35 621.126C270.045 620.086 269.872 619.499 269.685 618.911C258.909 585.935 266.668 563.266 295.344 543.933C298.254 541.971 301.187 540.041 304.12 538.112C310.591 533.854 317.059 529.599 323.279 525.007C345.88 508.329 360.09 486.327 363.431 457.844C364.805 446.148 363.781 434.657 359.848 423.275C358.176 424.287 356.587 425.295 355.042 426.275C351.744 428.366 348.647 430.33 345.382 431.934C303.466 452.507 259.152 455.053 214.03 448.245C184.802 443.834 156.584 436.019 136.218 411.348Z"
fill="url(#paint0_linear_1805_24383)"></path>
<defs>
<linearGradient
id="paint0_linear_1805_24383"
x1="247.358"
y1="0"
x2="247.358"
y2="622.479"
gradientUnits="userSpaceOnUse"
>
<stop stop-opacity="0.9"></stop>
<stop offset="1" stop-opacity="0.2"></stop>
</linearGradient>
</defs>
</svg>
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
<p class="instructions">
To get started, open the directory <code>src/pages</code> in your project.<br />
<strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
</p>
<ul role="list" class="link-card-grid">
<Card
href="https://docs.astro.build/"
title="Documentation"
body="Learn how Astro works and explore the official API docs."
/>
<Card
href="https://astro.build/integrations/"
title="Integrations"
body="Supercharge your project with new frameworks and libraries."
/>
<Card
href="https://astro.build/themes/"
title="Themes"
body="Explore a galaxy of community-built starter themes."
/>
<Card
href="https://astro.build/chat/"
title="Community"
body="Come say hi to our amazing Discord community. ❤️"
/>
</ul>
</main>
</Layout>
<style>
main {
margin: auto;
padding: 1rem;
width: 800px;
max-width: calc(100% - 2rem);
color: white;
font-size: 20px;
line-height: 1.6;
}
.astro-a {
position: absolute;
top: -32px;
left: 50%;
transform: translatex(-50%);
width: 220px;
height: auto;
z-index: -1;
}
h1 {
font-size: 4rem;
font-weight: 700;
line-height: 1;
text-align: center;
margin-bottom: 1em;
}
.text-gradient {
background-image: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-size: 400%;
background-position: 0%;
}
.instructions {
margin-bottom: 2rem;
border: 1px solid rgba(var(--accent-light), 25%);
background: linear-gradient(rgba(var(--accent-dark), 66%), rgba(var(--accent-dark), 33%));
padding: 1.5rem;
border-radius: 8px;
}
.instructions code {
font-size: 0.8em;
font-weight: bold;
background: rgba(var(--accent-light), 12%);
color: rgb(var(--accent-light));
border-radius: 4px;
padding: 0.3em 0.4em;
}
.instructions strong {
color: rgb(var(--accent-light));
}
.link-card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
gap: 2rem;
padding: 0;
}
</style>

View File

@ -0,0 +1,17 @@
---
import Layout from 'layouts/Layout.astro';
import { Marker, Popup } from 'leaflet';
import { MapContainer } from 'react-leaflet'
---
<Layout title="maps test">
<MapContainer client:load center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}>
<Marker client:load lat={51.505} lng={-0.09}>
<Popup client:load>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
</Layout>

View File

@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {},
},
plugins: [],
}

11
front/tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": "src",
// hide an issue with typescript
"noUnusedLocals": false
},
"ts-node": {
"esm": true
}
}