Merge branch 'master' into luke

This commit is contained in:
LuckyLaszlo
2023-01-01 22:41:25 +01:00
48 changed files with 2505 additions and 1338 deletions

8
.gitignore vendored
View File

@@ -15,13 +15,11 @@ Thumbs.db
*.log *.log
# compiled output # compiled output
/dist
node_modules node_modules
./srcs/requirement/api_back/node_modules ./srcs/requirement/nestjs/api_back/dist
./srcs/requirement/api_back/dist ./srcs/requirements/svelte/api_front/public/build/
./srcs/requirement/api_front/node_modules
./srcs/requirement/api_front/public/build
# Logs # Logs
logs logs
*.log *.log

View File

@@ -19,10 +19,10 @@ down:
docker compose -f ${DOCKERCOMPOSEPATH} -v down docker compose -f ${DOCKERCOMPOSEPATH} -v down
destroy: destroy:
docker compose -f ${DOCKERCOMPOSEPATH} down -v --rmi all --remove-orphans - docker compose -f ${DOCKERCOMPOSEPATH} down -v --rmi all --remove-orphans
docker ps -aq | xargs --no-run-if-empty docker rm -f - docker ps -aq | xargs --no-run-if-empty docker rm -f
docker images -aq | xargs --no-run-if-empty docker rmi -f - docker images -aq | xargs --no-run-if-empty docker rmi -f
docker volume ls -q | xargs --no-run-if-empty docker volume rm - docker volume ls -q | xargs --no-run-if-empty docker volume rm
stop: stop:
docker compose -f ${DOCKERCOMPOSEPATH} stop docker compose -f ${DOCKERCOMPOSEPATH} stop

View File

