#258 update names, flags, links, age for all languages

This commit is contained in:
Andrea 2021-12-14 18:38:53 +01:00
parent a936b00f4b
commit 961de266e5
18 changed files with 199 additions and 66 deletions

View File

@ -12,7 +12,7 @@
<div class="row flex-row-reverse"> <div class="row flex-row-reverse">
<div class="col-12 col-md-4"> <div class="col-12 col-md-4">
<div class="btn-group-vertical w-100 mb-3"> <div class="btn-group-vertical w-100 mb-3">
<SocialLogin v-for="(providerOptions, provider) in socialProviders" <SocialLogin v-for="(providerOptions, provider) in socialProviders" :key="provider"
:provider="provider" :options="providerOptions"/> :provider="provider" :options="providerOptions"/>
</div> </div>
</div> </div>

View File

@ -0,0 +1,37 @@
<template>
<div v-if="hasChanges" class="form-check form-switch my-2">
<label>
<input class="form-check-input" type="checkbox" v-model="propagate">
<T>profile.editor.propagate</T>
</label>
</div>
</template>
<script>
export default {
props: {
field: { required: true },
before: { required: true },
after: { required: true },
},
data() {
return {
propagate: false,
}
},
computed: {
hasChanges() {
return JSON.stringify(this.before) !== JSON.stringify(this.after);
}
},
methods: {
emit() {
this.$emit('change', this.field, this.hasChanges && this.propagate);
},
},
watch: {
hasChanges() { this.emit(); },
propagate() { this.emit(); },
}
}
</script>

View File

@ -551,6 +551,7 @@ profile:
header: 'Card editor' header: 'Card editor'
save: 'Save your card' save: 'Save your card'
defaults: 'Restore defaults' defaults: 'Restore defaults'
propagate: 'Propagate this change to your cards in all languages'
opinion: opinion:
yes: 'Yes' yes: 'Yes'
jokingly: 'Jokingly' jokingly: 'Jokingly'

View File

@ -443,6 +443,7 @@ profile:
header: 'Visitenkarte-Editor' header: 'Visitenkarte-Editor'
save: 'Visitenkarte speichern' save: 'Visitenkarte speichern'
defaults: 'Standardwerte wiederherstellen' defaults: 'Standardwerte wiederherstellen'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Ja' yes: 'Ja'
jokingly: 'Scherzhaft' jokingly: 'Scherzhaft'

View File

@ -552,6 +552,7 @@ profile:
header: 'Card editor' header: 'Card editor'
save: 'Save your card' save: 'Save your card'
defaults: 'Restore defaults' defaults: 'Restore defaults'
propagate: 'Propagate this change to your cards in all languages'
opinion: opinion:
yes: 'Yes' yes: 'Yes'
jokingly: 'Jokingly' jokingly: 'Jokingly'

View File

@ -456,6 +456,7 @@ profile:
header: 'Editor de tarjetas' header: 'Editor de tarjetas'
save: 'Guarda tu tarjeta' save: 'Guarda tu tarjeta'
defaults: 'Restaurar valores predeterminados' defaults: 'Restaurar valores predeterminados'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Sí' yes: 'Sí'
jokingly: 'En broma' jokingly: 'En broma'

View File

@ -449,6 +449,7 @@ profile:
header: 'Éditeur de carte' header: 'Éditeur de carte'
save: 'Sauvegarder votre carte' save: 'Sauvegarder votre carte'
defaults: 'Restaurer les valeurs par défaut' defaults: 'Restaurer les valeurs par défaut'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Oui' yes: 'Oui'
jokingly: 'Pour plaisanter' jokingly: 'Pour plaisanter'

View File

@ -455,6 +455,7 @@ profile:
header: 'Editor de cartões' header: 'Editor de cartões'
save: 'Salve o cartão' save: 'Salve o cartão'
defaults: 'Restaurar valores padrão' defaults: 'Restaurar valores padrão'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Sim' yes: 'Sim'
jokingly: 'É brincadeira' jokingly: 'É brincadeira'

View File

