validators as a plugin

This commit is contained in:
les 2020-09-05 01:21:47 +02:00
parent a0c462a3f7
commit f28347a227
17 changed files with 88 additions and 160 deletions

View file

@ -1,10 +1,19 @@
<template lang='pug'>
v-card
p(v-html="$t('event.follow_me_description', { title: settings.title, account: `@${settings.instance_name}@${domain}`})")
v-text-field(v-model='instance_hostname' ref='instance')
a(slot='append' :href='link' target='_blank')
v-btn(:disabled='(!couldGo || !proceed)' plain type="primary") {{$t("common.follow")}}
p.mt-2 <img class='instance_thumb' :src="instance.thumbnail"/> {{instance.title}}
v-card-title(v-text="$t('common.follow_me_title')")
v-card-text
p(v-html="$t('event.follow_me_description', { title: settings.title, account: `@${settings.instance_name}@${domain}`})")
v-text-field(
:rules='[$validators.required()]'
:label="$t('common.url')"
v-model='instance_hostname')
p <img class='instance_thumb' :src="instance.thumbnail"/> {{instance.title}}
v-card-actions
//- a(slot='append' :href='link' target='_blank')
v-spacer
v-btn(:disabled='(!couldGo || !proceed)'
:loading='loading'
color="primary") {{$t("common.follow")}}
</template>
<script>
import { mapState } from 'vuex'
@ -18,6 +27,7 @@ export default {
instance_hostname: '',
proceed: false,
instance: {},
loading: false,
get_instance_info: debounce(this.getInstanceInfo, 500)
}
},
@ -29,7 +39,6 @@ export default {
return URL.hostname
},
couldGo () {
console.error(this.instance_hostname)
// check if is mastodon
this.get_instance_info()
return true

View file

@ -19,8 +19,8 @@ export default {
return {
icon: 'md-alert',
color: 'primary',
bottom: false,
top: true,
bottom: true,
top: false,
left: false,
right: false,
active: false,

View file

@ -23,7 +23,7 @@
//- div.mt-4 {{$t('admin.instance_name')}}
v-text-field.mt-5(v-model='instance_name'
:label="$t('admin.instance_name')"
:hint="`${$t('admin.instance_name_help')} (@${instance_name}@${settings.baseurl|url2host})`"
:hint="`${$t('admin.instance_name_help')} ${instance_ap_url}`"
placeholder='Instance name' persistent-hint
@blur='save("instance_name", instance_name)')
@ -47,7 +47,7 @@
v-form(v-model='valid')
v-text-field.mt-4(v-model='instance_url'
persistent-hint
:rules="[validators.required('email')]"
:rules="[$validators.required()]"
:hint="$t('admin.add_trusted_instance')"
:label="$t('common.url')")
v-card-actions
@ -68,14 +68,12 @@
</template>
<script>
import { mapActions, mapState } from 'vuex'
import { validators } from '../../plugins/helpers'
import axios from 'axios'
export default {
name: 'Federation',
data ({ $store, $options }) {
return {
validators,
instance_url: '',
instance_name: $store.state.settings.instance_name,
instance_place: $store.state.settings.instance_place,
@ -107,6 +105,10 @@ export default {
enable_trusted_instances: {
get () { return this.settings.enable_trusted_instances },
set (value) { this.setSetting({ key: 'enable_trusted_instances', value }) }
},
instance_ap_url () {
const instance_url = this.settings.baseurl.match(/^https?:\/\/(.[^/:]+)/i)[1]
return `(@${this.instance_name}@${instance_url})`
}
},
methods: {

View file

@ -38,11 +38,11 @@
v-card-text
v-form(v-model='valid' ref='linkModalForm')
v-text-field(v-model='link.label'
:rules="[validators.required('label')]"
:rules="[$validators.required('label')]"
label='Label')
v-text-field(v-model='link.href'
:rules="[validators.required('href')]"
label='Href')
:rules="[$validators.required($t('common.url'))]"
:label="$t('common.url')")
v-card-actions
v-spacer
v-btn(link @click='linkModal=false' color='error') {{$t('common.cancel')}}
@ -67,13 +67,11 @@
</template>
<script>
import { mapActions, mapState } from 'vuex'
import { validators } from '../../plugins/helpers'
export default {
name: 'Theme',
data () {
return {
validators,
valid: false,
logoKey: 0,
link: { href: '', label: '' },

View file

@ -17,7 +17,7 @@
v-form
v-text-field(v-model='new_user.email'
:label="$t('common.email')"
:rules="[validators.required('email')]")
:rules="[$validators.required('email')]")
v-switch(v-model='new_user.is_admin' :label="$t('common.admin')" inset)
v-alert(type='info' :closable='false') {{$t('admin.user_add_help')}}
v-card-actions
@ -42,7 +42,6 @@
</template>
<script>
import { mapState } from 'vuex'
import { validators } from '../../plugins/helpers'
export default {
name: 'Users',
@ -51,7 +50,6 @@ export default {
},
data () {
return {
validators,
newUserDialog: false,
new_user: {
email: '',

View file

@ -228,6 +228,10 @@
"5": "quinto",
"-1": "ultimo"
},
"validators": {
"required": "Campo {fieldName} necessario",
"email": "Inserisci una email valida"
},
"about": "\n <p>\n <a href='https://gancio.org'>Gancio</a> e' un progetto dell'<a href='https://autistici.org/underscore'>underscore hacklab</a> e uno dei\n servizi di <a href='https://cisti.org'>cisti.org</a>.</p>\n\n <h5> Cos'è gancio?</h5>\n <p>Uno strumento di condivisione di eventi per comunità radicali.\n Dentro gancio puoi trovare e inserire eventi.\n Gancio, come tutto <a href='https://cisti.org'>cisti.org</a> è uno strumento\n antisessista, antirazzista, antifascista e anticapitalista, riflettici quando\n pubblichi un evento.</p>\n \n <h5>Ok, ma cosa vuol dire gancio?</h5>\n <p>\n Se vieni a Torino e dici: \"ehi, ci diamo un gancio alle 8?\" nessuno si presenterà con i guantoni per fare a mazzate.\n Darsi un gancio vuol dire beccarsi alle ore X in un posto Y.</p>\n <code>\n <ul>\n <li> a che ora è il gancio in radio per andare al presidio?</li>\n <li> non so ma domani non posso venire, ho gia' un gancio per caricare il bar.</li>\n </ul>\n </code>\n\n <h5> Contatti</h5>\n <p>\n Hai scritto una nuova interfaccia per gancio? Vuoi aprire un nuovo nodo di gancio nella tua città?\n C'è qualcosa che vorresti migliorare? Per contribuire i sorgenti sono liberi e disponibili \n <a href='https://framagit.org/les/gancio'>qui</a>. Aiuti e suggerimenti sono sempre benvenuti, puoi scriverci\n su underscore chicciola autistici.org</p>\n ",
"oauth": {
"authorization_request": "L'applicazione esterna <code>{app}</code> richiede l'autorizzazione a svolgere le sequenti attività su <code>{instance_name}</code>:",

View file

@ -41,6 +41,7 @@ module.exports = {
'@/plugins/filters', // text filters, datetime filters, generic transformation helpers etc.
'@/plugins/vue-clipboard', // vuetify
'@/plugins/axios', // axios baseurl configuration
'@/plugins/validators', // inject validators
{ src: '@/plugins/v-calendar', ssr: false } // calendar, fix ssr
],

View file

@ -9,12 +9,12 @@
v-card-text
v-form(v-model='valid' ref='form')
v-text-field(v-model='email' type='email'
:rules='validators.email' autofocus
:rules='$validators.email' autofocus
:placeholder='$t("common.email")'
ref='email')
v-text-field(v-model='password'
:rules='validators.password'
:rules='$validators.password'
type='password'
:placeholder='$t("common.password")')
@ -41,13 +41,11 @@
<script>
import { mapState } from 'vuex'
import { validators } from '../plugins/helpers'
export default {
name: 'Login',
data () {
return {
validators,
password: '',
email: '',
loading: false,

View file

@ -11,15 +11,15 @@
v-form(ref='form' v-model='valid')
v-text-field(ref='email'
v-model='user.email' type='email'
:rules="validators.email"
:rules="$validators.email"
:label='$t("common.email")' autocomplete='email')
v-text-field(v-model='user.password' type="password"
:rules="validators.password"
:rules="$validators.password"
:label="$t('common.password')")
v-textarea(v-model='user.description'
:rules="[validators.required('description')]"
:rules="[$validators.required($t('common.description'))]"
:label="$t('common.description')")
v-card-actions
@ -33,13 +33,11 @@
<script>
import { mapState } from 'vuex'
import get from 'lodash/get'
import { validators } from '../plugins/helpers'
export default {
name: 'Register',
data () {
return {
validators,
loading: false,
user: {},
valid: true

View file

@ -5,7 +5,7 @@
v-card-text(v-if='$auth.user && $auth.user.is_admin')
Editor(v-model='about')
v-card-text(v-else v-html='about')
v-card-actions
v-card-actions(v-if='$auth.user && $auth.user.is_admin')
v-spacer
v-btn(color='primary' plain
@click='save') {{$t('common.save')}}

View file

@ -65,7 +65,7 @@
v-btn(type='text' @click='showFollowMe=true') {{$t('event.interact_with_me')}}
span(v-if='settings.enable_resources && event.resources.length') - {{$tc('common.n_resources', event.resources.length)}}
v-dialog(v-model='showFollowMe' destroy-on-close)
v-dialog(v-model='showFollowMe' destroy-on-close max-width='500px')
h4(slot='title') {{$t('common.follow_me_title')}}
FollowMe
@ -77,21 +77,30 @@
v-carousel(:interval='10000' ref='carousel' arrow='always')
v-carousel-item(v-for='attachment in selectedResource.data.attachment' :key='attachment.url')
v-img(:src='attachment.url')
v-card.mb-1(v-if='settings.enable_resources' v-for='resource in event.resources' :key='resource.id' :class='{disabled: resource.hidden}')
span
v-dropdown.mr-2(v-if='$auth.user && $auth.user.is_admin')
v-btn(circle icon='el-icon-more' size='mini')
v-menu(slot='dropdown')
el-dropdown-item(v-if='!resource.hidden' icon='el-icon-remove' @click.native='hideResource(resource, true)') {{$t('admin.hide_resource')}}
el-dropdown-item(v-else icon='el-icon-success' @click.native='hideResource(resource, false)') {{$t('admin.show_resource')}}
el-dropdown-item(icon='el-icon-delete' @click.native='deleteResource(resource)') {{$t('admin.delete_resource')}}
el-dropdown-item(icon='el-icon-lock' @click.native='blockUser(resource)') {{$t('admin.block_user')}}
a(:href='resource.data.url || resource.data.context')
small {{resource.data.published|dateFormat('ddd, D MMMM HH:mm')}}
v-list.mb-1(v-if='settings.enable_resources' v-for='resource in event.resources' dark
:key='resource.id' :class='{disabled: resource.hidden}')
v-list-item
v-list-title
v-menu(v-if='$auth.user && $auth.user.is_admin' offset-y)
template(v-slot:activator="{ on, attrs }")
v-btn.mr-2(v-on='on' v-attrs='attrs' color='primary' small icon outlined)
v-icon mdi-dots-vertical
v-list
v-list-item(v-if='!resource.hidden' @click='hideResource(resource, true)')
v-list-item-title <v-icon left>mdi-eye-off</v-icon> {{$t('admin.hide_resource')}}
v-list-item(v-else @click='hideResource(resource, false)')
v-list-item-title <v-icon left>mdi-eye-on</v-icon> {{$t('admin.show_resource')}}
v-list-item(@click='deleteResource(resource)')
v-list-item-title <v-icon left>mdi-delete</v-icon> {{$t('admin.delete_resource')}}
v-list-item(@click='blockUser(resource)')
v-list-item-title <v-icon left>mdi-lock</v-icon> {{$t('admin.block_user')}}
div.mt-1(v-html='resource_filter(resource.data.content)')
span.previewImage(@click='showResource(resource)')
img(v-for='img in resource.data.attachment' :src='img.url')
a(:href='resource.data.url || resource.data.context')
small {{resource.data.published|dateFormat('ddd, D MMMM HH:mm')}}
div.mt-1(v-html='resource_filter(resource.data.content)')
span.previewImage(@click='showResource(resource)')
img(v-for='img in resource.data.attachment' :src='img.url')
</template>
<script>
@ -228,56 +237,20 @@ export default {
this.selectedResource = resource
document.getElementById('resourceDialog').focus()
},
async remove () {
try {
await this.$root.$confirm(this.$t('event.remove_confirmation'), this.$t('common.confirm'), {
confirmButtonText: this.$t('common.ok'),
cancelButtonText: this.$t('common.cancel'),
type: 'error'
})
await this.$axios.delete(`/user/event/${this.event.id}`)
this.delEvent(Number(this.event.id))
this.$router.replace('/')
} catch (e) {
console.error(e)
}
},
async toggle () {
try {
if (this.event.is_visible) {
await this.$axios.$get(`/event/unconfirm/${this.event.id}`)
this.event.is_visible = false
} else {
await this.$axios.$get(`/event/confirm/${this.event.id}`)
this.event.is_visible = true
}
} catch (e) {
console.error(e)
}
},
async hideResource (resource, hidden) {
await this.$axios.$put(`/resources/${resource.id}`, { hidden })
resource.hidden = hidden
},
async blockUser (resource) {
try {
await this.$root.$confirm(this.$t('admin.user_block_confirm'), {
confirmButtonText: this.$t('common.ok'),
cancelButtonText: this.$t('common.cancel'),
type: 'error'
})
await this.$root.$confirm(this.$t('admin.user_block_confirm'))
await this.$axios.post('/instances/toggle_user_block', { ap_id: resource.ap_user.ap_id })
this.$root.$message({ message: this.$t('admin.user_blocked', { user: resource.ap_user.ap_id }), type: 'success' })
} catch (e) { }
},
async deleteResource (resource) {
try {
await this.$root.$confirm(this.$t('admin.delete_resource_confirm'),
this.$t('common.confirm'), {
confirmButtonText: this.$t('common.ok'),
cancelButtonText: this.$t('common.cancel'),
type: 'error'
})
await this.$root.$confirm(this.$t('admin.delete_resource_confirm'))
await this.$axios.delete(`/resources/${resource.id}`)
this.event.resources = this.event.resources.filter(r => r.id !== resource.id)
} catch (e) { }

View file

@ -29,9 +29,7 @@ export default {
methods: {
...mapActions(['delEvent']),
async remove (parent = false) {
const ret = await this.$root.$confirm(this.$t(`event.remove_${parent ? 'recurrent_' : ''}confirmation`), this.$t('common.confirm'), {
type: 'error'
})
const ret = await this.$root.$confirm(this.$t('common.confirm'), this.$t(`event.remove_${parent ? 'recurrent_' : ''}confirmation`))
if (!ret) { return }
const id = parent ? this.event.parentId : this.event.id
await this.$axios.delete(`/event/${id}`)

View file

@ -3,23 +3,20 @@
v-col(cols='12' md="6" lg="5" xl="4")
v-card
v-card-title {{settings.title}} - {{$t('common.recover_password')}}
//- nuxt-link(to='/')
//- v-img(src='/logo.png')
//- span {{settings.title}} - {{$t('common.recover_password')}}
v-card-text
div(v-if='valid')
v-text-field(type='password'
:rules="validators.password"
:rules="$validators.password"
autofocus :placeholder='$t("common.new_password")'
v-model='new_password')
div(v-else) {{$t('recover.not_valid_code')}}
v-card-actions
v-spacer
v-btn(v-if='valid' color='primary' @click='change_password') {{$t('common.send')}}
</template>
<script>
import { mapState } from 'vuex'
import { validators } from '../../plugins/helpers'
export default {
name: 'Recover',
@ -34,7 +31,7 @@ export default {
}
},
data () {
return { new_password: '', validators }
return { new_password: '' }
},
computed: mapState(['settings']),
methods: {

View file

@ -15,7 +15,6 @@
</template>
<script>
import { validators } from '../../plugins/helpers'
export default {
name: 'Recover',
@ -29,7 +28,7 @@ export default {
}
},
data () {
return { validators, new_password: '' }
return { new_password: '' }
},
methods: {
async change_password () {

View file

@ -1,13 +0,0 @@
const linkify = require('linkifyjs')
export const validators = {
required (fieldName) {
return value => !!value || `validators.required.${fieldName}`
},
email: [
v => !!v || 'validators.required.email',
v => (v && !!linkify.test(v, 'email')) || 'validators.valid.email'
],
password: [
v => !!v || 'validators.required.password'
]
}

19
plugins/validators.js Normal file
View file

@ -0,0 +1,19 @@
const linkify = require('linkifyjs')
export default ({ app }, inject) => {
const $t = app.i18n.t.bind(app.i18n)
const validators = {
required (fieldName) {
return value => !!value || $t('validators.required', { fieldName })
},
email: [
v => !!v || $t('validators.required', { fieldName: $t('common.email') }),
v => (v && !!linkify.test(v, 'email')) || $t('validators.email')
],
password: [
v => !!v || $t('validators.required', { fieldName: $t('common.password') })
]
}
inject('validators', validators)
}

View file

@ -1,59 +1,6 @@
import Vue from 'vue'
// https://fontawesome.com/icons?d=gallery
// //
// import 'vue-awesome/icons/lock'
// import 'vue-awesome/icons/user'
// import 'vue-awesome/icons/plus'
// import 'vue-awesome/icons/cog'
// import 'vue-awesome/icons/tools'
// import 'vue-awesome/icons/file-export'
// import 'vue-awesome/icons/sign-out-alt'
// import 'vue-awesome/icons/clock'
// import 'vue-awesome/icons/map-marker-alt'
// import 'vue-awesome/icons/file-alt'
// import 'vue-awesome/icons/image'
// import 'vue-awesome/icons/tag'
// import 'vue-awesome/icons/users'
// import 'vue-awesome/icons/calendar'
// import 'vue-awesome/icons/edit'
// import 'vue-awesome/icons/envelope-open-text'
// import 'vue-awesome/icons/user-secret'
// import 'vue-awesome/icons/question-circle'
// import 'vue-awesome/icons/share'
// import 'vue-awesome/icons/comment'
// import 'vue-awesome/icons/comments'
// import 'vue-awesome/icons/tags'
// import 'vue-awesome/icons/chevron-right'
// import 'vue-awesome/icons/chevron-left'
// import 'vue-awesome/icons/search'
// import 'vue-awesome/icons/times'
// import 'vue-awesome/icons/envelope'
// import 'vue-awesome/icons/calendar-day'
// import 'vue-awesome/icons/calendar-week'
// import 'vue-awesome/icons/calendar-alt'
// import 'vue-awesome/icons/network-wired'
// import 'vue-awesome/icons/rss'
// import 'vue-awesome/icons/bold'
// import 'vue-awesome/icons/italic'
// import 'vue-awesome/icons/strikethrough'
// import 'vue-awesome/icons/quote-right'
// import 'vue-awesome/icons/underline'
// import 'vue-awesome/icons/code'
// import 'vue-awesome/icons/paragraph'
// import 'vue-awesome/icons/list-ul'
// import 'vue-awesome/icons/list-ol'
// import 'vue-awesome/icons/heading'
// import 'vue-awesome/icons/link'
// import 'vue-awesome/icons/hands-helping'
// import 'vue-awesome/icons/question'
// import 'vue-awesome/icons/vector-square'
// import 'vue-awesome/icons/bullhorn'
// import Icon from 'vue-awesome/components/Icon'
import VueClipboard from 'vue-clipboard2'
export default () => {
// Vue.component('v-icon', Icon)
Vue.use(VueClipboard)
}