@@ -1,3 +1,4 @@
### Pour lancer le docker : ### Pour lancer le docker :
- Il faut un fichier .env qu'on ne doit pas push, donc je ne le push pas. - Il faut un fichier .env qu'on ne doit pas push, donc je ne le push pas.
@@ -6,6 +7,8 @@
- Il faut le placer au même endroit que docker-compose.yml - Il faut le placer au même endroit que docker-compose.yml
- Dans le makefile il y a un sedf pour changer l'un ou l'autre. - Dans le makefile il y a un sedf pour changer l'un ou l'autre.
- also add an alias for transcendance in /etc/hosts
### TODO List : Utilisateur édition. ### TODO List : Utilisateur édition.
@@ -26,40 +29,6 @@
- [ ] Docker : trouver un moyen simple de générer un .env. Peut-être renouveller les clé à chaque lancement. - [ ] Docker : trouver un moyen simple de générer un .env. Peut-être renouveller les clé à chaque lancement.
## questions :
- choose a secondary browser
- choose solution to rootless mode (VM, rebuild, unique root uid)
- choose 2fa method : texto ? Google Authentication ?
- when chat-room owner leaves what happens ?
- can chat-room administrators ban and mute other administrators ?
- game technologie (canvas ?)
---
## tasks :
#### luke
- getting started with Javascript
- getting started with Node.js/Nest.js
- pong game solo front-end (canvas ? js ?)
- add multiplayers to Pong with Node.js (without database, accounts, ...)
#### eric
- getting started with Javascript
- getting started with framework TypeScript front-end (Svelte ?)
- single-page démo, sans back-end
- chat front-end ? (tester avec des messages random locaux)
#### hugo
- getting started with Javascript
- getting started with Node.js/Nest.js
- getting started with PostgreSQL
--- ---
## instructions : ## instructions :
@@ -82,70 +51,81 @@
#### security concerns : #### security concerns :
- [ ] hash every passwords in db - [ ] hash every passwords in db
- [ ] protection against SQL injections - [ ] protection against SQL injections
- [ ] server-side validation of users inputs - [ ] server-side validation of users inputs
- [ ] store credentials in local .env git-ignored - [ ] store credentials in local .env git-ignored
#### user account : #### user account :
- [ ] login with 42 intranet OAuth system - [ ] login with 42 intranet OAuth system
- [ ] user can choose name, avatar, 2fa (ex texto or Google Authenticator) - [ ] user can choose name, avatar, 2fa (ex texto or Google Authenticator)
- [ ] display user name on site - [ ] display user name on site
- [ ] user default avatar if not chosen - [ ] user default avatar if not chosen
- [ ] user can add friends, and see status (online/offline, in game, ...) - [ ] user can add friends, and see status (online/offline, in game, ...)
- [ ] display stats on user profile (wins, losses, ladderm levelm achievements, ...) - [ ] display stats on user profile (wins, losses, ladderm levelm achievements, ...)
- [ ] public match history (lvl games, ladder, ...) - [ ] public match history (lvl games, ladder, ...)
#### chat : #### chat :
- [ ] can create chat-rooms (public/private, password protected) - [ ] can create chat-rooms (public/private, password protected)
- [ ] send direct messages - [ ] send direct messages
- [ ] block other users - [ ] block other users
- [ ] creators of chat-room are owners, untill they leave - [ ] creators of chat-room are owners, untill they leave
- [ ] chat-room owner can set, change, remove password - [ ] chat-room owner can set, change, remove password
- [ ] chat-room owner is administrator and can set other administrators - [ ] chat-room owner is administrator and can set other administrators
- [ ] administrators can ban or mute for a time other users - [ ] administrators can ban or mute for a time other users
- [ ] send game invitation in chat - [ ] send game invitation in chat
- [ ] view user profiles from chat - [ ] view user profiles from chat
#### game : #### game :
- [ ] play pong with others on website - [ ] play pong with others on website
- [ ] matchmaking system : join a queue untill automatic match - [ ] matchmaking system : join a queue untill automatic match
- [ ] faithfull to original pong (1972) - [ ] faithfull to original pong (1972)
- [ ] customs options (powers up, multiple maps, ...), with a default one - [ ] customs options (powers up, multiple maps, ...), with a default one
- [ ] reponsive - [ ] reponsive
- [ ] can watch other matchs - [ ] can watch other matchs
--- ---
## Resources ## Resources
- [routes back](https://semestriel.framapad.org/p/z5gqbq51dx-9xlo?lang=fr)
### error msg
- [rollup packages did not export](https://stackoverflow.com/questions/69768925/rollup-plugin-svelte-the-following-packages-did-not-export-their-package-json)
### Svelte ### Svelte
- [The Official Svelte Tutorial](https://svelte.dev/tutorial/basics) - [The Official Svelte Tutorial](https://svelte.dev/tutorial/basics)
- SPA Svelte Article [Build a single-page application in Svelte with svelte-spa-router](https://blog.logrocket.com/build-spa-svelte-svelte-spa-router/) - SPA Svelte Article [Build a single-page application in Svelte with svelte-spa-router](https://blog.logrocket.com/build-spa-svelte-svelte-spa-router/)
- [An excellent Svelt Tutorial video series](https://www.youtube.com/watch?v=zojEMeQGGHs&list=PL4cUxeGkcC9hlbrVO_2QFVqVPhlZmz7tO&index=2) - [An excellent Svelt Tutorial video series](https://www.youtube.com/watch?v=zojEMeQGGHs&list=PL4cUxeGkcC9hlbrVO_2QFVqVPhlZmz7tO&index=2)
- to check svelte logs, do a 'docker logs --follow <container-id>'
### nestjs
- [linkedin clone angular nestjs](https://www.youtube.com/watch?v=gL3D-MIt_G8&list=PL9_OU-1M9E_ut3NA04C4eHZuuAFQOUwT0&index=1)
- [nestjs crash course](https://www.youtube.com/watch?v=vGafqCNCCSs)
### websocket
- [game networking](https://gafferongames.com/post/what_every_programmer_needs_to_know_about_game_networking/)
- [client-server game architecture](https://www.gabrielgambetta.com/client-server-game-architecture.html)
- [websocket api mozilla doc](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
- [websocket rfc](https://www.rfc-editor.org/rfc/rfc6455.html)
- [ws doc npm](https://www.npmjs.com/package/ws)
- [exemple chat implementation](https://github.com/mdn/samples-server/tree/master/s/websocket-chat)
- [websocket and nginx](https://www.nginx.com/blog/websocket-nginx/)
### css
- [separation of concern](https://adamwathan.me/css-utility-classes-and-separation-of-concerns/)
- [decoupling css and html](https://www.smashingmagazine.com/2012/04/decoupling-html-from-css/)
### security
- [xss attack with innerHTML](https://gomakethings.com/a-safer-alternative-to-innerhtml-with-vanilla-js/)
- [xss attack innerHTML prevention](https://stackoverflow.com/questions/30661497/xss-prevention-and-innerhtml)
- [xss attack prevention with createTextNode](https://stackoverflow.com/questions/11654555/is-createtextnode-completely-safe-from-html-injection-xss)
- [xss attacks prevention in svelte](https://stackoverflow.com/questions/74931516/in-svete-what-to-use-instead-of-html-to-avoid-xss-attacks/74932137)
### installation
- [node and npm with nvm](https://github.com/nvm-sh/nvm)
- [docker](https://github.com/docker/docker-install)

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1,87 +1,98 @@
#! /usr/bin/env bash #! /usr/bin/env bash
# This script is used to create a new environment for the project.
# Create a new environment for docker
# Function to generate passwords
#
function generate_password
{
# base64 alphabet is alphanumeric characters and "+", "/", "="
# https://en.wikipedia.org/wiki/Base64#Base64_table_from_RFC_4648
# we could delete them 'tr -d "+/="', but that would randomly shorten the string
echo $(openssl rand -base64 32 | tr "/" "_" );
}
# This script is used to create a new environment for the project.
#
ENV_FILE_DOCKER=./srcs/.env ENV_FILE_DOCKER=./srcs/.env
ENV_FILE_NESTJS=./srcs/requirements/nestjs/api_back/.env ENV_FILE_NESTJS=./srcs/requirements/nestjs/api_back/.env
# Check for existing .env
# Create a new environment for docker
if [ -f "$ENV_FILE_DOCKER" ] && [ -f "$ENV_FILE_NESTJS" ]; then if [ -f "$ENV_FILE_DOCKER" ] && [ -f "$ENV_FILE_NESTJS" ]; then
echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS already exists. Do you want to overwrite them ? (y/n)" echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS already exists. Do you want to overwrite them ? (y/n)"
OVERWRITE=""
# Ask to overwrite the .env files
while [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "n" ]; do
read -p "Enter your choice : " OVERWRITE read -p "Enter your choice : " OVERWRITE
done
if [ "$OVERWRITE" = "y" ]; then if [ "$OVERWRITE" = "y" ]; then
rm "$ENV_FILE_DOCKER" && rm "$ENV_FILE_NESTJS" rm "$ENV_FILE_DOCKER" && rm "$ENV_FILE_NESTJS"
docker rmi -f postgres
else else
echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS will not be overwritten. The script will exit." echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS will not be overwritten. The script will exit."
exit 0 exit 0
fi fi
fi fi
echo "Creating a new environment for docker"
read -p "Enter the env configuration for nestjs : \"1\" for development OR \"2\" for production : " NODE_ENV
# Create a new environment for docker
#
echo "Creating a new environment for docker"
NODE_ENV=""
# Ask if dev or prod environment
while [ "$NODE_ENV" != "1" ] && [ "$NODE_ENV" != "2" ]; do
read -p "Enter the env configuration for nestjs : \"1\" for development OR \"2\" for production : " NODE_ENV
done
if [ "$NODE_ENV" = "1" ]; then if [ "$NODE_ENV" = "1" ]; then
echo "NODE_ENV=development" > "$ENV_FILE_DOCKER" echo "NODE_ENV=development" > "$ENV_FILE_DOCKER"
elif [ "$NODE_ENV" = "2" ]; then
echo "NODE_ENV=production" > "$ENV_FILE_DOCKER"
else else
echo "You entered a wrong value. The default value will be used (development)." echo "NODE_ENV=production" > "$ENV_FILE_DOCKER"
echo "NODE_ENV=development" > "$ENV_FILE_DOCKER"
fi fi
# Env variables
read -p "Enter the name of the host like \"localhost\" : " PROJECT_HOST read -p "Enter the name of the host like \"localhost\" : " PROJECT_HOST
echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_DOCKER" echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_DOCKER"
echo "WEBSITE_PORT=8080" >> "$ENV_FILE_DOCKER" echo "WEBSITE_PORT=8080" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_USER=postgres" >> "$ENV_FILE_DOCKER" echo "POSTGRES_USER=postgres" >> "$ENV_FILE_DOCKER"
POSTGRES_PASSWORD=$(openssl rand -base64 32) echo "#if change postgres pswd, do make destroy" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> "$ENV_FILE_DOCKER" echo "POSTGRES_PASSWORD=$(generate_password)" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_DOCKER" echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_DOCKER" echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_PORT=5432" >> "$ENV_FILE_DOCKER" echo "POSTGRES_PORT=5432" >> "$ENV_FILE_DOCKER"
echo "REDIS_HOST=redis" >> "$ENV_FILE_DOCKER" echo "REDIS_HOST=redis" >> "$ENV_FILE_DOCKER"
echo "REDIS_PORT=6379" >> "$ENV_FILE_DOCKER" echo "REDIS_PORT=6379" >> "$ENV_FILE_DOCKER"
echo "REDIS_PASSWORD=$(openssl rand -base64 32)" >> "$ENV_FILE_DOCKER" echo "REDIS_PASSWORD=$(generate_password)" >> "$ENV_FILE_DOCKER"
# Create a new environment for nestjs # Create a new environment for nestjs
#
echo "Creating a new environment for nestjs" echo "Creating a new environment for nestjs"
echo "NODE_ENV=\$NODE_ENV" > "$ENV_FILE_NESTJS"
if [ "$NODE_ENV" = "1" ]; then echo "WEBSITE_HOST=\$WEBSITE_HOST" >> "$ENV_FILE_NESTJS"
echo "NODE_ENV=development" > "$ENV_FILE_NESTJS" echo "WEBSITE_PORT=\$WEBSITE_PORT" >> "$ENV_FILE_NESTJS"
elif [ "$NODE_ENV" = "2" ]; then echo "POSTGRES_USER=\$POSTGRES_USER" >> "$ENV_FILE_NESTJS"
echo "NODE_ENV=production" > "$ENV_FILE_NESTJS" echo "POSTGRES_PASSWORD=\$POSTGRES_PASSWORD" >> "$ENV_FILE_NESTJS"
else echo "POSTGRES_DB=\$POSTGRES_DB" >> "$ENV_FILE_NESTJS"
echo "NODE_ENV=development" > "$ENV_FILE_NESTJS" echo "POSTGRES_HOST=\$POSTGRES_HOST" >> "$ENV_FILE_NESTJS"
fi echo "POSTGRES_PORT=\$POSTGRES_PORT" >> "$ENV_FILE_NESTJS"
# Connection to 42
echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_NESTJS"
echo "WEBSITE_PORT=8080" >> "$ENV_FILE_NESTJS"
echo "POSTGRES_USER=postgres" >> "$ENV_FILE_NESTJS"
echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> "$ENV_FILE_NESTJS"
echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_NESTJS"
echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_NESTJS"
echo "POSTGRES_PORT=5432" >> "$ENV_FILE_NESTJS"
echo "In the next steps, we'll need to enter the client secret and client id of the 42 api" echo "In the next steps, we'll need to enter the client secret and client id of the 42 api"
read -p "Enter the client id of the 42 api : " CLIENT_ID read -p "Enter the client id of the 42 api : " CLIENT_ID
echo "FORTYTWO_CLIENT_ID=$CLIENT_ID" >> "$ENV_FILE_NESTJS" echo "FORTYTWO_CLIENT_ID=$CLIENT_ID" >> "$ENV_FILE_NESTJS"
read -p "Enter the client secret of the 42 api : " CLIENT_SECRET read -p "Enter the client secret of the 42 api : " CLIENT_SECRET
echo "FORTYTWO_CLIENT_SECRET=$CLIENT_SECRET" >> "$ENV_FILE_NESTJS" echo "FORTYTWO_CLIENT_SECRET=$CLIENT_SECRET" >> "$ENV_FILE_NESTJS"
echo "FORTYTWO_CALLBACK_URL=http://$PROJECT_HOST:8080/api/v2/auth/redirect" >> "$ENV_FILE_NESTJS" FT_CALLBACK="http://\$WEBSITE_HOST:\$WEBSITE_PORT/api/v2/auth/redirect"
echo "FORTYTWO_CALLBACK_URL=$FT_CALLBACK" >> "$ENV_FILE_NESTJS"
echo "COOKIE_SECRET=$(openssl rand -base64 32)" >> "$ENV_FILE_NESTJS" # Other configs
echo "COOKIE_SECRET=$(generate_password)" >> "$ENV_FILE_NESTJS"
echo "PORT=3000" >> "$ENV_FILE_NESTJS" echo "PORT=3000" >> "$ENV_FILE_NESTJS"
echo "REDIS_HOST=redis" >> "$ENV_FILE_DOCKER"
echo "REDIS_PORT=6379" >> "$ENV_FILE_DOCKER"
echo "REDIS_PASSWORD=$REDIS_PASSWORD" >> "$ENV_FILE_DOCKER"
echo "TWO_FACTOR_AUTHENTICATION_APP_NAME=Transcendance" >> "$ENV_FILE_NESTJS" echo "TWO_FACTOR_AUTHENTICATION_APP_NAME=Transcendance" >> "$ENV_FILE_NESTJS"
echo "TICKET_FOR_PLAYING_GAME_SECRET=$(generate_password)" >> "$ENV_FILE_NESTJS"
echo "TICKET_FOR_PLAYING_GAME_SECRET=$(openssl rand -base64 32)" >> "$ENV_FILE_NESTJS"
# it's finished !
#
echo "The environment has been created successfully. You can now wait for the docker to build the project." echo "The environment has been created successfully. You can now wait for the docker to build the project."

3
package-lock.json generated Normal file
View File

@@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

View File

@@ -5,6 +5,16 @@ services:
context: ./requirements/nestjs context: ./requirements/nestjs
target: development target: development
dockerfile: Dockerfile dockerfile: Dockerfile
no_cache: true
args:
- NODE_ENV=${NODE_ENV}
- WEBSITE_HOST=${WEBSITE_HOST}
- WEBSITE_PORT=${WEBSITE_PORT}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_HOST=${POSTGRES_HOST}
- POSTGRES_PORT=${POSTGRES_PORT}
volumes: volumes:
- ./requirements/nestjs/api_back/src:/usr/app/src - ./requirements/nestjs/api_back/src:/usr/app/src
- ./requirements/nestjs/api_back/test:/usr/app/test/ - ./requirements/nestjs/api_back/test:/usr/app/test/

View File

@@ -2,11 +2,47 @@ FROM node:alpine AS development
WORKDIR /usr/app WORKDIR /usr/app
ARG NODE_ENV
ARG WEBSITE_HOST
ARG WEBSITE_PORT
ARG POSTGRES_USER
ARG POSTGRES_PASSWORD
ARG POSTGRES_DB
ARG POSTGRES_HOST
ARG POSTGRES_PORT
COPY ./api_back ./ COPY ./api_back ./
COPY ./api_back/.env ./.env
COPY ./api_back/src/uploads/avatars/default.png ./uploads/avatars/default.png COPY ./api_back/src/uploads/avatars/default.png ./uploads/avatars/default.png
COPY ./api_back/.env ./.env
#RUN sed -i "s/\$NODE_ENV/${NODE_ENV}/g" ./.env && \
# sed -i "s/\$WEBSITE_HOST/${WEBSITE_HOST}/g" ./.env && \
# sed -i "s/\$WEBSITE_PORT/${WEBSITE_PORT}/g" ./.env && \
# sed -i "s/\$POSTGRES_USER/${POSTGRES_USER}/g" ./.env && \
# sed -i "s/\$POSTGRES_PASSWORD/${POSTGRES_PASSWORD}/g" ./.env && \
# sed -i "s/\$POSTGRES_DB/${POSTGRES_DB}/g" ./.env && \
# sed -i "s/\$POSTGRES_HOST/${POSTGRES_HOST}/g" ./.env && \
# sed -i "s/\$POSTGRES_PORT/${POSTGRES_PORT}/g" ./.env
RUN sed -i "s/\$NODE_ENV/${NODE_ENV}/g" ./.env
RUN sed -i "s/\$WEBSITE_HOST/${WEBSITE_HOST}/g" ./.env
RUN sed -i "s/\$WEBSITE_PORT/${WEBSITE_PORT}/g" ./.env
RUN sed -i "s/\$POSTGRES_USER/${POSTGRES_USER}/g" ./.env
RUN echo ["$POSTGRESS_PASSWORD"] && \
echo ["$POSTGRESS_PASSWORD"] && \
echo ["$POSTGRESS_PASSWORD"] && \
echo ["$POSTGRESS_PASSWORD"] && \
echo ["$POSTGRESS_PASSWORD"] && \
echo ["$POSTGRESS_PASSWORD"] && \
echo ["$POSTGRESS_PASSWORD"] && \
sed -i "s/\$POSTGRES_PASSWORD/'${POSTGRESS_PASSWORD}'/g" ./.env
RUN sed -i "s/\$POSTGRES_DB/${POSTGRES_DB}/g" ./.env
RUN sed -i "s/\$POSTGRES_HOST/${POSTGRES_HOST}/g" ./.env
RUN sed -i "s/\$POSTGRES_PORT/${POSTGRES_PORT}/g" ./.env
RUN npm install RUN npm install
RUN npm ci RUN npm ci
CMD [ "npm", "run", "start:dev" ] CMD [ "npm", "run", "start:dev" ]

View File

@@ -15,7 +15,9 @@
"@nestjs/mapped-types": "^1.2.0", "@nestjs/mapped-types": "^1.2.0",
"@nestjs/passport": "^9.0.0", "@nestjs/passport": "^9.0.0",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-socket.io": "^9.2.1",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^9.0.1",
"@nestjs/websockets": "^9.2.1",
"@types/express-session": "^1.17.5", "@types/express-session": "^1.17.5",
"@types/redis": "^4.0.11", "@types/redis": "^4.0.11",
"@types/validator": "^13.7.9", "@types/validator": "^13.7.9",
@@ -35,6 +37,7 @@
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0", "rxjs": "^7.2.0",
"socket.io": "^4.5.4",
"typeorm": "^0.3.10", "typeorm": "^0.3.10",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },
@@ -1691,6 +1694,104 @@
"@nestjs/core": "^9.0.0" "@nestjs/core": "^9.0.0"
} }
}, },
"node_modules/@nestjs/platform-express/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/@nestjs/platform-express/node_modules/express": {
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz",
"integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.0",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7",
"qs": "6.10.3",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/@nestjs/platform-express/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/@nestjs/platform-express/node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"node_modules/@nestjs/platform-socket.io": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-9.2.1.tgz",
"integrity": "sha512-McLXgmkNDvYhX4RcudpLa/RNvy7NA4vb+7gJxJ12yp189Ijcaoktrex1a4F7PPQ5iKACiI/D0rfvQAe9P1ez+g==",
"dependencies": {
"socket.io": "4.5.3",
"tslib": "2.4.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/nest"
},
"peerDependencies": {
"@nestjs/common": "^9.0.0",
"@nestjs/websockets": "^9.0.0",
"rxjs": "^7.1.0"
}
},
"node_modules/@nestjs/platform-socket.io/node_modules/socket.io": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz",
"integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.2",
"engine.io": "~6.2.0",
"socket.io-adapter": "~2.4.0",
"socket.io-parser": "~4.2.0"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/@nestjs/platform-socket.io/node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"node_modules/@nestjs/schematics": { "node_modules/@nestjs/schematics": {
"version": "9.0.3", "version": "9.0.3",
"resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.0.3.tgz", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.0.3.tgz",
@@ -1837,6 +1938,33 @@
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
}, },
"node_modules/@nestjs/websockets": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-9.2.1.tgz",
"integrity": "sha512-3VYyjLybobsWp6fPtOIGmZL83nV0nzqs+A2KoMf6PxVuFQeTT+BYJqbYE3I1D2wE9d9m81U1efpIeOuL8CXRAQ==",
"dependencies": {
"iterare": "1.2.1",
"object-hash": "3.0.0",
"tslib": "2.4.1"
},
"peerDependencies": {
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-socket.io": "^9.0.0",
"reflect-metadata": "^0.1.12",
"rxjs": "^7.1.0"
},
"peerDependenciesMeta": {
"@nestjs/platform-socket.io": {
"optional": true
}
}
},
"node_modules/@nestjs/websockets/node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2023,6 +2151,11 @@
"@sinonjs/commons": "^1.7.0" "@sinonjs/commons": "^1.7.0"
} }
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"node_modules/@sqltools/formatter": { "node_modules/@sqltools/formatter": {
"version": "1.2.5", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz",
@@ -2110,12 +2243,25 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"node_modules/@types/cookiejar": { "node_modules/@types/cookiejar": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz",
"integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==",
"dev": true "dev": true
}, },
"node_modules/@types/cors": {
"version": "2.8.13",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "8.4.10", "version": "8.4.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz",
@@ -3046,6 +3192,14 @@
} }
] ]
}, },
"node_modules/base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"engines": {
"node": "^4.5.0 || >= 5.9"
}
},
"node_modules/base64url": { "node_modules/base64url": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
@@ -3974,6 +4128,42 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"node_modules/engine.io": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz",
"integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==",
"dependencies": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.2.3"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/engine.io-parser": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/engine.io/node_modules/cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.12.0", "version": "5.12.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
@@ -8278,6 +8468,39 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/socket.io": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz",
"integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.2",
"engine.io": "~6.2.1",
"socket.io-adapter": "~2.4.0",
"socket.io-parser": "~4.2.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-adapter": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz",
"integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg=="
},
"node_modules/socket.io-parser": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz",
"integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.7.4", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
@@ -9556,6 +9779,26 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0" "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
} }
}, },
"node_modules/ws": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xml2js": { "node_modules/xml2js": {
"version": "0.4.23", "version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
@@ -10868,6 +11111,35 @@
"tslib": "2.4.1" "tslib": "2.4.1"
} }
}, },
"@nestjs/platform-socket.io": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@nestjs/platform-socket.io/-/platform-socket.io-9.2.1.tgz",
"integrity": "sha512-McLXgmkNDvYhX4RcudpLa/RNvy7NA4vb+7gJxJ12yp189Ijcaoktrex1a4F7PPQ5iKACiI/D0rfvQAe9P1ez+g==",
"requires": {
"socket.io": "4.5.3",
"tslib": "2.4.1"
},
"dependencies": {
"socket.io": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz",
"integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==",
"requires": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.2",
"engine.io": "~6.2.0",
"socket.io-adapter": "~2.4.0",
"socket.io-parser": "~4.2.0"
}
},
"tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
}
}
},
"@nestjs/schematics": { "@nestjs/schematics": {
"version": "9.0.3", "version": "9.0.3",
"resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.0.3.tgz", "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-9.0.3.tgz",
@@ -10970,6 +11242,23 @@
} }
} }
}, },
"@nestjs/websockets": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-9.2.1.tgz",
"integrity": "sha512-3VYyjLybobsWp6fPtOIGmZL83nV0nzqs+A2KoMf6PxVuFQeTT+BYJqbYE3I1D2wE9d9m81U1efpIeOuL8CXRAQ==",
"requires": {
"iterare": "1.2.1",
"object-hash": "3.0.0",
"tslib": "2.4.1"
},
"dependencies": {
"tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
}
}
},
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -11123,6 +11412,11 @@
"@sinonjs/commons": "^1.7.0" "@sinonjs/commons": "^1.7.0"
} }
}, },
"@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"@sqltools/formatter": { "@sqltools/formatter": {
"version": "1.2.5", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz",
@@ -11210,12 +11504,25 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"@types/cookiejar": { "@types/cookiejar": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz",
"integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==",
"dev": true "dev": true
}, },
"@types/cors": {
"version": "2.8.13",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
"requires": {
"@types/node": "*"
}
},
"@types/eslint": { "@types/eslint": {
"version": "8.4.10", "version": "8.4.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz",
@@ -11958,6 +12265,11 @@
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
}, },
"base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
},
"base64url": { "base64url": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
@@ -12643,6 +12955,35 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"engine.io": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz",
"integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==",
"requires": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.4.1",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.2.3"
},
"dependencies": {
"cookie": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
}
}
},
"engine.io-parser": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
},
"enhanced-resolve": { "enhanced-resolve": {
"version": "5.12.0", "version": "5.12.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
@@ -15876,6 +16217,33 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true "dev": true
}, },
"socket.io": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz",
"integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==",
"requires": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.2",
"engine.io": "~6.2.1",
"socket.io-adapter": "~2.4.0",
"socket.io-parser": "~4.2.1"
}
},
"socket.io-adapter": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz",
"integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg=="
},
"socket.io-parser": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz",
"integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
}
},
"source-map": { "source-map": {
"version": "0.7.4", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
@@ -16719,6 +17087,12 @@
"signal-exit": "^3.0.7" "signal-exit": "^3.0.7"
} }
}, },
"ws": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"requires": {}
},
"xml2js": { "xml2js": {
"version": "0.4.23", "version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",

View File

@@ -27,7 +27,9 @@
"@nestjs/mapped-types": "^1.2.0", "@nestjs/mapped-types": "^1.2.0",
"@nestjs/passport": "^9.0.0", "@nestjs/passport": "^9.0.0",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-socket.io": "^9.2.1",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^9.0.1",
"@nestjs/websockets": "^9.2.1",
"@types/express-session": "^1.17.5", "@types/express-session": "^1.17.5",
"@types/validator": "^13.7.9", "@types/validator": "^13.7.9",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
@@ -46,6 +48,7 @@
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.2.0", "rxjs": "^7.2.0",
"socket.io": "^4.5.4",
"typeorm": "^0.3.10", "typeorm": "^0.3.10",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },

View File

@@ -8,9 +8,11 @@ import { FriendshipsModule } from './friendship/friendships.module';
import { AuthenticationModule } from './auth/42/authentication.module'; import { AuthenticationModule } from './auth/42/authentication.module';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { GameModule } from './game/game.module'; import { GameModule } from './game/game.module';
import { ChatGateway } from './chat/chat.gateway';
@Module({ @Module({
imports: [UsersModule, imports: [
UsersModule,
AuthenticationModule, AuthenticationModule,
PassportModule.register({ session: true }), PassportModule.register({ session: true }),
FriendshipsModule, FriendshipsModule,
@@ -28,8 +30,12 @@ import { GameModule } from './game/game.module';
//avec une classe pour le module //avec une classe pour le module
synchronize: true, synchronize: true,
}), }),
// GameModule,
], ],
controllers: [AppController], controllers: [AppController],
providers: [AppService], providers: [
AppService,
ChatGateway,
],
}) })
export class AppModule {} export class AppModule {}

