Skip to content

Commit

Permalink
Making legals link customizable
Browse files Browse the repository at this point in the history
This PR makes legal links (privacy policy, etc...) customizable via ADMIN_API.
This also removes the need for a DISPLAY_TERMS_OF_USE environment variable.

This PR also adds new fields in the /map endpoint to customize the look of the platform (background color and customize icons)
  • Loading branch information
moufmouf committed Oct 12, 2022
1 parent d7e8ce8 commit af66e69
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 19 deletions.
35 changes: 30 additions & 5 deletions front/src/Components/Login/LoginScene.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts">
import type { Game } from "../../Phaser/Game/Game";
import { LoginScene, LoginSceneName } from "../../Phaser/Login/LoginScene";
import { DISPLAY_TERMS_OF_USE, MAX_USERNAME_LENGTH } from "../../Enum/EnvironmentVariable";
import { MAX_USERNAME_LENGTH } from "../../Enum/EnvironmentVariable";
import logoImg from "../images/logo.png";
import poweredByWorkAdventureImg from "../images/Powered_By_WorkAdventure_Big.png";
import { gameManager } from "../../Phaser/Game/GameManager";
import LL from "../../i18n/i18n-svelte";
import LL, {locale} from "../../i18n/i18n-svelte";
import { NameNotValidError, NameTooLongError } from "../../Exception/NameError";
export let game: Game;
Expand All @@ -17,6 +17,29 @@
let errorName = "";
let logo = gameManager.currentStartedRoom?.loginSceneLogo ?? logoImg;
let legals = gameManager.currentStartedRoom?.legals ?? {};
let legalStrings: string[] = [];
if (legals?.termsOfUseUrl) {
legalStrings.push("<a href=\""+encodeURI(legals.termsOfUseUrl)+"\" target=\"_blank\">" + $LL.login.termsOfUse() + "</a>");
}
if (legals?.privacyPolicyUrl) {
legalStrings.push("<a href=\""+encodeURI(legals.privacyPolicyUrl)+"\" target=\"_blank\">" + $LL.login.privacyPolicy() + "</a>");
}
if (legals?.cookiePolicyUrl) {
legalStrings.push("<a href=\""+encodeURI(legals.cookiePolicyUrl)+"\" target=\"_blank\">" + $LL.login.cookiePolicy() + "</a>");
}
let legalString: string | undefined;
if (legalStrings.length > 0) {
if (Intl.ListFormat) {
const formatter = new Intl.ListFormat(locale, { style: 'long', type: 'conjunction' });
legalString = formatter.format(legalStrings);
} else {
// For old browsers
legalString = legalStrings.join(', ');
}
}
function submit() {
startValidating = true;
Expand Down Expand Up @@ -66,11 +89,13 @@
{/if}
</section>

{#if DISPLAY_TERMS_OF_USE}
{#if legalString}
<section class="terms-and-conditions">
<a style="display: none;" href="traduction">Need for traduction</a>
<a style="display: none;" href="translation">Needed for translation CSS</a>
<p>
{@html $LL.login.terms()}
{@html $LL.login.terms({
links: legalString
})}
</p>
</section>
{/if}
Expand Down
16 changes: 12 additions & 4 deletions front/src/Connexion/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CONTACT_URL, PUSHER_URL, DISABLE_ANONYMOUS } from "../Enum/EnvironmentV
import { localUserStore } from "./LocalUserStore";
import axios from "axios";
import { axiosWithRetry } from "./AxiosUtils";
import { isMapDetailsData } from "../Messages/JsonMessages/MapDetailsData";
import {isMapDetailsData, LegalsData, MapDetailsData} from "../Messages/JsonMessages/MapDetailsData";
import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect";
import { MucRoomDefinitionInterface } from "../Messages/JsonMessages/MucRoomDefinitionInterface";

Expand Down Expand Up @@ -34,6 +34,7 @@ export class Room {
private _showPoweredBy: boolean | undefined = true;
private _roomName: string | undefined;
private _pricingUrl: string | undefined;
private _legals: LegalsData | undefined;

private constructor(private roomUrl: URL) {
this.id = roomUrl.pathname;
Expand Down Expand Up @@ -95,7 +96,7 @@ export class Room {

private async getMapDetail(): Promise<MapDetail | RoomRedirect> {
try {
const result = await axiosWithRetry.get(`${PUSHER_URL}/map`, {
const result = await axiosWithRetry.get<unknown>(`${PUSHER_URL}/map`, {
params: {
playUri: this.roomUrl.toString(),
authToken: localUserStore.getAuthToken(),
Expand All @@ -104,18 +105,20 @@ export class Room {

const data = result.data;

if (data.authenticationMandatory !== undefined) {
data.authenticationMandatory = Boolean(data.authenticationMandatory);
if ((data as MapDetailsData).authenticationMandatory !== undefined) {
(data as MapDetailsData).authenticationMandatory = Boolean((data as MapDetailsData).authenticationMandatory);
}

const roomRedirectChecking = isRoomRedirect.safeParse(data);
const mapDetailsDataChecking = isMapDetailsData.safeParse(data);

if (roomRedirectChecking.success) {
const data = roomRedirectChecking.data;
return {
redirectUrl: data.redirectUrl,
};
} else if (mapDetailsDataChecking.success) {
const data = mapDetailsDataChecking.data;
console.log("Map ", this.id, " resolves to URL ", data.mapUrl);
this._mapUrl = data.mapUrl;
this._group = data.group;
Expand All @@ -139,6 +142,7 @@ export class Room {
this._roomName = data.roomName ?? undefined;

this._pricingUrl = data.pricingUrl ?? undefined;
this._legals = data.legals ?? undefined;

return new MapDetail(data.mapUrl);
} else {
Expand Down Expand Up @@ -265,4 +269,8 @@ export class Room {
get pricingUrl(): string | undefined {
return this._pricingUrl;
}

get legals(): LegalsData | undefined {
return this._legals;
}
}
1 change: 0 additions & 1 deletion front/src/Enum/EnvironmentVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const POSITION_DELAY = 200; // Wait 200ms between sending position events
const MAX_EXTRAPOLATION_TIME = 100; // Extrapolate a maximum of 250ms if no new movement is sent by the player
export const MAX_USERNAME_LENGTH = parseInt(getEnvConfig("MAX_USERNAME_LENGTH") || "") || 10;
export const MAX_PER_GROUP = parseInt(getEnvConfig("MAX_PER_GROUP") || "4");
export const DISPLAY_TERMS_OF_USE = getEnvConfig("DISPLAY_TERMS_OF_USE") == "true";
export const NODE_ENV = getEnvConfig("NODE_ENV") || "development";
export const CONTACT_URL = getEnvConfig("CONTACT_URL") || undefined;
export const POSTHOG_API_KEY: string = (getEnvConfig("POSTHOG_API_KEY") as string) || "";
Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/ca-ES/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const login: DeepPartial<Translation["login"]> = {
notValidError: "El nom no és vàlid",
},
},
terms: `Si continueu, esteu d'acord amb els nostres <a href="https://workadventu.re/terms-of-use" target="_blank">termes d'ús</a>, <a href="https://workadventu.re/privacy-policy" target="_blank">política de privacitat</a> i <a href="https://workadventu.re/cookie-policy" target="_blank">política de cookie</a>.`,
terms: `Si continueu, esteu d'acord amb els nostres {links}.`,
termsOfUse: "termes d'ús",
privacyPolicy: "política de privacitat",
cookiePolicy: "política de cookie",
continue: "Continuar",
};

Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/de-DE/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const login: DeepPartial<Translation["login"]> = {
notValidError: "Der Name ist ungültig",
},
},
terms: 'Wenn du fortfährst, akzeptierst du die <a href="https://workadventu.re/terms-of-use" target="_blank">Nutzungsbedingungen</a>, <a href="https://workadventu.re/privacy-policy" target="_blank">Datenschutzerklärung</a> und <a href="https://workadventu.re/cookie-policy" target="_blank">Cookierichtlinien</a>.',
terms: 'Wenn du fortfährst, akzeptierst du die {links}.',
termsOfUse: "Nutzungsbedingungen",
privacyPolicy: "Datenschutzerklärung",
cookiePolicy: "Cookierichtlinien",
continue: "Fortfahren",
};

Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/en-US/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ const login: BaseTranslation = {
notValidError: "Incorrect name format",
},
},
terms: 'By continuing, you are agreeing our <a href="https://workadventu.re/terms-of-use" target="_blank">terms of use</a>, <a href="https://workadventu.re/privacy-policy" target="_blank">privacy policy</a> and <a href="https://workadventu.re/cookie-policy" target="_blank">cookie policy</a>.',
terms: 'By continuing, you are agreeing our {links}.',
termsOfUse: "terms of use",
privacyPolicy: "privacy policy",
cookiePolicy: "cookie policy",
continue: "Continue",
};

Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/es-ES/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const login: DeepPartial<Translation["login"]> = {
notValidError: "El nombre no es válido",
},
},
terms: 'Si continúa, está de acuerdo con nuestros <a href="https://workadventu.re/terms-of-use" target="_blank">términos de uso</a>, <a href="https://workadventu.re/privacy-policy" target="_blank">política de privacidad</a> y <a href="https://workadventu.re/cookie-policy" target="_blank">política de cookie</a>.',
terms: 'Si continúa, está de acuerdo con nuestros {links}.',
termsOfUse: "términos de uso",
privacyPolicy: "política de privacidad",
cookiePolicy: "política de cookie",
continue: "Continuar",
};

Expand Down
2 changes: 1 addition & 1 deletion front/src/i18n/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { FormattersInitializer } from "typesafe-i18n";
import type { Locales, Formatters } from "./i18n-types";

// eslint-disable-next-line @typescript-eslint/require-await
export const initFormatters: FormattersInitializer<Locales, Formatters> = async () => {
export const initFormatters: FormattersInitializer<Locales, Formatters> = async (locale: Locales) => {
const formatters: Formatters = {
// add your formatter functions here
};
Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/fr-FR/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const login: DeepPartial<Translation["login"]> = {
notValidError: "Le nom n'est pas valide",
},
},
terms: 'En continuant, vous acceptez nos <a href="https://workadventu.re/terms-of-use" target="_blank">conditions d\'utilisation</a>, notre <a href="https://workadventu.re/privacy-policy" target="_blank">politique de confidentialité</a> et notre <a href="https://workadventu.re/cookie-policy" target="_blank">politique relative aux cookies</a>.',
terms: 'En continuant, vous acceptez nos {links}.',
termsOfUse: "nos conditions d'utilisation",
privacyPolicy: "notre politique de confidentialité",
cookiePolicy: "notre politique relative aux cookies",
continue: "Continuer",
};

Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/pt-BR/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const login: DeepPartial<Translation["login"]> = {
notValidError: "O nome não é válido",
},
},
terms: 'Ao continuar, você concorda com nossos <a href="https://workadventu.re/terms-of-use" target="_blank">termos de uso</a> e <a href="https://workadventu.re/cookie-policy" target="_blank">política de privacidade de cookies</a>.',
terms: 'Ao continuar, você concorda com nossos {links}.',
termsOfUse: "termos de uso",
privacyPolicy: "política de privacidade",
cookiePolicy: "política de cookies",
continue: "Continuar",
};

Expand Down
5 changes: 4 additions & 1 deletion front/src/i18n/zh-CN/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ const login: DeepPartial<Translation["login"]> = {
empty: "名字为空",
},
},
terms: '点击继续,意味着你同意我们的<a href="https://workadventu.re/terms-of-use" target="_blank">使用协议</a>, <a href="https://workadventu.re/privacy-policy" target="_blank">隐私政策</a> 和 <a href="https://workadventu.re/cookie-policy" target="_blank">Cookie策略</a>.',
terms: '点击继续,意味着你同意我们的{links}.',
termsOfUse: "使用协议",
privacyPolicy: "隐私政策",
cookiePolicy: "Cookie策略",
continue: "继续",
};

Expand Down
1 change: 0 additions & 1 deletion front/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export default defineConfig({
"START_ROOM_URL",
"MAX_USERNAME_LENGTH",
"MAX_PER_GROUP",
"DISPLAY_TERMS_OF_USE",
"POSTHOG_API_KEY",
"POSTHOG_URL",
"NODE_ENV",
Expand Down
48 changes: 48 additions & 0 deletions messages/JsonMessages/MapDetailsData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,42 @@ const isMapThirdPartyData = z.object({
}),
});

const isLegalsData = z.object({
termsOfUseUrl: extendApi(z.string().nullable().optional(), {
description: "The link to the 'terms of user' page (link displayed on the 'enter your name' scene)",
}),
privacyPolicyUrl: extendApi(z.string().nullable().optional(), {
description: "The link to the 'privacy policy' page (link displayed on the 'enter your name' scene)",
}),
cookiePolicyUrl: extendApi(z.string().nullable().optional(), {
description: "The link to the 'cookie policy' page (link displayed on the 'enter your name' scene)",
}),
});

const CustomizeSceneData = z.object({
clothesIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the clothes icon",
}),
accessoryIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the accessory icon",
}),
hatIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the hat icon",
}),
hairIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the hair icon",
}),
eyesIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the eyes icon",
}),
bodyIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the body icon",
}),
turnIcon: extendApi(z.string().nullable().optional(), {
description: "The URL of the turn icon",
}),
});

