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
# 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. # This script is used to create a new environment for the project.
#
# Create a new environment for docker 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
if [ -f "$ENV_FILE_DOCKER" ] && [ -f "$ENV_FILE_NESTJS" ]; then
# Create a new environment for docker echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS already exists. Do you want to overwrite them ? (y/n)"
if [ -f "$ENV_FILE_DOCKER" ] && [ -f "$ENV_FILE_NESTJS" ]; then OVERWRITE=""
echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS already exists. Do you want to overwrite them ? (y/n)" # Ask to overwrite the .env files
read -p "Enter your choice : " OVERWRITE while [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "n" ]; do
if [ "$OVERWRITE" = "y" ]; then read -p "Enter your choice : " OVERWRITE
rm "$ENV_FILE_DOCKER" && rm "$ENV_FILE_NESTJS" done
else if [ "$OVERWRITE" = "y" ]; then
echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS will not be overwritten. The script will exit." rm "$ENV_FILE_DOCKER" && rm "$ENV_FILE_NESTJS"
exit 0 docker rmi -f postgres
else
echo "The file $ENV_FILE_DOCKER and $ENV_FILE_NESTJS will not be overwritten. The script will exit."
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
if [ "$NODE_ENV" = "1" ]; then
echo "NODE_ENV=development" > "$ENV_FILE_DOCKER" # Create a new environment for docker
elif [ "$NODE_ENV" = "2" ]; then #
echo "NODE_ENV=production" > "$ENV_FILE_DOCKER" echo "Creating a new environment for docker"
else NODE_ENV=""
echo "You entered a wrong value. The default value will be used (development)." # Ask if dev or prod environment
echo "NODE_ENV=development" > "$ENV_FILE_DOCKER" while [ "$NODE_ENV" != "1" ] && [ "$NODE_ENV" != "2" ]; do
fi read -p "Enter the env configuration for nestjs : \"1\" for development OR \"2\" for production : " NODE_ENV
read -p "Enter the name of the host like \"localhost\" : " PROJECT_HOST done
echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_DOCKER" if [ "$NODE_ENV" = "1" ]; then
echo "WEBSITE_PORT=8080" >> "$ENV_FILE_DOCKER" echo "NODE_ENV=development" > "$ENV_FILE_DOCKER"
echo "POSTGRES_USER=postgres" >> "$ENV_FILE_DOCKER" else
POSTGRES_PASSWORD=$(openssl rand -base64 32) echo "NODE_ENV=production" > "$ENV_FILE_DOCKER"
echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> "$ENV_FILE_DOCKER" fi
echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_DOCKER" # Env variables
echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_DOCKER" read -p "Enter the name of the host like \"localhost\" : " PROJECT_HOST
echo "POSTGRES_PORT=5432" >> "$ENV_FILE_DOCKER" echo "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_DOCKER"
echo "REDIS_HOST=redis" >> "$ENV_FILE_DOCKER" echo "WEBSITE_PORT=8080" >> "$ENV_FILE_DOCKER"
echo "REDIS_PORT=6379" >> "$ENV_FILE_DOCKER" echo "POSTGRES_USER=postgres" >> "$ENV_FILE_DOCKER"
echo "REDIS_PASSWORD=$(openssl rand -base64 32)" >> "$ENV_FILE_DOCKER" echo "#if change postgres pswd, do make destroy" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_PASSWORD=$(generate_password)" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_DB=transcendance_db" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_HOST=postgresql" >> "$ENV_FILE_DOCKER"
echo "POSTGRES_PORT=5432" >> "$ENV_FILE_DOCKER"
echo "REDIS_HOST=redis" >> "$ENV_FILE_DOCKER"
echo "REDIS_PORT=6379" >> "$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"
if [ "$NODE_ENV" = "1" ]; then echo "NODE_ENV=\$NODE_ENV" > "$ENV_FILE_NESTJS"
echo "NODE_ENV=development" > "$ENV_FILE_NESTJS" echo "WEBSITE_HOST=\$WEBSITE_HOST" >> "$ENV_FILE_NESTJS"
elif [ "$NODE_ENV" = "2" ]; then echo "WEBSITE_PORT=\$WEBSITE_PORT" >> "$ENV_FILE_NESTJS"
echo "NODE_ENV=production" > "$ENV_FILE_NESTJS" echo "POSTGRES_USER=\$POSTGRES_USER" >> "$ENV_FILE_NESTJS"
else echo "POSTGRES_PASSWORD=\$POSTGRES_PASSWORD" >> "$ENV_FILE_NESTJS"
echo "NODE_ENV=development" > "$ENV_FILE_NESTJS" echo "POSTGRES_DB=\$POSTGRES_DB" >> "$ENV_FILE_NESTJS"
fi echo "POSTGRES_HOST=\$POSTGRES_HOST" >> "$ENV_FILE_NESTJS"
echo "POSTGRES_PORT=\$POSTGRES_PORT" >> "$ENV_FILE_NESTJS"
# Connection to 42
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
echo "FORTYTWO_CLIENT_ID=$CLIENT_ID" >> "$ENV_FILE_NESTJS"
read -p "Enter the client secret of the 42 api : " CLIENT_SECRET
echo "FORTYTWO_CLIENT_SECRET=$CLIENT_SECRET" >> "$ENV_FILE_NESTJS"
FT_CALLBACK="http://\$WEBSITE_HOST:\$WEBSITE_PORT/api/v2/auth/redirect"
echo "FORTYTWO_CALLBACK_URL=$FT_CALLBACK" >> "$ENV_FILE_NESTJS"
# Other configs
echo "COOKIE_SECRET=$(generate_password)" >> "$ENV_FILE_NESTJS"
echo "PORT=3000" >> "$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 "WEBSITE_HOST=$PROJECT_HOST" >> "$ENV_FILE_NESTJS" # it's finished !
echo "WEBSITE_PORT=8080" >> "$ENV_FILE_NESTJS" #
echo "POSTGRES_USER=postgres" >> "$ENV_FILE_NESTJS" echo "The environment has been created successfully. You can now wait for the docker to build the project."
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"
read -p "Enter the client id of the 42 api : " CLIENT_ID
echo "FORTYTWO_CLIENT_ID=$CLIENT_ID" >> "$ENV_FILE_NESTJS"
read -p "Enter the client secret of the 42 api : " CLIENT_SECRET
echo "FORTYTWO_CLIENT_SECRET=$CLIENT_SECRET" >> "$ENV_FILE_NESTJS"
echo "FORTYTWO_CALLBACK_URL=http://$PROJECT_HOST:8080/api/v2/auth/redirect" >> "$ENV_FILE_NESTJS"
echo "COOKIE_SECRET=$(openssl rand -base64 32)" >> "$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 "TICKET_FOR_PLAYING_GAME_SECRET=$(openssl rand -base64 32)" >> "$ENV_FILE_NESTJS"
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,28 +8,34 @@ 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: [
AuthenticationModule, UsersModule,
PassportModule.register({ session: true }), AuthenticationModule,
FriendshipsModule, PassportModule.register({ session: true }),
GameModule, FriendshipsModule,
ConfigModule.forRoot(), GameModule,
TypeOrmModule.forRoot({ ConfigModule.forRoot(),
type: 'postgres', TypeOrmModule.forRoot({
host: process.env.POSTGRES_HOST, type: 'postgres',
port: parseInt(process.env.POSTGRES_PORT), host: process.env.POSTGRES_HOST,
username: process.env.POSTGRES_USER, port: parseInt(process.env.POSTGRES_PORT),
password: process.env.POSTGRES_PASSWORD, username: process.env.POSTGRES_USER,
database: process.env.POSTGRES_DATABASE, password: process.env.POSTGRES_PASSWORD,
autoLoadEntities: true, database: process.env.POSTGRES_DATABASE,
//ne pas synchroniser quand on est en prod. Trouver un moyen de set ça, sûrement autoLoadEntities: true,
//avec une classe pour le module //ne pas synchroniser quand on est en prod. Trouver un moyen de set ça, sûrement
synchronize: true, //avec une classe pour le module
}), 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

@@ -1,16 +1,17 @@
<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

@@ -1,21 +1,24 @@
<script lang="ts"> <script lang="ts">
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

@@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
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>