From c23500e0a06f754e981a93db72ad47ce620dd745 Mon Sep 17 00:00:00 2001 From: starnakin Date: Thu, 25 Jan 2024 17:37:08 +0100 Subject: [PATCH 1/8] doc: fix: docstring: use Promise --- frontend/static/js/api/MyProfile.js | 2 +- frontend/static/js/api/account.js | 8 ++++---- frontend/static/js/api/client.js | 19 ++++++++++--------- frontend/static/js/api/matchmaking.js | 5 ++++- frontend/static/js/api/profile.js | 4 ++++ frontend/static/js/api/profiles.js | 6 +++--- .../static/js/api/tournament/tournament.js | 10 ++++++++++ .../static/js/api/tournament/tournaments.js | 7 ++++++- 8 files changed, 42 insertions(+), 19 deletions(-) diff --git a/frontend/static/js/api/MyProfile.js b/frontend/static/js/api/MyProfile.js index 208531a..de3f46e 100644 --- a/frontend/static/js/api/MyProfile.js +++ b/frontend/static/js/api/MyProfile.js @@ -15,7 +15,7 @@ class MyProfile extends Profile /** * * @param {*} form_data - * @returns + * @returns {Promise} */ async change_avatar(form_data) { diff --git a/frontend/static/js/api/account.js b/frontend/static/js/api/account.js index 6abb89b..b8b7e83 100644 --- a/frontend/static/js/api/account.js +++ b/frontend/static/js/api/account.js @@ -16,7 +16,7 @@ class Account /** * @param {String} username * @param {String} password - * @returns + * @returns {?Promise} */ async create(username, password) { @@ -33,7 +33,7 @@ class Account /** * @param {String} password - * @returns + * @returns {?Promise} */ async delete(password) { @@ -52,7 +52,7 @@ class Account /** * Get account data (username) - * @returns + * @returns {?Promise} */ async get() { @@ -71,7 +71,7 @@ class Account * * @param {*} data * @param {Number} password - * @returns + * @returns {?Object} */ async update(data, password) { diff --git a/frontend/static/js/api/client.js b/frontend/static/js/api/client.js index 2ec1123..3d0a900 100644 --- a/frontend/static/js/api/client.js +++ b/frontend/static/js/api/client.js @@ -77,7 +77,7 @@ class Client /** * The only right way to determine is the user is logged - * @returns {Boolean} + * @returns {Promise} */ async isAuthentificate() { @@ -90,7 +90,7 @@ class Client * Send a GET request to %uri% * @param {String} uri * @param {*} data - * @returns {Response} + * @returns {Promise} */ async _get(uri, data) { @@ -105,7 +105,7 @@ class Client * Send a POST request * @param {String} uri * @param {*} data - * @returns {Response} + * @returns {Promise} */ async _post(uri, data) { @@ -124,7 +124,7 @@ class Client * Send a DELETE request * @param {String} uri * @param {String} data - * @returns {Response} + * @returns {Promise} */ async _delete(uri, data) { @@ -143,7 +143,7 @@ class Client * Send a PATCH request with json * @param {String} uri * @param {*} data - * @returns {Response} + * @returns {Promise} */ async _patch_json(uri, data) { @@ -162,7 +162,7 @@ class Client * Send a PATCH request with file * @param {String} uri * @param {*} file - * @returns {Response} + * @returns {Promise} */ async _patch_file(uri, file) { @@ -178,7 +178,7 @@ class Client /** * Change logged state. Use It if you recv an 403 error - * @param {Boolean} state + * @param {Promise} state * @returns */ async _update_logged(state) @@ -210,7 +210,7 @@ class Client * Loggin the user * @param {String} username * @param {String} password - * @returns + * @returns {Promise} */ async login(username, password) { @@ -223,6 +223,7 @@ class Client /** * Logout the user + * @returns {Promise} */ async logout() { @@ -232,7 +233,7 @@ class Client /** * Determine if the user is logged. NEVER USE IT, USE isAuthentificated() - * @returns {Boolean} + * @returns {Promise} */ async _test_logged() { diff --git a/frontend/static/js/api/matchmaking.js b/frontend/static/js/api/matchmaking.js index 1178803..c63dd4d 100644 --- a/frontend/static/js/api/matchmaking.js +++ b/frontend/static/js/api/matchmaking.js @@ -19,7 +19,7 @@ class MatchMaking * @param {CallableFunction} receive_func * @param {CallableFunction} disconnect_func * @param {Number} mode The number of players in a game - * @returns {undefined} + * @returns {Promise} */ async start(receive_func, disconnect_func, mode) { @@ -50,6 +50,9 @@ class MatchMaking this.disconnect_func(event); } + /** + * @returns {Promise} + */ async stop() { if (this._socket) diff --git a/frontend/static/js/api/profile.js b/frontend/static/js/api/profile.js index 39717b5..918761d 100644 --- a/frontend/static/js/api/profile.js +++ b/frontend/static/js/api/profile.js @@ -33,6 +33,10 @@ class Profile this.isBlocked = false; } + /** + * + * @returns {Promise<*>} + */ async init() { let response = await this.client._get(`/api/profiles/${this.username}`); diff --git a/frontend/static/js/api/profiles.js b/frontend/static/js/api/profiles.js index 52206ec..3d46efe 100644 --- a/frontend/static/js/api/profiles.js +++ b/frontend/static/js/api/profiles.js @@ -15,7 +15,7 @@ class Profiles /** * - * @returns {[Profile]} + * @returns {Promise<[Profile]>} */ async all() { @@ -45,7 +45,7 @@ class Profiles /** * Block a user * @param {Number} user_id - * @returns + * @returns {Promise} */ async block(user_id) { @@ -62,7 +62,7 @@ class Profiles /** * Unblock a user * @param {Number} user_id - * @returns + * @returns {Promise} */ async deblock(user_id) { diff --git a/frontend/static/js/api/tournament/tournament.js b/frontend/static/js/api/tournament/tournament.js index b0ac785..46a9502 100644 --- a/frontend/static/js/api/tournament/tournament.js +++ b/frontend/static/js/api/tournament/tournament.js @@ -73,6 +73,10 @@ class Tourmanent this.connected = false; } + /** + * + * @returns {Promise} + */ async init() { let response = await this.client._get(`/api/tournaments/${id}`); @@ -108,6 +112,12 @@ class Tourmanent this._socket.send(JSON.stringify({participate: ""})); } + /** + * Join the tournament Websocket + * @param {CallableFunction} receive_func + * @param {CallableFunction} disconnect_func + * @returns {?} + */ async join(receive_func, disconnect_func) { if (!await this.client.isAuthentificate()) diff --git a/frontend/static/js/api/tournament/tournaments.js b/frontend/static/js/api/tournament/tournaments.js index 2ae420a..9f00564 100644 --- a/frontend/static/js/api/tournament/tournaments.js +++ b/frontend/static/js/api/tournament/tournaments.js @@ -17,7 +17,7 @@ class Tourmanents /** * * @param {Number} id - * @returns + * @returns {?Promise} */ async getTournament(id) { @@ -47,6 +47,7 @@ class Tourmanents /** * @param {String} state must be "finished", or "started", or "waiting". Any other return all elements + * @returns {?Promise<[Tourmanent]>} */ async search(state) { @@ -76,6 +77,10 @@ class Tourmanents return tournaments; } + /** + * Get all tournaments + * @returns {?Promise<[Tourmanent]>} + */ async all() { return await this.search(""); From feaaaec128c01b9578d4813ffec0418fc9a128b0 Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Mon, 29 Jan 2024 10:16:06 +0100 Subject: [PATCH 2/8] improved login redirections --- frontend/static/js/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js index 2d2af71..4005051 100644 --- a/frontend/static/js/index.js +++ b/frontend/static/js/index.js @@ -107,14 +107,16 @@ const router = async(uri) => { if (lastView !== undefined) await lastView.leavePage(); + if (uri !== '/login' && uri !== '/register' && uri !== '/logout') + lastPageUrlBeforeLogin = uri; + else + lastPageUrlBeforeLogin = undefined; const view = new match.route.view(getParams(match), lastPageUrlBeforeLogin); if (view instanceof AbstractRedirectView && await view.redirect()) return 1; lastView = view; - if (uri !== '/login' && uri !== '/register' && uri !== '/logout') - lastPageUrlBeforeLogin = uri; if (await renderView(view)) return 1; From f32caad343e6d974a6bf2d4a5b452e71081b67d7 Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Mon, 29 Jan 2024 10:19:11 +0100 Subject: [PATCH 3/8] bozo move --- frontend/static/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js index 4005051..e2a7cfe 100644 --- a/frontend/static/js/index.js +++ b/frontend/static/js/index.js @@ -19,7 +19,7 @@ import TournamentPageView from "./views/tournament/TournamentPageView.js"; import TournamentsView from "./views/tournament/TournamentsListView.js"; import TournamentCreateView from "./views/tournament/TournamentCreateView.js"; -let client = new Client(location.protocol + "//" + location.host) +let client = new Client(location.origin) let lastView = undefined let lastPageUrlBeforeLogin = undefined From b0ba327f7f7283ce74279b3fc0ebb7992d958dad Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Mon, 29 Jan 2024 10:19:55 +0100 Subject: [PATCH 4/8] ; --- frontend/static/js/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js index e2a7cfe..d94db7d 100644 --- a/frontend/static/js/index.js +++ b/frontend/static/js/index.js @@ -19,10 +19,10 @@ import TournamentPageView from "./views/tournament/TournamentPageView.js"; import TournamentsView from "./views/tournament/TournamentsListView.js"; import TournamentCreateView from "./views/tournament/TournamentCreateView.js"; -let client = new Client(location.origin) +let client = new Client(location.origin); -let lastView = undefined -let lastPageUrlBeforeLogin = undefined +let lastView = undefined; +let lastPageUrlBeforeLogin = undefined; const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\\/").replace(/:\w+/g, "(.+)") + "$"); From 8ee2beb432c61a09391a8e0893e7fe6e22321bfa Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Mon, 29 Jan 2024 10:50:18 +0100 Subject: [PATCH 5/8] lang: improved, Home view translation --- frontend/static/js/api/LanguageManager.js | 47 ++++++++++++++++------- frontend/static/js/index.js | 15 ++++++-- frontend/static/js/lang/en.json | 7 +++- frontend/static/js/lang/fr.json | 7 +++- frontend/static/js/views/HomeView.js | 11 +++--- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/frontend/static/js/api/LanguageManager.js b/frontend/static/js/api/LanguageManager.js index 3e1c9b3..2c9ebb5 100644 --- a/frontend/static/js/api/LanguageManager.js +++ b/frontend/static/js/api/LanguageManager.js @@ -1,11 +1,17 @@ +import { reloadView } from '../index.js' + export default class LanguageManager { constructor() { this.availableLanguages = ['en', 'fr']; + this.dict = null; this.currentLang = 'en' this.chosenLang = localStorage.getItem('preferedLanguage') || this.currentLang; if (this.chosenLang !== this.currentLang && this.availableLanguages.includes(this.chosenLang)) { this.translatePage(); + this.currentLang = this.chosenLang; + } else { + this.loadDict(this.chosenLang); } } @@ -13,33 +19,48 @@ export default class LanguageManager { if (this.currentLang === this.chosenLang) return; - let dictUrl = `${location.origin}/static/js/lang/${this.chosenLang}.json`; - let translation = await fetch(dictUrl).then(response => { - if (response.status !== 200) - return null; - return response.json(); - }); - if (!translation) { - console.log(`No translation found for language ${this.chosenLang}`); + await this.loadDict(this.chosenLang); + if (!this.dict) return 1; - } + document.querySelectorAll('[data-i18n]').forEach(el => { let key = el.getAttribute('data-i18n'); - el.innerHTML = translation[key]; + el.innerHTML = this.dict[key]; }) + await reloadView(); - this.currentLang = this.chosenLang; return 0; } async changeLanguage(lang) { if (lang === this.currentLang || !this.availableLanguages.includes(lang)) - return; + return 1; this.chosenLang = lang; if (await this.translatePage() !== 0) - return; + return 1; + this.currentLang = this.chosenLang; localStorage.setItem('preferedLanguage', lang); + return 0; + } + + async loadDict(lang) { + let dictUrl = `${location.origin}/static/js/lang/${lang}.json`; + let response = await fetch(dictUrl); + + if (response.status !== 200) { + console.log(`No translation found for language ${lang}`); + return; + } + + this.dict = await response.json(); + } + + get(key, defaultTxt) { + if (!this.dict) + return defaultTxt; + + return this.dict[key] || defaultTxt; } } diff --git a/frontend/static/js/index.js b/frontend/static/js/index.js index d94db7d..02b1591 100644 --- a/frontend/static/js/index.js +++ b/frontend/static/js/index.js @@ -48,9 +48,11 @@ const navigateTo = async (uri) => { } }; +const reloadView = async _ => renderView(lastView); + async function renderView(view) { - let content = await view.getHtml(); + let content = await view?.getHtml(); if (content == null) return 1; @@ -140,12 +142,19 @@ document.addEventListener("DOMContentLoaded", async () => { //Languages Array.from(document.getElementById('languageSelector').children).forEach(el => { - el.onclick = _ => client.lang.changeLanguage(el.value); + el.onclick = async _ => { + if (await client.lang.changeLanguage(el.value)) + return; + document.querySelector('#languageSelector > .active')?.classList.remove('active'); + el.classList.add('active'); + }; }); + document.querySelector(`#languageSelector > [value=${client.lang.chosenLang}]`) + ?.classList.add('active'); await client.isAuthentificate(); router(location.pathname); document.querySelector('a[href=\'' + location.pathname + '\']')?.classList.add('active'); }); -export { client, navigateTo } +export { client, navigateTo, reloadView } diff --git a/frontend/static/js/lang/en.json b/frontend/static/js/lang/en.json index 3d9b14e..c558d5d 100644 --- a/frontend/static/js/lang/en.json +++ b/frontend/static/js/lang/en.json @@ -5,5 +5,10 @@ "navbarRegister": "Register", "navbarProfile": "My Profile", "navbarSettings": "Settings", - "navbarLogout": "Logout" + "navbarLogout": "Logout", + "homeTitle": "Home", + "homeOnline": "Play online", + "homeOffline": "Play offline", + "homeMe": "Me", + "homeLogout": "Logout" } diff --git a/frontend/static/js/lang/fr.json b/frontend/static/js/lang/fr.json index 3307204..76228c5 100644 --- a/frontend/static/js/lang/fr.json +++ b/frontend/static/js/lang/fr.json @@ -5,5 +5,10 @@ "navbarRegister": "S'inscrire", "navbarProfile": "Mon Profil", "navbarSettings": "Paramètres", - "navbarLogout": "Se déconnecter" + "navbarLogout": "Se déconnecter", + "homeTitle": "Maison", + "homeOnline": "Jouer en ligne", + "homeOffline": "Jouer hors ligne", + "homeMe": "Moi", + "homeLogout": "Se déconnecter" } diff --git a/frontend/static/js/views/HomeView.js b/frontend/static/js/views/HomeView.js index fb13511..1266d36 100644 --- a/frontend/static/js/views/HomeView.js +++ b/frontend/static/js/views/HomeView.js @@ -1,3 +1,4 @@ +import { client } from "../index.js"; import AbstractAuthentificateView from "./abstracts/AbstractAuthentifiedView.js"; export default class extends AbstractAuthentificateView { @@ -8,11 +9,11 @@ export default class extends AbstractAuthentificateView { async getHtml() { return /* HTML */ ` -

HOME

- Play a game - Play offline - Me - Logout +

${client.lang.get('homeTitle', 'Home')}

+ ${client.lang.get('homeOnline', 'Play online')} + ${client.lang.get('homeOffline', 'Play offline')} + ${client.lang.get('homeMe', 'Me')} + ${client.lang.get('homeLogout', 'Logout')} `; } } From ab5c3deec1e348431c3ba56c67d7e47dc58d038b Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Mon, 29 Jan 2024 12:59:49 +0100 Subject: [PATCH 6/8] lang: window title translation --- frontend/static/js/lang/en.json | 1 + frontend/static/js/lang/fr.json | 7 ++++--- frontend/static/js/views/HomeView.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/static/js/lang/en.json b/frontend/static/js/lang/en.json index c558d5d..8fc8946 100644 --- a/frontend/static/js/lang/en.json +++ b/frontend/static/js/lang/en.json @@ -6,6 +6,7 @@ "navbarProfile": "My Profile", "navbarSettings": "Settings", "navbarLogout": "Logout", + "homeWindowTitle": "Home", "homeTitle": "Home", "homeOnline": "Play online", "homeOffline": "Play offline", diff --git a/frontend/static/js/lang/fr.json b/frontend/static/js/lang/fr.json index 76228c5..a879558 100644 --- a/frontend/static/js/lang/fr.json +++ b/frontend/static/js/lang/fr.json @@ -1,14 +1,15 @@ { "navbarSearch": "Recherche", "navbarHome": "Maison", - "navbarLogin": "Se connecter", + "navbarLogin": "Connexion", "navbarRegister": "S'inscrire", "navbarProfile": "Mon Profil", "navbarSettings": "Paramètres", - "navbarLogout": "Se déconnecter", + "navbarLogout": "Déconnexion", + "homeWindowTitle": "Maison", "homeTitle": "Maison", "homeOnline": "Jouer en ligne", "homeOffline": "Jouer hors ligne", "homeMe": "Moi", - "homeLogout": "Se déconnecter" + "homeLogout": "Déconnexion" } diff --git a/frontend/static/js/views/HomeView.js b/frontend/static/js/views/HomeView.js index 1266d36..a98fd9f 100644 --- a/frontend/static/js/views/HomeView.js +++ b/frontend/static/js/views/HomeView.js @@ -3,7 +3,7 @@ import AbstractAuthentificateView from "./abstracts/AbstractAuthentifiedView.js" export default class extends AbstractAuthentificateView { constructor(params) { - super(params, "Home"); + super(params, client.lang.get('homeWindowTitle', 'Home')); this.redirect_url = "/login" } From 2f5cfc0e57015dd0dfe3bda50838adee424d1717 Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Wed, 31 Jan 2024 12:53:19 +0100 Subject: [PATCH 7/8] accounts: 401 Response in case of invalid login --- accounts/views/login.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/views/login.py b/accounts/views/login.py index fc02e4a..afcc03d 100644 --- a/accounts/views/login.py +++ b/accounts/views/login.py @@ -18,6 +18,6 @@ class LoginView(APIView): serializer.is_valid(raise_exception=True) user = serializer.get_user(data) if user is None: - return Response({'login': ['Invalid username or password.']}, status.HTTP_400_BAD_REQUEST) + return Response({'login': ['Invalid username or password.']}, status.HTTP_401_UNAUTHORIZED) login(request, user) return Response({'id': user.pk}, status=status.HTTP_200_OK) From d4575c92dbbae76dc8d26c2eaaa8438e4036d1f1 Mon Sep 17 00:00:00 2001 From: AdrienLSH Date: Wed, 31 Jan 2024 13:54:36 +0100 Subject: [PATCH 8/8] lang: translation of django's response --- frontend/static/js/api/client.js | 3 ++- transcendence/settings.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/frontend/static/js/api/client.js b/frontend/static/js/api/client.js index 3d0a900..1e89882 100644 --- a/frontend/static/js/api/client.js +++ b/frontend/static/js/api/client.js @@ -114,7 +114,8 @@ class Client headers: { "Content-Type": "application/json", "X-CSRFToken": getCookie("csrftoken"), - }, + 'Accept-Language': this.lang.currentLang, + }, body: JSON.stringify(data), }); return response; diff --git a/transcendence/settings.py b/transcendence/settings.py index b75cedb..f6193a8 100644 --- a/transcendence/settings.py +++ b/transcendence/settings.py @@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/4.2/ref/settings/ import os from pathlib import Path +from django.utils.translation import gettext_lazy as _ # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -79,6 +80,7 @@ MIDDLEWARE = [ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.locale.LocaleMiddleware', ] ROOT_URLCONF = 'transcendence.urls' @@ -137,6 +139,11 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' +LANGUAGES = [ + ('en', _('English')), + ('fr', _('French')), +] + TIME_ZONE = 'UTC' USE_I18N = True