export const isMapDetailsData = z.object({
mapUrl: extendApi(z.string(), {
description: "The full URL to the JSON map file",
Expand Down Expand Up @@ -115,9 +151,21 @@ export const isMapDetailsData = z.object({
"The url of the page where the user can see the price to upgrade and can use the features he wants in the future.",
example: "https://example.com/pricing",
}),
legals: extendApi(isLegalsData.nullable().optional(), {
description: "Configuration of the legals link (privacy policy, etc...)",
}),
customizeWokaScene: extendApi(CustomizeSceneData.nullable().optional(), {
description: "Configuration of the 'Customize your Woka' scene (WIP)",
}),
backgroundColor: extendApi(z.string().nullable().optional(), {
description: 'The background color used on configuration scenes (enter your name, select a woka, etc...) (WIP)',
example: "#330033",
}),
});

export type MapDetailsData = z.infer<typeof isMapDetailsData>;
export type MapThirdPartyData = z.infer<typeof isMapThirdPartyData>;
export type MapBbbData = z.infer<typeof isBbbData>;
export type MapJitsiData = z.infer<typeof isJitsiData>;
export type LegalsData = z.infer<typeof isLegalsData>;
export type CustomizeSceneData = z.infer<typeof CustomizeSceneData>;

0 comments on commit af66e69

Please sign in to comment.