@ -457,6 +457,7 @@ profile:
header: 'カード編集' header: 'カード編集'
save: 'カード保存' save: 'カード保存'
defaults: '既定に復元' defaults: '既定に復元'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: '好き' yes: '好き'
jokingly: '冗談っぽく' jokingly: '冗談っぽく'

View File

@ -449,6 +449,7 @@ profile:
header: 'Kaart editor' header: 'Kaart editor'
save: 'Sla jouw kaart op' save: 'Sla jouw kaart op'
defaults: 'Zet terug naar standaardwaarden' defaults: 'Zet terug naar standaardwaarden'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Ja' yes: 'Ja'
jokingly: 'Voor de grap' jokingly: 'Voor de grap'

View File

@ -453,6 +453,7 @@ profile:
header: 'Kort redigerer' header: 'Kort redigerer'
save: 'Lagre kort' save: 'Lagre kort'
defaults: 'Restaurer originale' defaults: 'Restaurer originale'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Ja' yes: 'Ja'
jokingly: 'På tull' jokingly: 'På tull'

View File

@ -1245,6 +1245,7 @@ profile:
header: 'Edytor wizytówki' header: 'Edytor wizytówki'
save: 'Zapisz wizytówkę' save: 'Zapisz wizytówkę'
defaults: 'Przywróć domyślne' defaults: 'Przywróć domyślne'
propagate: 'Zapisz tę zmianę we wszystkich swoich wizytówkach, w każdym języku'
opinion: opinion:
yes: 'Tak' yes: 'Tak'
jokingly: 'Żartobliwie' jokingly: 'Żartobliwie'

View File

@ -451,6 +451,7 @@ profile:
header: 'Editor de cartões' header: 'Editor de cartões'
save: 'Salve o cartão' save: 'Salve o cartão'
defaults: 'Restaurar valores padrão' defaults: 'Restaurar valores padrão'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Sim' yes: 'Sim'
jokingly: 'É brincadeira' jokingly: 'É brincadeira'
@ -626,7 +627,7 @@ terms:
Oi! Lhe escrevemos para informar que atualizámos nossos termos de serviço. Oi! Lhe escrevemos para informar que atualizámos nossos termos de serviço.
changes: changes:
- > - >
Em janeiro vamos começar a vamos deletar em breve as contas não usadas para previr a acumulação dos nomes Em janeiro vamos começar a vamos deletar em breve as contas não usadas para previr a acumulação dos nomes
(quando não há nem carta nem entrada por um mês). (quando não há nem carta nem entrada por um mês).
- > - >
Gostávamos de oferecer um espaço seguro para toda a gente queer independentemente de sua idade Gostávamos de oferecer um espaço seguro para toda a gente queer independentemente de sua idade
@ -640,7 +641,7 @@ terms:
Todas estas traduções são auxiliares, a versão inglesa continua sendo a única juricamente vinculativa. Todas estas traduções são auxiliares, a versão inglesa continua sendo a única juricamente vinculativa.
- > - >
Apesar de queerfobia, transfobia, exclusionismo queer e trolling Apesar de queerfobia, transfobia, exclusionismo queer e trolling
sempre terem sido compreendidos como infrangimentos de Termos de Serviço como «infringir as regras sociais», sempre terem sido compreendidos como infrangimentos de Termos de Serviço como «infringir as regras sociais»,
daqui por diante enlistamos todas elas como proibidas. daqui por diante enlistamos todas elas como proibidas.
admin: admin:

View File

@ -482,6 +482,7 @@ profile:
header: 'Редактор карточек' header: 'Редактор карточек'
save: 'Сохранить Вашу карточку' save: 'Сохранить Вашу карточку'
defaults: 'Вернуть слова по умолчанию' defaults: 'Вернуть слова по умолчанию'
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'Да' yes: 'Да'
jokingly: 'В шутку' jokingly: 'В шутку'

View File

@ -456,6 +456,7 @@ profile:
header: 'רעדאַקציע פון די װיזיט־⁠קאַרטל' header: 'רעדאַקציע פון די װיזיט־⁠קאַרטל'
save: 'Save your card' save: 'Save your card'
defaults: 'Restore defaults' # TODO defaults: 'Restore defaults' # TODO
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: 'יאָ' yes: 'יאָ'
jokingly: 'אין אַ שפּאַס' jokingly: 'אין אַ שפּאַס'