View File

@@ -0,0 +1,41 @@
import {
WebSocketGateway,
SubscribeMessage,
WebSocketServer,
MessageBody,
OnGatewayConnection,
OnGatewayDisconnect,
} from '@nestjs/websockets';
import { UsersService } from 'src/users/users.service';
import { PaginationQueryDto } from 'src/common/dto/pagination-query.dto';
@WebSocketGateway(5000, {
path: '/chat',
})
export class ChatGateway
implements OnGatewayConnection, OnGatewayDisconnect
{
constructor
(
private usersService: UsersService,
) {}
@WebSocketServer()
server;
// how to guard the handleConnection ?
// https://github.com/nestjs/nest/issues/882
async handleConnection(client) {
const paginationQuery = new PaginationQueryDto();
const users = await this.usersService.findAll(paginationQuery);
console.log('---- Client connected :', client.id);
console.log('users :', users);
}
handleDisconnect(client) {
console.log('---- client disconnected :', client.id);
}
/*
*/
}

View File

@@ -1,4 +1,5 @@
server { server {
listen 8080 default_server; listen 8080 default_server;
listen [::]:8080 default_server; listen [::]:8080 default_server;
server_name transcendance; server_name transcendance;
@@ -11,6 +12,15 @@ server {
proxy_pass http://backend_dev:3000; proxy_pass http://backend_dev:3000;
} }
location /chat {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://backend_dev:5000/chat;
}
location /api/v2/game/gameserver { location /api/v2/game/gameserver {
deny all; deny all;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,7 @@
}, },
"dependencies": { "dependencies": {
"sirv-cli": "^2.0.0", "sirv-cli": "^2.0.0",
"socket.io-client": "^4.5.4",
"svelte-spa-router": "^3.3.0" "svelte-spa-router": "^3.3.0"
} }
} }