View File

@ -435,6 +435,7 @@ profile:
header: '卡編輯' header: '卡編輯'
save: '保存卡' save: '保存卡'
defaults: 'Restore defaults' # TODO defaults: 'Restore defaults' # TODO
propagate: 'Propagate this change to your cards in all languages' # TODO
opinion: opinion:
yes: '至愛' yes: '至愛'
jokingly: '諧謔' jokingly: '諧謔'

View File

@ -30,6 +30,7 @@
<div class="form-group"> <div class="form-group">
<label for="teamName">Team page display name:</label> <label for="teamName">Team page display name:</label>
<input class="form-control" name="teamName" maxlength="36" v-model="teamName"/> <input class="form-control" name="teamName" maxlength="36" v-model="teamName"/>
<PropagateCheckbox field="teamName" :before="beforeChanges.teamName" :after="teamName" v-if="otherProfiles > 0" @change="propagateChanged"/>
</div> </div>
<hr/> <hr/>
@ -44,6 +45,7 @@
<div class="form-group"> <div class="form-group">
<label for="footerName">Footer display name:</label> <label for="footerName">Footer display name:</label>
<input class="form-control" name="footerName" maxlength="36" v-model="footerName"/> <input class="form-control" name="footerName" maxlength="36" v-model="footerName"/>
<PropagateCheckbox field="footerName" :before="beforeChanges.footerName" :after="footerName" v-if="otherProfiles > 0" @change="propagateChanged"/>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -96,6 +98,7 @@
<T>profile.names</T> <T>profile.names</T>
</h3> </h3>
<OpinionListInput v-model="names"/> <OpinionListInput v-model="names"/>
<PropagateCheckbox field="names" :before="beforeChanges.names" :after="names" v-if="otherProfiles > 0" @change="propagateChanged"/>
</section> </section>
<section class="form-group"> <section class="form-group">
@ -131,6 +134,7 @@
<ButtonList v-model="flags" :options="allFlags" v-slot="s"> <ButtonList v-model="flags" :options="allFlags" v-slot="s">
<Flag :name="s.desc.split('|')[0]" :alt="s.desc.split('|')[1]" :img="`/flags/${s.v}.png`"/> <Flag :name="s.desc.split('|')[0]" :alt="s.desc.split('|')[1]" :img="`/flags/${s.v}.png`"/>
</ButtonList> </ButtonList>
<PropagateCheckbox field="flags" :before="beforeChanges.flags" :after="flags" v-if="otherProfiles > 0" @change="propagateChanged"/>
<details class="form-group border rounded" :open="Object.keys(customFlags).length > 0"> <details class="form-group border rounded" :open="Object.keys(customFlags).length > 0">
<summary class="px-3 py-2"> <summary class="px-3 py-2">
@ -140,7 +144,7 @@
<ImageWidgetRich v-model="customFlags" sizes="flag"/> <ImageWidgetRich v-model="customFlags" sizes="flag"/>
</div> </div>
</details> </details>
<PropagateCheckbox field="customFlags" :before="beforeChanges.customFlags" :after="customFlags" v-if="otherProfiles > 0" @change="propagateChanged"/>
<Answer question="flags" small/> <Answer question="flags" small/>
</section> </section>
@ -152,6 +156,7 @@
<ListInput v-model="links" v-slot="s"> <ListInput v-model="links" v-slot="s">
<input v-model="s.val" type="url" class="form-control" @keyup="s.update(s.val)" @paste="s.update(s.val)" @change="s.update(s.val)" required/> <input v-model="s.val" type="url" class="form-control" @keyup="s.update(s.val)" @paste="s.update(s.val)" @change="s.update(s.val)" required/>
</ListInput> </ListInput>
<PropagateCheckbox field="links" :before="beforeChanges.links" :after="links" v-if="otherProfiles > 0" @change="propagateChanged"/>
<p class="small text-muted mb-0"> <p class="small text-muted mb-0">
<Icon v="ad"/> <Icon v="ad"/>
<T>profile.linksRecommended</T> <T>profile.linksRecommended</T>
@ -179,6 +184,7 @@
<div class="input-group mb-3"> <div class="input-group mb-3">
<datepicker v-model="birthday" inline :disabled-dates="disabledDates" initial-view="year"/> <datepicker v-model="birthday" inline :disabled-dates="disabledDates" initial-view="year"/>
</div> </div>
<PropagateCheckbox field="birthday" :before="beforeChanges.birthday" :after="birthday" v-if="otherProfiles > 0" @change="propagateChanged"/>
</section> </section>
<section class="form-group"> <section class="form-group">
@ -223,6 +229,73 @@
} }
})) }))
const buildProfile = (profiles, currentLocale) => {
for (let locale in profiles) {
if (!profiles.hasOwnProperty(locale)) {
continue;
}
if (locale === currentLocale) {
const profile = profiles[locale];
return {
names: dictToList(profile.names),
pronouns: dictToList(profile.pronouns),
description: profile.description,
birthday: profile.birthday,
links: Object.keys(profile.links).length ? profile.links : [],
flags: profile.flags,
customFlags: profile.customFlags,
words: profile.words.map(x => dictToList(x)),
teamName: profile.teamName,
footerName: profile.footerName,
footerAreas: profile.footerAreas,
credentials: profile.credentials,
credentialsLevel: profile.credentialsLevel,
credentialsName: profile.credentialsName,
};
}
}
for (let locale in profiles) {
if (!profiles.hasOwnProperty(locale)) {
continue;
}
const profile = profiles[locale];
return {
names: dictToList(profile.names),
pronouns: [],
description: '',
birthday: profile.birthday,
links: Object.keys(profile.links).length ? profile.links : [],
flags: profile.flags.filter(f => !f.startsWith('-')),
customFlags: profile.customFlags,
words: [...defaultWords],
teamName: profile.teamName,
footerName: profile.footerName,
footerAreas: [],
credentials: [],
credentialsLevel: null,
credentialsName: null,
};
}
return {
names: [],
pronouns: [],
description: '',
birthday: null,
links: [],
flags: [],
customFlags: {},
words: [...defaultWords],
teamName: '',
footerName: '',
footerAreas: [],
credentials: [],
credentialsLevel: null,
credentialsName: null,
};
};
export default { export default {
mixins: [link], mixins: [link],
data() { data() {
@ -232,6 +305,7 @@
to: minBirthdate, to: minBirthdate,
from: maxBirthdate, from: maxBirthdate,
}, },
propagate: [],
}; };
}, },
async asyncData({ app, store }) { async asyncData({ app, store }) {
@ -243,69 +317,12 @@
authorization: 'Bearer ' + store.state.token, authorization: 'Bearer ' + store.state.token,
} })).profiles; } })).profiles;
for (let locale in profiles) { const profile = buildProfile(profiles, app.context.env.LOCALE);
if (!profiles.hasOwnProperty(locale)) {
continue;
}
if (locale === app.context.env.LOCALE) {
const profile = profiles[locale];
return {
names: dictToList(profile.names),
pronouns: dictToList(profile.pronouns),
description: profile.description,
birthday: profile.birthday,
links: Object.keys(profile.links).length ? profile.links : [],
flags: profile.flags,
customFlags: profile.customFlags,
words: profile.words.map(x => dictToList(x)),
teamName: profile.teamName,
footerName: profile.footerName,
footerAreas: profile.footerAreas,
credentials: profile.credentials,
credentialsLevel: profile.credentialsLevel,
credentialsName: profile.credentialsName,
};
}
}
for (let locale in profiles) {
if (!profiles.hasOwnProperty(locale)) {
continue;
}
const profile = profiles[locale];
return {
names: dictToList(profile.names),
pronouns: [],
description: '',
birthday: profile.birthday,
links: Object.keys(profile.links).length ? profile.links : [],
flags: profile.flags.filter(f => !f.startsWith('-')),
customFlags: profile.customFlags,
words: [...defaultWords],
teamName: profile.teamName,
footerName: profile.footerName,
footerAreas: [],
credentials: [],
credentialsLevel: null,
credentialsName: null,
};
}
return { return {
names: [], ...profile,
pronouns: [], beforeChanges: JSON.parse(JSON.stringify(profile)),
description: '', otherProfiles: Object.keys(profiles).filter(l => l !== app.context.env.LOCALE).length,
birthday: null,
links: [],
flags: [],
customFlags: {},
words: [...defaultWords],
teamName: '',
footerName: '',
footerAreas: [],
credentials: [],
credentialsLevel: null,
credentialsName: null,
}; };
}, },
mounted() { mounted() {
@ -327,12 +344,15 @@
flags: [...this.flags], flags: [...this.flags],
customFlags: {...this.customFlags}, customFlags: {...this.customFlags},
words: this.words.map(x => listToDict(x)), words: this.words.map(x => listToDict(x)),
teamName: this.teamName, teamName: this.teamName,
footerName: this.footerName, footerName: this.footerName,
footerAreas: this.footerAreas, footerAreas: this.footerAreas,
credentials: this.credentials, credentials: this.credentials,
credentialsLevel: this.credentialsLevel, credentialsLevel: this.credentialsLevel,
credentialsName: this.credentialsName, credentialsName: this.credentialsName,
propagate: this.propagate,
}); });
this.$router.push(`/@${this.$user().username}`); this.$router.push(`/@${this.$user().username}`);
} finally { } finally {
@ -365,7 +385,13 @@
await this.$confirm(); await this.$confirm();
this.words = [...defaultWords]; this.words = [...defaultWords];
} },
propagateChanged(field, checked) {
this.propagate = this.propagate.filter(f => f !== field);
if (checked) {
this.propagate.push(field);
}
},
}, },
computed: { computed: {
mainPronoun() { mainPronoun() {

View File

@ -200,6 +200,62 @@ router.post('/profile/save', handleErrorAsync(async (req, res) => {
)`); )`);
} }
if ((req.body.propagate || []).includes('teamName')) {
await req.db.get(SQL`UPDATE profiles
SET teamName = ${req.isGranted() ? req.body.teamName || null : ''}
WHERE userId = ${req.user.id} AND teamName != '' AND teamName IS NOT NULL;
`);
}
if ((req.body.propagate || []).includes('footerName')) {
await req.db.get(SQL`UPDATE profiles
SET footerName = ${req.isGranted() ? req.body.footerName || null : ''}
WHERE userId = ${req.user.id} AND footerName != '' AND footerName IS NOT NULL;
`);
}
if ((req.body.propagate || []).includes('names')) {
await req.db.get(SQL`UPDATE profiles
SET names = ${JSON.stringify(req.body.names)}
WHERE userId = ${req.user.id};
`);
}
if ((req.body.propagate || []).includes('flags')) {
await req.db.get(SQL`UPDATE profiles
SET flags = ${JSON.stringify(req.body.flags)}
WHERE userId = ${req.user.id};
`);
}
if ((req.body.propagate || []).includes('customFlags')) {
await req.db.get(SQL`UPDATE profiles
customFlags = ${JSON.stringify(req.body.customFlags)}
WHERE userId = ${req.user.id};
`);
}
if ((req.body.propagate || []).includes('links')) {
await req.db.get(SQL`UPDATE profiles
SET links = ${JSON.stringify(req.body.links.filter(x => !!x))}
WHERE userId = ${req.user.id};
`);
}
if ((req.body.propagate || []).includes('links')) {
await req.db.get(SQL`UPDATE profiles
SET links = ${JSON.stringify(req.body.links.filter(x => !!x))}
WHERE userId = ${req.user.id};
`);
}
if ((req.body.propagate || []).includes('birthday')) {
await req.db.get(SQL`UPDATE profiles
SET birthday = ${sanitiseBirthday(req.body.birthday || null)}
WHERE userId = ${req.user.id};
`);
}
const sus = [...isSuspicious(req.body)]; const sus = [...isSuspicious(req.body)];
if (sus.length && !await hasAutomatedReports(req.db, req.user.id)) { if (sus.length && !await hasAutomatedReports(req.db, req.user.id)) {
await req.db.get(SQL` await req.db.get(SQL`