View File

@@ -1,3 +1,4 @@
html, body { html, body {
position: relative; position: relative;
width: 100%; width: 100%;

View File

@@ -0,0 +1,5 @@
<script context="module">
export const Domain = "transcendance";
export const Port = "8080";
export const PortIo = "8080";
</script>

View File

@@ -3,12 +3,13 @@
import { push } from "svelte-spa-router"; import { push } from "svelte-spa-router";
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { get } from "svelte/store"; import { get } from "svelte/store";
import { Domain, Port } from "../Constantes.svelte";
let user; let user;
onMount(async () => { onMount(async () => {
user = await fetch('http://transcendance:8080/api/v2/user') user = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then((resp) => resp.json()) .then((resp) => resp.json())
// i mean i could do a failed to load user or some shit, maybe with a .catch or something? but atm why bother // i mean i could do a failed to load user or some shit, maybe with a .catch or something? but atm why bother
@@ -32,14 +33,14 @@
}); });
const login = async() => { const login = async() => {
window.location.href = 'http://transcendance:8080/api/v2/auth'; window.location.href = `http://${Domain}:${Port}/api/v2/auth`;
console.log('you are now logged in'); console.log('you are now logged in');
} }
// i could prolly put this in it's own compoent, i seem to use it in several places... or maybe just some JS? like no need for html // i could prolly put this in it's own compoent, i seem to use it in several places... or maybe just some JS? like no need for html
// we could .then( () => replace('/') ) need the func so TS compatible... // we could .then( () => replace('/') ) need the func so TS compatible...
const logout = async() => { const logout = async() => {
await fetch('http://transcendance:8080/api/v2/auth/logout', { await fetch(`http://${Domain}:${Port}/api/v2/auth/logout`, {
method: 'POST', method: 'POST',
}); });
user = undefined; user = undefined;

View File

@@ -1,9 +1,10 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { push } from "svelte-spa-router"; import { push } from "svelte-spa-router";
import { Domain, Port } from "../Constantes.svelte";
// onMount( async() => { // onMount( async() => {
// await fetch("http://transcendance:8080/api/v2/auth/2fa/generate", // await fetch(`http://${Domain}:${Port}/api/v2/auth/2fa/generate`,
// { // {
// method: 'POST', // method: 'POST',
// }) // })
@@ -19,7 +20,7 @@
let qrCode = ""; let qrCode = "";
let wrongCode = ""; let wrongCode = "";
const fetchQrCodeImg = (async() => { const fetchQrCodeImg = (async() => {
await fetch("http://transcendance:8080/api/v2/auth/2fa/generate", await fetch(`http://${Domain}:${Port}/api/v2/auth/2fa/generate`,
{ {
method: 'POST', method: 'POST',
}) })
@@ -31,7 +32,7 @@
})() })()
const submitCode = async() => { const submitCode = async() => {
const response = await fetch("http://transcendance:8080/api/v2/auth/2fa/check", const response = await fetch(`http://${Domain}:${Port}/api/v2/auth/2fa/check`,
{ {
method : 'POST', method : 'POST',
headers : { headers : {

View File

@@ -3,6 +3,7 @@
import { onMount, onDestroy } from "svelte"; import { onMount, onDestroy } from "svelte";
import Header from '../../pieces/Header.svelte'; import Header from '../../pieces/Header.svelte';
import { fade, fly } from 'svelte/transition'; import { fade, fly } from 'svelte/transition';
import { Domain, Port } from "../../Constantes.svelte";
import * as pong from "./client/pong"; import * as pong from "./client/pong";
import { gameState } from "./client/ws"; import { gameState } from "./client/ws";
@@ -34,9 +35,9 @@
let idOfIntevalCheckTerminationOfTheMatch; let idOfIntevalCheckTerminationOfTheMatch;
onMount( async() => { onMount( async() => {
user = await fetch('http://transcendance:8080/api/v2/user') user = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then( x => x.json() ); .then( x => x.json() );
allUsers = await fetch('http://transcendance:8080/api/v2/user/all') allUsers = await fetch(`http://${Domain}:${Port}/api/v2/user/all`)
.then( x => x.json() ); .then( x => x.json() );
options.playerOneUsername = user.username; options.playerOneUsername = user.username;
}) })
@@ -52,7 +53,7 @@
showWaitPage = true; showWaitPage = true;
const matchOptions = pong.computeMatchOptions(options); const matchOptions = pong.computeMatchOptions(options);
const responseWhenGrantToken = fetch("http://transcendance:8080/api/v2/game/ticket", { const responseWhenGrantToken = fetch(`http://${Domain}:${Port}/api/v2/game/ticket`, {
method : "POST", method : "POST",
headers : {'Content-Type': 'application/json'}, headers : {'Content-Type': 'application/json'},
body : JSON.stringify({ body : JSON.stringify({
@@ -140,13 +141,13 @@
const showInvitation = async() => { const showInvitation = async() => {
showGameOption = false; showGameOption = false;
showInvitations = true; showInvitations = true;
invitations = await fetch("http://transcendance:8080/api/v2/game/invitations") invitations = await fetch(`http://${Domain}:${Port}/api/v2/game/invitations`)
.then(x => x.json()) .then(x => x.json())
invitations.length !== 0 ? isThereAnyInvitation = true : isThereAnyInvitation = false invitations.length !== 0 ? isThereAnyInvitation = true : isThereAnyInvitation = false
} }
const rejectInvitation = async(invitation) => { const rejectInvitation = async(invitation) => {
await fetch("http://transcendance:8080/api/v2/game/decline",{ await fetch(`http://${Domain}:${Port}/api/v2/game/decline`, {
method: "POST", method: "POST",
headers: { 'Content-Type': 'application/json'}, headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
@@ -159,7 +160,7 @@
} }
const acceptInvitation = async(invitation : any) => { const acceptInvitation = async(invitation : any) => {
const res = await fetch("http://transcendance:8080/api/v2/game/accept",{ const res = await fetch(`http://${Domain}:${Port}/api/v2/game/accept`, {
method: "POST", method: "POST",
headers: { 'Content-Type': 'application/json'}, headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({

View File

@@ -4,6 +4,7 @@
import Header from '../../pieces/Header.svelte'; import Header from '../../pieces/Header.svelte';
import MatchListElem from "../../pieces/MatchListElem.svelte"; import MatchListElem from "../../pieces/MatchListElem.svelte";
import { fade, fly } from 'svelte/transition'; import { fade, fly } from 'svelte/transition';
import { Domain, Port } from "../../Constantes.svelte";
import * as pongSpectator from "./client/pongSpectator"; import * as pongSpectator from "./client/pongSpectator";
import { gameState } from "./client/ws"; import { gameState } from "./client/ws";
@@ -48,9 +49,9 @@
let hiddenGame = true; let hiddenGame = true;
onMount( async() => { onMount( async() => {
user = await fetch('http://transcendance:8080/api/v2/user') user = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then( x => x.json() ); .then( x => x.json() );
allUsers = await fetch('http://transcendance:8080/api/v2/user/all') allUsers = await fetch(`http://${Domain}:${Port}/api/v2/user/all`)
.then( x => x.json() ); .then( x => x.json() );
// WIP: fetch for match list here // WIP: fetch for match list here
matchList = dummyMatchList; matchList = dummyMatchList;

View File

@@ -2,15 +2,16 @@
<script lang="ts"> <script lang="ts">
import { onMount, onDestroy } from "svelte"; import { onMount, onDestroy } from "svelte";
import Header from "../../pieces/Header.svelte"; import Header from "../../pieces/Header.svelte";
import { Domain, Port } from "../../Constantes.svelte";
//user's stuff //user's stuff
let currentUser; let currentUser;
let allUsers = []; let allUsers = [];
let idInterval; let idInterval;
onMount( async() => { onMount( async() => {
currentUser = await fetch('http://transcendance:8080/api/v2/user') currentUser = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then( x => x.json() ); .then( x => x.json() );
allUsers = await fetch('http://transcendance:8080/api/v2/game/ranking') allUsers = await fetch(`http://${Domain}:${Port}/api/v2/game/ranking`)
.then( x => x.json() ); .then( x => x.json() );
idInterval = setInterval(fetchScores, 10000); idInterval = setInterval(fetchScores, 10000);
}) })
@@ -20,7 +21,7 @@
}) })
function fetchScores() { function fetchScores() {
fetch('http://transcendance:8080/api/v2/game/ranking') fetch(`http://${Domain}:${Port}/api/v2/game/ranking`)
.then( x => x.json() ) .then( x => x.json() )
.then( x => allUsers = x ); .then( x => allUsers = x );
} }

View File

@@ -2,20 +2,23 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import GenerateUserDisplay from '../../pieces/GenerateUserDisplay.svelte'; import GenerateUserDisplay from '../../pieces/GenerateUserDisplay.svelte';
import { Domain, Port } from "../../Constantes.svelte";
import Chat from '../../pieces/chat/Chat.svelte';
let user; let user;
onMount( async() => { onMount( async() => {
// console.log('mounting profile display') // console.log('mounting profile display')
user = await fetch('http://transcendance:8080/api/v2/user') user = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then( (x) => x.json() ); .then( (x) => x.json() );
}) })
</script> </script>
<Chat color="bisque"/>
<!-- is this if excessive? --> <!-- is this if excessive? -->
<div class="outer"> <div class="outer">
<!-- OHHHH i could use #await instead of if and have an nice loading page! --> <!-- OHHHH i could use #await instead of if and have an nice loading page! -->

View File

@@ -2,6 +2,7 @@
import { onMount } from "svelte"; import { onMount } from "svelte";
import { binding_callbacks } from "svelte/internal"; import { binding_callbacks } from "svelte/internal";
import { Domain, Port } from "../../Constantes.svelte";
import Button from "../../pieces/Button.svelte"; import Button from "../../pieces/Button.svelte";
import DisplayAUser from "../../pieces/DisplayAUser.svelte"; import DisplayAUser from "../../pieces/DisplayAUser.svelte";
@@ -38,7 +39,7 @@ could be a list of friends and if they're active but i can't see that yet
onMount( async() => { onMount( async() => {
// yea no idea what // yea no idea what
// i mean do i fetch user? i will for now // i mean do i fetch user? i will for now
user = await fetch('http://transcendance:8080/api/v2/user') user = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then( (x) => x.json() ); .then( (x) => x.json() );
// userBeingViewed = user; // userBeingViewed = user;
@@ -46,26 +47,26 @@ could be a list of friends and if they're active but i can't see that yet
// console.log(user) // console.log(user)
// console.log(user.username) // console.log(user.username)
myFriends = await fetch("http://transcendance:8080/api/v2/network/myfriends") myFriends = await fetch(`http://${Domain}:${Port}/api/v2/network/myfriends`)
.then( (x) => x.json() ); .then( (x) => x.json() );
// console.log('my friends') // console.log('my friends')
// console.log(myFriends) // console.log(myFriends)
requestsMade = await fetch('http://transcendance:8080/api/v2/network/pending') requestsMade = await fetch(`http://${Domain}:${Port}/api/v2/network/pending`)
.then( x => x.json() ); .then( x => x.json() );
// console.log('Requests pending '); // console.log('Requests pending ');
// console.log(requestsMade); // console.log(requestsMade);
requestsRecieved = await fetch('http://transcendance:8080/api/v2/network/received') requestsRecieved = await fetch(`http://${Domain}:${Port}/api/v2/network/received`)
.then( x => x.json() ); .then( x => x.json() );
// console.log('Requests received '); // console.log('Requests received ');
// console.log(requestsRecieved); // console.log(requestsRecieved);
allUsers = await fetch('http://transcendance:8080/api/v2/user/all') allUsers = await fetch(`http://${Domain}:${Port}/api/v2/user/all`)
.then( x => x.json() ); .then( x => x.json() );
// console.log('got all users ' + allUsers) // console.log('got all users ' + allUsers)
@@ -74,20 +75,20 @@ could be a list of friends and if they're active but i can't see that yet
const displayAllUsers = async() => { const displayAllUsers = async() => {
allUsers = await fetch('http://transcendance:8080/api/v2/user/all') allUsers = await fetch(`http://${Domain}:${Port}/api/v2/user/all`)
.then( x => x.json() ); .then( x => x.json() );
// console.log('got all users ' + allUsers) // console.log('got all users ' + allUsers)
}; };
const displayAllFriends = async() => { const displayAllFriends = async() => {
myFriends = await fetch('http://transcendance:8080/api/v2/network/myfriends') myFriends = await fetch(`http://${Domain}:${Port}/api/v2/network/myfriends`)
.then( x => x.json() ); .then( x => x.json() );
// console.log('got all friends ' + allFriends) // console.log('got all friends ' + allFriends)
}; };
const displayRequestsMade = async() => { const displayRequestsMade = async() => {
requestsMade = await fetch('http://transcendance:8080/api/v2/network/pending') requestsMade = await fetch(`http://${Domain}:${Port}/api/v2/network/pending`)
.then( x => x.json() ); .then( x => x.json() );
// console.log('got requests made ' + requestsMade) // console.log('got requests made ' + requestsMade)
}; };
@@ -106,7 +107,7 @@ could be a list of friends and if they're active but i can't see that yet
} }
if (valid) { if (valid) {
sentFriendRequest = await fetch("http://transcendance:8080/api/v2/network/myfriends", { sentFriendRequest = await fetch(`http://${Domain}:${Port}/api/v2/network/myfriends`, {
method : "POST", method : "POST",
headers: { 'Content-Type': 'application/json'}, headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
@@ -124,7 +125,7 @@ could be a list of friends and if they're active but i can't see that yet
// sendUsername = userBeingViewed.username; // sendUsername = userBeingViewed.username;
// prolly like fetch if you're friends or not? // prolly like fetch if you're friends or not?
// GET http://transcendance:8080/api/v2/networks/myfriends?username=aUser but i need to make that as long as Cherif // GET `http://${Domain}:${Port}/api/v2/networks/myfriends?username=aUser` but i need to make that as long as Cherif
// doesn't have a better option // doesn't have a better option
// like i want this thing to return the Friendship ID ideally // like i want this thing to return the Friendship ID ideally
}; };

View File

@@ -3,6 +3,7 @@
import Card from '../../pieces/Card.svelte'; import Card from '../../pieces/Card.svelte';
import {onMount} from 'svelte'; import {onMount} from 'svelte';
import { push } from 'svelte-spa-router'; import { push } from 'svelte-spa-router';
import { Domain, Port } from "../../Constantes.svelte";
import Button from '../../pieces/Button.svelte'; import Button from '../../pieces/Button.svelte';
let user; let user;
@@ -16,7 +17,7 @@
let success = {username: '', avatar: '' }; let success = {username: '', avatar: '' };
onMount( async() => { onMount( async() => {
user = await fetch('http://transcendance:8080/api/v2/user') user = await fetch(`http://${Domain}:${Port}/api/v2/user`)
.then( (x) => x.json() ); .then( (x) => x.json() );
// do a .catch? // do a .catch?
@@ -33,7 +34,7 @@
// console.log('this is what is in the avatar before fetch') // console.log('this is what is in the avatar before fetch')
// console.log(avatar) // console.log(avatar)
await fetch("http://transcendance:8080/api/v2/user/avatar", {method: "GET"}) await fetch(`http://${Domain}:${Port}/api/v2/user/avatar`, {method: "GET"})
.then(response => {return response.blob()}) .then(response => {return response.blob()})
.then(data => { .then(data => {
const url = URL.createObjectURL(data); const url = URL.createObjectURL(data);
@@ -63,7 +64,7 @@
else { else {
errors.username = ''; errors.username = '';
} }
await fetch('http://transcendance:8080/api/v2/user',{ await fetch(`http://${Domain}:${Port}/api/v2/user`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@@ -100,7 +101,7 @@
// tmp // tmp
console.log(data); console.log(data);
await fetch("http://transcendance:8080/api/v2/user/avatar", await fetch(`http://${Domain}:${Port}/api/v2/user/avatar`,
{ {
method : 'POST', method : 'POST',
body : data, body : data,
@@ -108,7 +109,7 @@
.then(() => uploadAvatarSuccess = true ) // for some reason it needs to be a function, i think a TS thing, not a promis otherwise .then(() => uploadAvatarSuccess = true ) // for some reason it needs to be a function, i think a TS thing, not a promis otherwise
.then(() => success.avatar = 'Your changes have been saved') .then(() => success.avatar = 'Your changes have been saved')
.catch(() => errors.avatar = 'Sorry failed to upload your new Avatar' ); .catch(() => errors.avatar = 'Sorry failed to upload your new Avatar' );
await fetch("http://transcendance:8080/api/v2/user/avatar", {method: "GET"}) await fetch(`http://${Domain}:${Port}/api/v2/user/avatar`, {method: "GET"})
.then(response => {return response.blob()}) .then(response => {return response.blob()})
.then(data => { .then(data => {
const url = URL.createObjectURL(data); const url = URL.createObjectURL(data);

View File

@@ -2,6 +2,7 @@
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import GenerateUserDisplay from './GenerateUserDisplay.svelte'; import GenerateUserDisplay from './GenerateUserDisplay.svelte';
import { Domain, Port } from "../Constantes.svelte";
// import {updateGeneratedUser} from './GenerateUserDisplay.svelte'; // import {updateGeneratedUser} from './GenerateUserDisplay.svelte';
export let aUsername; export let aUsername;
@@ -9,8 +10,8 @@
onMount( async() => { onMount( async() => {
console.log('Display aUser username: '+ aUsername) console.log('Display aUser username: '+ aUsername)
// http://transcendance:8080/api/v2/user?username=NomDuUserATrouver //`http://${Domain}:${Port}/api/v2/user?username=NomDuUserATrouve`
user = await fetch(`http://transcendance:8080/api/v2/user?username=${aUsername}`) user = await fetch(`http://${Domain}:${Port}/api/v2/user?username=${aUsername}`)
.then( (x) => x.json() ); .then( (x) => x.json() );
// console.log('Display a user: ') // console.log('Display a user: ')
@@ -26,15 +27,15 @@
const updateUser = async(updatedUser) => { const updateUser = async(updatedUser) => {
console.log('Display Update aUser username: '+ updateUser) console.log('Display Update aUser username: '+ updateUser)
// http://transcendance:8080/api/v2/user?username=NomDuUserATrouver //`http://${Domain}:${Port}/api/v2/user?username=NomDuUserATrouve`
user = await fetch(`http://transcendance:8080/api/v2/user?username=${updateUser}`) user = await fetch(`http://${Domain}:${Port}/api/v2/user?username=${updateUser}`)
.then( (x) => x.json() ); .then( (x) => x.json() );
}; };
// export const updateUser = async(updatedUser) => { // export const updateUser = async(updatedUser) => {
// console.log('Display Update aUser username: '+ updateUser) // console.log('Display Update aUser username: '+ updateUser)
// // http://transcendance:8080/api/v2/user?username=NomDuUserATrouver // //`http://${Domain}:${Port}/api/v2/user?username=NomDuUserATrouve`
// user = await fetch(`http://transcendance:8080/api/v2/user?username=${updateUser}`) // user = await fetch(`http://${Domain}:${Port}/api/v2/user?username=${updateUser}`)
// .then( (x) => x.json() ); // .then( (x) => x.json() );
// updateGeneratedUser(updateUser); // updateGeneratedUser(updateUser);

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { Domain, Port } from "../Constantes.svelte";
export let user; export let user;
export let primary; export let primary;
@@ -11,7 +12,7 @@
onMount( async() => { onMount( async() => {
// using this for now cuz for some reason there is yet to be a way to fet another person's avatar // using this for now cuz for some reason there is yet to be a way to fet another person's avatar
if (primary) { if (primary) {
await fetch("http://transcendance:8080/api/v2/user/avatar", {method: "GET"}) await fetch(`http://${Domain}:${Port}/api/v2/user/avatar`, {method: "GET"})
.then(response => {return response.blob()}) .then(response => {return response.blob()})
.then(data => { .then(data => {
const url = URL.createObjectURL(data); const url = URL.createObjectURL(data);

View File

@@ -1,13 +1,14 @@
<script lang="ts"> <script lang="ts">
import { push } from "svelte-spa-router"; import { push } from "svelte-spa-router";
import { location } from 'svelte-spa-router'; import { location } from 'svelte-spa-router';
import { Domain, Port } from "../Constantes.svelte";
import active from 'svelte-spa-router/active' import active from 'svelte-spa-router/active'
// or i could leave them all and not display if they're active? // or i could leave them all and not display if they're active?
let handleClickLogout = async () => { let handleClickLogout = async () => {
await fetch('http://transcendance:8080/api/v2/auth/logout', { await fetch(`http://${Domain}:${Port}/api/v2/auth/logout`, {
method: 'POST', method: 'POST',
}) })
// .then(resp => resp.json) // .then(resp => resp.json)

View File

@@ -0,0 +1,59 @@
<script lang="ts">
import Layouts from './Chat_layouts.svelte';
import { Domain, PortIo } from "../../Constantes.svelte";
export let color = "transparent";
/* web sockets with socket.io
*/
import { onMount } from 'svelte';
import io from 'socket.io-client';
const socket = io(`http://${Domain}:${PortIo}`, {
path: '/chat'
});
onMount(async => {
socket.on('connect', function(){
console.log("socket.io connected");
});
socket.on('disconnect', function(){
console.log("socket.io disconnected");
});
socket.on('connect_error', function(){
console.log("socket.io connect_error");
});
socket.on('connect_timeout', function(){
console.log("socket.io connect_timeout");
});
socket.on('error', function(){
console.log("socket.io error");
});
socket.on('reconnect', function(){
console.log("socket.io reconnect");
});
socket.on('reconnect_attempt', function(){
console.log("socket.io reconnect_attempt");
});
socket.on('reconnecting', function(){
console.log("socket.io reconnecting");
});
socket.on('reconnect_error', function(){
console.log("socket.io reconnect_error");
});
socket.on('reconnect_failed', function(){
console.log("socket.io reconnect_failed");
});
socket.on('ping', function(){
console.log("socket.io ping");
});
socket.on('pong', function(){
console.log("socket.io pong");
});
});
</script>
<Layouts color={color} />
<style></style>

View File

@@ -0,0 +1,133 @@
<script lang="ts">
export let color;
export let layout;
</script>
<div class="{layout} chat_box" style="background-color: {color};">
<slot></slot>
</div>
<style>
/* chat_box and default style
*/
.chat_box {
display: flex;
position: fixed;
bottom: 20px;
right: 20px;
padding: 0px;
width: auto;
height: auto;
border: 1px solid black;
z-index: 1;
}
/* * * * * * * * * * * * * * * * * * * * *
GLOBAL STYLES
*/
/* Hide scrollbar
*/
.chat_box :global(*) {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.chat_box :global(*::-webkit-scrollbar) {
display: none; /* Chrome, Safari and Opera */
}
/* for grid_box and all childrens
*/
.chat_box :global(.grid_box) {
display: grid;
margin: 5px;
gap: 5px;
width: 300px;
height: 400px;
}
.chat_box :global(.grid_box *) {
display: flex;
flex-direction: column;
position: relative;
box-sizing: border-box;
}
/* all p
*/
.chat_box :global(.grid_box p) {
padding: 10px;
font-size: 15px;
}
/* all panel
*/
.chat_box :global(.panel) {
overflow-y: scroll;
}
.chat_box :global(.panel > *) {
margin-top: 10px;
margin-bottom: 10px;
}
/* * * * * * * * * * * * * * * * * * * * *
GLOBAL UTILITIES
*/
/* __show_if_only_child
*/
.chat_box :global(.__show_if_only_child) {
display: none;
}
.chat_box :global(.__show_if_only_child:only-child) {
display: flex;
color: rgb(100, 100, 100);
}
/* __center
*/
.chat_box :global(.__center) {
margin-left: auto;
margin-right: auto;
}
/* __border_top
*/
.chat_box :global(.__border_top) {
border-top: 1px solid black;
}
/* __check_change_next
*/
.chat_box :global(.__check_change_next:checked ~ .__to_show) {
display: flex;
}
.chat_box :global(.__check_change_next:checked ~ .__to_block),
.chat_box :global(.__check_change_next:checked ~ .__to_block *) {
pointer-events: none;
color: rgb(100, 100, 100);
}
.chat_box :global(.__to_show) {
display: none;
}
</style>

View File

@@ -0,0 +1,188 @@
<!--
<Button
bind:layout
new_layout=""
on_click={}
my_class=""
my_title=""
>
value
</Button>
-->
<script lang="ts">
export let my_class = "";
export let my_title = "";
export let layout = "";
export let new_layout = "";
export let on_click = "";
function update_layout() {
layout = new_layout;
}
</script>
<button on:click={update_layout} on:click={on_click} title={my_title} class={my_class}>
<p><slot></slot></p>
</button>
<style>
/*
- default config
- for btn list
- for transparent btn
- for deactivated btn
- for icon
- for 3 dots btn
- for close btn
- for back btn
*/
/* default config
*/
button {
padding: 0px;
margin: auto;
width: 100%;
cursor: pointer;
outline: none;
border: none;
background-color: rgb(220, 220, 220);
}
button p {
width: 100%;
margin: auto;
text-align: center;
}
button:hover {
background-color: rgb(200, 200, 200);
}
button:active {
background-color: rgb(190, 190, 190);
}
/* for btn list
*/
.list:not(:hover) {
background-color: rgb(240, 240, 240);
}
.list p {
text-align: left;
}
/* for transparent btn
*/
.transparent:not(:hover) {
background-color: transparent;
}
/* for deactivated btn
*/
.deactivate {
background-color: transparent;
pointer-events: none;
}
/* for icon
*/
.icon p {
display: none;
}
.icon:not(:hover) {
background-color: transparent;
}
.icon {
width: 30px;
height: 100%;
padding: 0px;
}
/* for 3 dots btn
*/
.dots::after {
content: '\2807';
font-size: 20px;
position: absolute;
top: 50%;
left: 0px;
width: 100%;
height: auto;
text-align: center;
transform: translateY(-50%);
cursor: pointer;
}
/* for close btn
*/
.close::before {
content: "";
position: absolute;
top: calc(50% - 1px);
left: 5px;
width: 20px;
height: 2px;
background-color: black;
}
/* for back btn
*/
.back::before {
content: "";
position: absolute;
top: calc(50% - 6px - 1px);
left: 6px;
width: 14px;
height: 14px;
border-left: 1px solid black;
border-bottom: 1px solid black;
transform: rotate(45deg);
}
/* for blocked user
https://www.fileformat.info/info/unicode/category/So/list.htm
U+1F512 LOCK 🔒
U+1F513 OPEN LOCK 🔓
*/
.blocked {
padding-left: 30px;
}
.blocked::before {
content: "";
position: absolute;
top: calc(50% - 2px);
left: 10px;
cursor: pointer;
width: 13px;
height: 10px;
border-radius: 2px;
background-color: rgb(110, 110, 110);
}
.blocked::after {
content: "";
position: absolute;
top: calc(50% - 9px);
left: 12px;
cursor: pointer;
width: 9px;
height: 13px;
border-radius: 5px;
box-sizing: border-box;
border: 3px solid rgb(110, 110, 110);
}
</style>

View File

@@ -0,0 +1,86 @@
<script lang="ts">
import Debug from './tmp_debug.svelte';
import ChatBox from './Chat_box_css.svelte';
import CloseLayout from './Layout_close.svelte';
import HomeLayout from './Layout_home.svelte';
import RoomLayout from './Layout_room.svelte';
import NewLayout from './Layout_new.svelte';
import SettingsLayout from './Layout_settings.svelte';
import RoomsetLayout from './Layout_room_set.svelte';
import ProtectedLayout from './Layout_protected.svelte';
import CreateLayout from './Layout_create.svelte';
import MuteLayout from './Layout_mute.svelte';
import UserLayout from './Layout_user.svelte';
import Button from './Chat_button.svelte';
/* global variables
*/
export let color;
let room = "";
let admin = false;
let layout = "close";
let layouts = ["home", "home"];
/* hold previous version of layout, to go back
*/
function set_layouts(layout)
{
if (layout === "close")
return;
if (layout === layouts[0])
return;
if (layout === layouts[1])
layouts = [layout, "home"];
else
layouts = [layout, layouts[0]];
}
$: set_layouts(layout);
</script>
<ChatBox layout={layout} color={color}>
{#if layout === "home"}
<HomeLayout bind:layout />
{:else if layout === "close"}
<CloseLayout bind:layout />
{:else if layout === "room"}
<RoomLayout bind:layout back={layouts[1]} />
{:else if layout === "new"}
<NewLayout bind:layout back={layouts[1]} />
{:else if layout === "settings"}
<SettingsLayout bind:layout back={layouts[1]} />
{:else if layout === "room_set"}
<RoomsetLayout bind:layout back={layouts[1]} />
{:else if layout === "protected"}
<ProtectedLayout bind:layout back={layouts[1]} />
{:else if layout === "create"}
<CreateLayout bind:layout back={layouts[1]} />
{:else if layout === "mute"}
<MuteLayout bind:layout back={layouts[1]} />
{:else if layout === "user"}
<UserLayout bind:layout back={layouts[1]} />
{/if}
</ChatBox>
<!-- TMP DEBUG -->
<Debug bind:layout bind:layouts />
<style></style>

View File

@@ -0,0 +1,67 @@
<script>
export let name;
</script>
<div class="chat_msg {name}">
<p class="name">{name}</p>
<p class="msg"><slot></slot></p>
</div>
<style>
.chat_msg {
/*
white-space: pre-wrap;
*/
margin: 5px auto;
padding: 5px;
border-radius: 5px;
}
/* all msg
*/
.chat_msg {
margin-left: 0px;
background-color: rgb(210, 210, 210);
max-width: 80%;
}
.chat_msg p {
padding: 0px;
}
.chat_msg p.name {
margin: 0px;
font-size: 12px;
color: rgb(100, 100, 100);
}
.chat_msg p.msg {
margin: 5px 0px;
}
.chat_msg p.msg :global(*) {
display: inline;
}
/* msg perso
*/
.chat_msg.me {
margin-right: 0px;
margin-left: auto;
background-color: rgb(210, 110, 10);
}
.chat_msg.me p.name {
display: none;
}
/* msg server
*/
.chat_msg.SERVER {
margin-left: auto;
background-color: transparent;
}
.chat_msg.SERVER p.name {
display: none;
}
.chat_msg.SERVER p.msg {
margin: 0px auto;
font-size: 12px;
color: rgb(100, 100, 100);
}
</style>

View File

@@ -0,0 +1,137 @@
<script>
import Button from './Chat_button.svelte';
export let layout;
</script>
<div class="grid_box">
<Button bind:layout new_layout="home" my_class="chat">
chat
</Button>
</div>
<style>
/* layout "close"
*/
.grid_box :global(.chat) {grid-area: chat;}
.grid_box {
gap: 0px;
grid:
' chat ' auto
/ auto ;
}
:global(.chat_box.close) .grid_box {
margin: 0px;
width: auto;
height: auto;
}
/* * * * * * * * * * * * * * * * * * * * *
GLOBAL STYLES
*/
/* Hide scrollbar
*/
.chat_box :global(*) {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.chat_box :global(*::-webkit-scrollbar) {
display: none; /* Chrome, Safari and Opera */
}
/* for grid_box and all childrens
*/
.chat_box :global(.grid_box) {
display: grid;
margin: 0px;
gap: 5px;
width: 100%;
height: 100%;
}
.chat_box :global(.grid_box *) {
display: flex;
flex-direction: column;
position: relative;
box-sizing: border-box;
}
/* all p
*/
.chat_box :global(.grid_box p) {
padding: 10px;
font-size: 15px;
}
/* all panel
*/
.chat_box :global(.panel) {
overflow-y: scroll;
}
.chat_box :global(.panel > *) {
margin-top: 10px;
margin-bottom: 10px;
}
/* * * * * * * * * * * * * * * * * * * * *
GLOBAL UTILITIES
*/
/* __show_if_only_child
*/
.chat_box :global(.__show_if_only_child) {
display: none;
}
.chat_box :global(.__show_if_only_child:only-child) {
display: flex;
color: rgb(100, 100, 100);
}
/* __center
*/
.chat_box :global(.__center) {
margin-left: auto;
margin-right: auto;
}
/* __border_top
*/
.chat_box :global(.__border_top) {
border-top: 1px solid black;
}
/* __check_change_next
*/
.chat_box :global(.__check_change_next:checked ~ .__to_show) {
display: flex;
}
.chat_box :global(.__check_change_next:checked ~ .__to_block),
.chat_box :global(.__check_change_next:checked ~ .__to_block *) {
pointer-events: none;
color: rgb(100, 100, 100);
}
.chat_box :global(.__to_show) {
display: none;
}
</style>

View File

@@ -0,0 +1,113 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- create -->
<Button my_class="create deactivate">
create
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel_create -->
<div class="panel panel_create">
<form>
<!-- name: -->
<label for="chat_name"><p>new room name :</p></label>
<input id="chat_name" required>
<!-- [ ] pubic -->
<input id="chat_public" type="radio" name="chat_create_type" checked>
<label for="chat_public" class="_radio"><p>public</p></label>
<!-- [ ] private -->
<input id="chat_private" type="radio" name="chat_create_type">
<label for="chat_private" class="_radio"><p>private</p></label>
<!-- [ ] protected -->
<input id="chat_protected" class="__check_change_next" type="radio" name="chat_create_type">
<label for="chat_protected" class="_radio"><p>protected</p></label>
<!-- [x] protected -->
<div class="__to_show">
<label for="chat_pswd"><p>choose a password :</p></label>
<input id="chat_pswd" type="password" placeholder="minimum 8 characters" minlength="8">
<p>confirm password :</p>
<input type="password">
</div>
<input type="submit" value="&#x2BA1">
</form>
</div>
</div>
<style>
/* grid layout "create"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.create ) {grid-area: create;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_create) {grid-area: panel_create;}
.grid_box {
grid:
' back create close ' auto
' panel_create panel_create panel_create ' 1fr
/ auto 1fr auto ;
}
/* radio elements style check
*/
form input[type=radio] {
display: none;
}
form label._radio {
margin: 0px 20px 0px auto;
padding-right: 10px;
cursor: pointer;
}
form label._radio p {
margin-top: 0px;
margin-bottom: 0px;
}
form label._radio::after {
content: "";
position: absolute;
top: calc(50% - 6px);
right: 0px;
width: 12px;
height: 12px;
border-radius: 6px;
border: 2px solid rgb(150, 150, 150);
box-sizing: border-box;
cursor: pointer;
}
form input[type=radio]:checked
+ label._radio::after {
background-color: rgb(200, 200, 200);
}
/* submit
*/
form input[type=submit] {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,73 @@
<script>
import Button from './Chat_button.svelte';
export let layout;
</script>
<div class="grid_box">
<!-- settings -->
<Button bind:layout new_layout="settings" my_class="settings dots icon">
settings
</Button>
<!-- new -->
<Button bind:layout new_layout="new" my_class="new transparent">
new
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel home -->
<div class="panel panel_home __border_top">
<p class="title">list of your rooms :</p>
<div class="room_list">
<div class="__show_if_only_child">
<p class="__center">/ you have no chat room yet /</p>
</div>
<!-- placeholders
<Button bind:layout new_layout="room" my_class="list">
a room
</Button>
<Button bind:layout new_layout="room" my_class="list">
another room
</Button>
<Button bind:layout new_layout="room" my_class="list">
placeholder
</Button>
------------- -->
<!-- END placeholders -->
</div>
</div>
</div>
<style>
/* grid layout "home"
*/
.grid_box :global(.settings ) {grid-area: settings;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.new ) {grid-area: new;}
.grid_box :global(.panel_home) {grid-area: panel_home;}
.grid_box {
grid:
' settings new close ' auto
' panel_home panel_home panel_home ' 1fr
/ auto 1fr auto ;
}
/* panel home
*/
.panel_home p.title {
margin: 10px auto 0px auto;
}
</style>

View File

@@ -0,0 +1,261 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- user -->
<Button my_class="user deactivate">
&lt;user&gt;
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel_mute -->
<!-- MUTE -->
<div class="panel panel_mute __border_top">
<p class="__center">mute this user for a time :</p>
<form>
<!-- forever -->
<input id="chat_mute_forever" class="__check_change_next" type="checkbox">
<label for="chat_mute_forever" class="_checkbox"><p>forever</p></label>
<div class="__to_block">
<!-- minutes -->
<label for="chat_mute_minutes" class="_select">
<p>minutes :</p>
<select id="chat_mute_minutes">
<option value="01">00</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="30">30</option>
<option value="31">31</option>
<option value="32">32</option>
<option value="33">33</option>
<option value="34">34</option>
<option value="35">35</option>
<option value="36">36</option>
<option value="37">37</option>
<option value="40">40</option>
<option value="41">41</option>
<option value="42">42</option>
<option value="43">43</option>
<option value="44">44</option>
<option value="45">45</option>
<option value="46">46</option>
<option value="47">47</option>
<option value="50">50</option>
<option value="51">51</option>
<option value="52">52</option>
<option value="53">53</option>
<option value="54">54</option>
<option value="55">55</option>
<option value="56">56</option>
<option value="57">57</option>
<option value="60">60</option>
</select>
</label>
<!-- hours -->
<label for="chat_mute_hours" class="_select">
<p>hours :</p>
<select id="chat_mute_hours">
<option value="01">00</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="30">30</option>
<option value="31">31</option>
<option value="32">32</option>
<option value="33">33</option>
<option value="34">34</option>
<option value="35">35</option>
<option value="36">36</option>
<option value="37">37</option>
<option value="40">40</option>
<option value="41">41</option>
<option value="42">42</option>
<option value="43">43</option>
<option value="44">44</option>
<option value="45">45</option>
<option value="46">46</option>
<option value="47">47</option>
<option value="50">50</option>
<option value="51">51</option>
<option value="52">52</option>
<option value="53">53</option>
<option value="54">54</option>
<option value="55">55</option>
<option value="56">56</option>
<option value="57">57</option>
<option value="60">60</option>
</select>
</label>
<!-- days -->
<label for="chat_mute_days" class="_select">
<p>days :</p>
<select id="chat_mute_days">
<option value="00">00</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="30">30</option>
<option value="31">31</option>
</select>
</label>
</div>
<input type="submit" value="&#x2BA1">
</form>
</div>
</div>
<style>
/* grid layout "mute"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.user ) {grid-area: user;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_mute) {grid-area: panel_mute;}
.grid_box {
grid:
' back user close ' auto
' panel_mute panel_mute panel_mute ' 1fr
/ auto 1fr auto ;
}
/* checkbox
*/
form input[type=checkbox] {
display: none;
}
form label._checkbox {
margin: 0px auto 0px 10px;
padding-left: 10px;
cursor: pointer;
}
form label._checkbox::after {
content: "";
position: absolute;
top: calc(50% - 6px);
left: 0px;
width: 12px;
height: 12px;
border: 2px solid rgb(150, 150, 150);
box-sizing: border-box;
cursor: pointer;
}
form input[type=checkbox]:checked
+ label._checkbox::after {
background-color: rgb(200, 200, 200);
}
/* select
*/
form label._select {
flex-direction: row;
}
form label._select p {
margin: 0px;
}
form select {
margin: auto auto auto 10px;
background-color: rgb(220, 220, 220);
border: none;
padding: 5px;
cursor: pointer;
}
form select:hover {
background-color: rgb(200, 200, 200);
}
/* submit
*/
form input[type=submit] {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,89 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- new -->
<Button my_class="new deactivate">
new
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel_new -->
<div class="panel panel_new __border_top">
<Button bind:layout new_layout="create" my_class="create">
create
</Button>
<p>join room :</p>
<div class="public_rooms">
<div class="__show_if_only_child">
<p class="__center">/ there are no public rooms yet /</p>
</div>
<!-- placeholders
<Button bind:layout new_layout="room" my_class="list">
placeholder
</Button>
<Button bind:layout new_layout="room" my_class="list">
join room
</Button>
<Button bind:layout new_layout="room" my_class="list">
one room
</Button>
<Button bind:layout new_layout="room" my_class="list">
another room
</Button>
<Button bind:layout new_layout="room" my_class="list">
one room
</Button>
<Button bind:layout new_layout="room" my_class="list">
another room
</Button>
<Button bind:layout new_layout="room" my_class="list">
one room
</Button>
<Button bind:layout new_layout="room" my_class="list">
another room
</Button>
<Button bind:layout new_layout="room" my_class="list">
one more room
</Button>
------------- -->
<!-- END placeholders -->
</div>
</div>
</div>
<style>
/* grid layout "new"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.new ) {grid-area: new;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_new) {grid-area: panel_new;}
.grid_box {
grid:
' back new close ' auto
' panel_new panel_new panel_new ' 1fr
/ auto 1fr auto ;
}
</style>

View File

@@ -0,0 +1,65 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- room_name -->
<Button my_class="room_name deactivate">
&lt;room_name&gt;
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel_protected -->
<div class="panel panel_protected __border_top">
<p class="title __center">this room is protected</p>
<form>
<label for="chat_pswd"><p>password :</p></label>
<input id="chat_pswd" type="password" required>
<input type="submit" value="&#x2BA1">
</form>
</div>
</div>
<style>
/* grid layout "protected"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.room_name ) {grid-area: room_name;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_protected) {grid-area: panel_protected;}
.grid_box {
grid:
' back room_name close ' auto
' panel_protected panel_protected panel_protected ' 1fr
/ auto 1fr auto ;
}
/* submit
*/
form input[type=submit] {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,149 @@
<script>
import Button from './Chat_button.svelte';
import Msg from './Chat_msg.svelte';
import io from 'socket.io-client';
export let layout = "";
export let back = "";
let msg = "";
let text_area;
let msgs = [];
function add_msg(from, the_msg)
{
msgs = [...msgs, { content: the_msg, name: from }];
}
function send_msg()
{
msg = msg.trim();
if (msg.length > 0) {
//socket.emit('sendmsg', msg);
add_msg("me", msg);
}
msg = "";
text_area.focus();
}
function send_msg_if(evt)
{
if (evt.shiftKey && evt.key === "Enter")
{
evt.preventDefault();
send_msg();
}
}
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- room_name -->
<Button bind:layout new_layout="room_set" my_class="room_name transparent">
&lt;room_name&gt;
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- msg -->
<div class="panel panel_msg">
<div class="msg_thread">
{#each msgs as msg}
<Msg name={msg.name}>{@html msg.content}</Msg>
{/each}
</div>
</div>
<!-- write -->
<div class="panel_write">
<div
class="text_area"
bind:innerHTML={msg}
bind:this={text_area}
on:keypress={send_msg_if}
contenteditable="true"
></div>
</div>
<!-- send -->
<Button my_class="send" on_click={send_msg}>
send
</Button>
</div>
<style>
/* grid layout "room"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.room_name ) {grid-area: room_name;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_msg ) {grid-area: panel_msg;}
.grid_box :global(.send ) {grid-area: send;}
.grid_box :global(.panel_write) {grid-area: panel_write;}
.grid_box {
grid:
' back room_name room_name close ' auto
' panel_msg panel_msg panel_msg panel_msg ' 1fr
' panel_write panel_write send send ' auto
/ auto 1fr auto auto ;
}
/* write area
*/
.grid_box .panel_write {
border: none;
overflow: visible;
}
.grid_box .text_area {
display: block;
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
background-color: white;
border: 1px solid black;
}
.grid_box .text_area:focus {
height: auto;
min-height: 100%;
max-height: 300px;
}
.grid_box .panel_write .text_area :global(*) {
display: block ruby;
}
/* msg area
*/
.grid_box .panel_msg {
flex-direction: column-reverse;
border: 1px solid black;
}
.grid_box .msg_thread {
width: 100%;
padding: 0px 5px;
}
</style>

View File

@@ -0,0 +1,76 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- room_name -->
<Button my_class="room_name deactivate">
&lt;room_name&gt;
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel_room_set -->
<div class="panel panel_room_set __border_top">
<Button bind:layout new_layout="create" my_class="create">
leave
</Button>
<p>room users :</p>
<div class="room_users">
<div class="__show_if_only_child">
<p class="__center">/ there are no public rooms yet /</p>
</div>
<!-- placeholders
------------- -->
<Button bind:layout new_layout="user" my_class="list">
user 1
</Button>
<Button bind:layout new_layout="user" my_class="list blocked">
user 2
</Button>
<Button bind:layout new_layout="user" my_class="list">
user 3
</Button>
<Button bind:layout new_layout="user" my_class="list">
user 4
</Button>
<!-- END placeholders -->
</div>
</div>
</div>
<style>
/* grid layout "room_set"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.room_name ) {grid-area: room_name;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_room_set) {grid-area: panel_room_set;}
.grid_box {
grid:
' back room_name close ' auto
' panel_room_set panel_room_set panel_room_set ' 1fr
/ auto 1fr auto ;
}
</style>

View File

@@ -0,0 +1,72 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- settings -->
<Button my_class="room_name deactivate">
settings
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- panel_settings -->
<div class="panel panel_settings __border_top">
<p>blocked users :</p>
<div class="blocked_users">
<div class="__show_if_only_child">
<p class="__center">/ you have blocked no one /</p>
</div>
<!-- placeholders
<Button bind:layout new_layout="user" my_class="list blocked">
user 1
</Button>
<Button bind:layout new_layout="user" my_class="list blocked">
user 2
</Button>
<Button bind:layout new_layout="user" my_class="list blocked">
user 3
</Button>
<Button bind:layout new_layout="user" my_class="list blocked">
user 4
</Button>
------------- -->
<!-- END placeholders -->
</div>
</div>
</div>
<style>
/* grid layout "settings"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.settings ) {grid-area: settings;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.panel_settings) {grid-area: panel_settings;}
.grid_box {
grid:
' back settings close ' auto
' panel_settings panel_settings panel_settings ' 1fr
/ auto 1fr auto ;
}
</style>

View File

@@ -0,0 +1,91 @@
<script>
import Button from './Chat_button.svelte';
export let layout = "";
export let back = "";
let mute = "mute";
let block = "block";
</script>
<div class="grid_box">
<!-- back -->
<Button bind:layout new_layout={back} my_class="back icon" my_title="go back {back}">
back
</Button>
<!-- user -->
<Button my_class="user deactivate">
&lt;user&gt;
</Button>
<!-- close -->
<Button bind:layout new_layout="close" my_class="close icon">
close
</Button>
<!-- room_name -->
{#if back === "room_set"}
<Button my_class="room_name deactivate __border_top">
&lt;room_name&gt;
</Button>
{/if}
<!-- panel_user -->
<div class="panel panel_user __border_top">
<p class="__center">user options :</p>
<Button>
view profile
</Button>
<Button>
game invitation
</Button>
<Button>
{block}
</Button>
{#if back === "room_set"}
<Button>
make admin
</Button>
<Button>
{mute}
</Button>
{/if}
</div>
</div>
<style>
/* grid layout "user"
*/
.grid_box :global(.back ) {grid-area: back;}
.grid_box :global(.user ) {grid-area: user;}
.grid_box :global(.close ) {grid-area: close;}
.grid_box :global(.room_name ) {grid-area: room_name;}
.grid_box :global(.panel_user) {grid-area: panel_user;}
.grid_box {
grid:
' back user close ' auto
' room_name room_name room_name ' auto
' panel_user panel_user panel_user ' 1fr
/ auto 1fr auto ;
}
/* for line height
*/
.panel_user {
margin-top: -5px;
}
</style>

View File

@@ -0,0 +1,27 @@
<script>
export let layout = "";
export let layouts = [];
</script>
<div style="display: flex; flex-direction: column; font-size: 12px; position: fixed; top: 20px; left: 20px; background-color: white;">
<p>temp, for testing :</p>
<button on:click={function(){layout = "close" }}>close</button>
<button on:click={function(){layout = "home" }}>home</button>
<button on:click={function(){layout = "room" }}>room</button>
<button on:click={function(){layout = "new" }}>new</button>
<button on:click={function(){layout = "settings" }}>settings</button>
<button on:click={function(){layout = "room_set" }}>room_set</button>
<button on:click={function(){layout = "protected"}}>protected</button>
<button on:click={function(){layout = "create" }}>create</button>
<button on:click={function(){layout = "mute" }}>mute</button>
<button on:click={function(){
layouts = ["settings", "settings"];
layout = "user";
}}>user from settings</button>
<button on:click={function(){
layouts = ["room_set", "room_set"];
layout = "user";
}}>user from room_set</button>
</div>