mirror of
https://framagit.org/les/gancio.git
synced 2025-01-31 16:42:22 +01:00
refactoring media in event (multiple in db, focalpoint, alt text)
This commit is contained in:
parent
49301de42d
commit
9673e40640
13 changed files with 271 additions and 106 deletions
|
@ -1,7 +1,7 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
v-card.h-event.event.d-flex
|
v-card.h-event.event.d-flex
|
||||||
nuxt-link(:to='`/event/${event.slug || event.id}`')
|
nuxt-link(:to='`/event/${event.slug || event.id}`')
|
||||||
v-img.u-featured.img(:src="`/media/thumb/${event.image_path || 'logo.svg' }`")
|
v-img.u-featured.img(v-if='event.media' :src='thumbnail' :position='thumbnailPosition' :alt='event.media.length ? event.media[0].name : ""')
|
||||||
v-icon.float-right.mr-1(v-if='event.parentId' color='success') mdi-repeat
|
v-icon.float-right.mr-1(v-if='event.parentId' color='success') mdi-repeat
|
||||||
.title.p-name {{event.title}}
|
.title.p-name {{event.title}}
|
||||||
|
|
||||||
|
@ -52,6 +52,22 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['settings']),
|
...mapState(['settings']),
|
||||||
|
thumbnail () {
|
||||||
|
let path
|
||||||
|
if (this.event.media && this.event.media.length) {
|
||||||
|
path = this.event.media[0].url
|
||||||
|
} else {
|
||||||
|
path = 'logo.svg'
|
||||||
|
}
|
||||||
|
return '/media/thumb/' + path
|
||||||
|
},
|
||||||
|
thumbnailPosition () {
|
||||||
|
if (this.event.media && this.event.media.length && this.event.media[0].focalpoint) {
|
||||||
|
const focalpoint = this.event.media[0].focalpoint
|
||||||
|
return `${(focalpoint[0] + 1) * 50}% ${(focalpoint[1] + 1) * 50}%`
|
||||||
|
}
|
||||||
|
return 'center center'
|
||||||
|
},
|
||||||
is_mine () {
|
is_mine () {
|
||||||
if (!this.$auth.user) {
|
if (!this.$auth.user) {
|
||||||
return false
|
return false
|
||||||
|
|
97
pages/add/MediaInput.vue
Normal file
97
pages/add/MediaInput.vue
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<template lang="pug">
|
||||||
|
span
|
||||||
|
v-dialog(v-model='openMediaDetails' max-width='1000px')
|
||||||
|
v-card
|
||||||
|
v-card-title {{$t('common.media')}}
|
||||||
|
v-card-text
|
||||||
|
v-row
|
||||||
|
v-col(:span='4' :cols='4')
|
||||||
|
p Scegli il punto centrale cliccando
|
||||||
|
v-img(v-if='mediaPreview'
|
||||||
|
:src='mediaPreview'
|
||||||
|
aspect-ratio='1.7778'
|
||||||
|
:position="position")
|
||||||
|
|
||||||
|
v-textarea.mt-4(type='text'
|
||||||
|
label='Alternative text'
|
||||||
|
persistent-hint
|
||||||
|
@input='v => name=v'
|
||||||
|
:value='value.name' filled
|
||||||
|
hint='Descrizione per utenti con disabilita visive')
|
||||||
|
v-card-actions.justify-space-between
|
||||||
|
v-btn(@click='openMediaDetails=false' color='warning') Cancel
|
||||||
|
v-btn(color='primary' @click='save') Save
|
||||||
|
|
||||||
|
v-col(:span='8' :cols='8')
|
||||||
|
v-img(
|
||||||
|
v-if='mediaPreview' :src='mediaPreview'
|
||||||
|
@click='selectFocal'
|
||||||
|
max-width='88%')
|
||||||
|
|
||||||
|
h3.mb-3.font-weight-regular(v-if='mediaPreview') {{$t('common.media')}}
|
||||||
|
v-img.col-12.col-sm-2.ml-3(v-if='mediaPreview' :src='mediaPreview' aspect-ratio='1.7778' :position='position')
|
||||||
|
v-btn-toggle
|
||||||
|
v-btn(text color='primary' @click='openMediaDetails = true') {{$t('common.edit')}}
|
||||||
|
v-btn(text color='primary' @click='remove') {{$t('common.remove')}}
|
||||||
|
p {{event.media[0].name}}
|
||||||
|
v-file-input(
|
||||||
|
v-else
|
||||||
|
:label="$t('common.media')"
|
||||||
|
:hint="$t('event.media_description')"
|
||||||
|
prepend-icon="mdi-camera"
|
||||||
|
:value='value.image'
|
||||||
|
@change="v => $emit('input', { image: v, focalpoint: [0, 0] })"
|
||||||
|
persistent-hint
|
||||||
|
accept='image/*')
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MediaInput',
|
||||||
|
props: {
|
||||||
|
value: { type: Object, default: () => ({ image: null }) },
|
||||||
|
event: { type: Object, default: () => {} }
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
console.error(this.value)
|
||||||
|
return {
|
||||||
|
openMediaDetails: false,
|
||||||
|
name: this.value.name || '',
|
||||||
|
focalpoint: this.value.focalpoint || [0, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
mediaPreview () {
|
||||||
|
if (!this.value.url && !this.value.image) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const url = this.value.image ? URL.createObjectURL(this.value.image) : `/media/thumb/${this.value.url}`
|
||||||
|
return url
|
||||||
|
},
|
||||||
|
position () {
|
||||||
|
return `${(this.focalpoint[0] + 1) * 50}% ${(this.focalpoint[1] + 1) * 50}%`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
save () {
|
||||||
|
this.$emit('input', { url: this.value.url, image: this.value.image, name: this.name, focalpoint: this.focalpoint })
|
||||||
|
this.openMediaDetails = false
|
||||||
|
},
|
||||||
|
remove () {
|
||||||
|
this.$emit('remove')
|
||||||
|
},
|
||||||
|
selectFocal (ev) {
|
||||||
|
const boundingClientRect = ev.target.getBoundingClientRect()
|
||||||
|
|
||||||
|
// get relative coordinate
|
||||||
|
const x = Math.ceil(ev.clientX - boundingClientRect.left)
|
||||||
|
const y = Math.ceil(ev.clientY - boundingClientRect.top)
|
||||||
|
|
||||||
|
// map to real image coordinate
|
||||||
|
const posY = -1 + (y / boundingClientRect.height) * 2
|
||||||
|
const posX = -1 + (x / boundingClientRect.width) * 2
|
||||||
|
|
||||||
|
this.focalpoint = [posX, posY]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -45,14 +45,7 @@
|
||||||
|
|
||||||
//- MEDIA / FLYER / POSTER
|
//- MEDIA / FLYER / POSTER
|
||||||
v-col(cols=12 md=6)
|
v-col(cols=12 md=6)
|
||||||
v-file-input(
|
MediaInput(v-model='event.media[0]' :event='event' @remove='event.media=[]')
|
||||||
:label="$t('common.media')"
|
|
||||||
:hint="$t('event.media_description')"
|
|
||||||
prepend-icon="mdi-camera"
|
|
||||||
v-model='event.image'
|
|
||||||
persistent-hint
|
|
||||||
accept='image/*')
|
|
||||||
v-img.col-12.col-sm-2.ml-3(v-if='mediaPreview' :src='mediaPreview')
|
|
||||||
|
|
||||||
//- tags
|
//- tags
|
||||||
v-col(cols=12 md=6)
|
v-col(cols=12 md=6)
|
||||||
|
@ -66,7 +59,7 @@
|
||||||
v-card-actions
|
v-card-actions
|
||||||
v-spacer
|
v-spacer
|
||||||
v-btn(@click='done' :loading='loading' :disabled='!valid || loading'
|
v-btn(@click='done' :loading='loading' :disabled='!valid || loading'
|
||||||
color='primary') {{edit?$t('common.edit'):$t('common.send')}}
|
color='primary') {{edit?$t('common.save'):$t('common.send')}}
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@ -77,16 +70,17 @@ import List from '@/components/List'
|
||||||
import ImportDialog from './ImportDialog'
|
import ImportDialog from './ImportDialog'
|
||||||
import DateInput from './DateInput'
|
import DateInput from './DateInput'
|
||||||
import WhereInput from './WhereInput'
|
import WhereInput from './WhereInput'
|
||||||
|
import MediaInput from './MediaInput'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NewEvent',
|
name: 'NewEvent',
|
||||||
components: { List, Editor, ImportDialog, WhereInput, DateInput },
|
components: { List, Editor, ImportDialog, MediaInput, WhereInput, DateInput },
|
||||||
validate ({ store }) {
|
validate ({ store }) {
|
||||||
return (store.state.auth.loggedIn || store.state.settings.allow_anon_event)
|
return (store.state.auth.loggedIn || store.state.settings.allow_anon_event)
|
||||||
},
|
},
|
||||||
async asyncData ({ params, $axios, error, store }) {
|
async asyncData ({ params, $axios, error, store }) {
|
||||||
if (params.edit) {
|
if (params.edit) {
|
||||||
const data = { event: { place: {} } }
|
const data = { event: { place: {}, media: [] } }
|
||||||
data.id = params.edit
|
data.id = params.edit
|
||||||
data.edit = true
|
data.edit = true
|
||||||
let event
|
let event
|
||||||
|
@ -112,7 +106,7 @@ export default {
|
||||||
data.event.description = event.description
|
data.event.description = event.description
|
||||||
data.event.id = event.id
|
data.event.id = event.id
|
||||||
data.event.tags = event.tags
|
data.event.tags = event.tags
|
||||||
data.event.image_path = event.image_path
|
data.event.media = event.media || []
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
|
@ -128,7 +122,7 @@ export default {
|
||||||
title: '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
image: null
|
media: []
|
||||||
},
|
},
|
||||||
page: { month, year },
|
page: { month, year },
|
||||||
fileList: [],
|
fileList: [],
|
||||||
|
@ -136,7 +130,6 @@ export default {
|
||||||
date: { from: 0, due: 0, recurrent: null },
|
date: { from: 0, due: 0, recurrent: null },
|
||||||
edit: false,
|
edit: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
mediaUrl: '',
|
|
||||||
disableAddress: false
|
disableAddress: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -145,16 +138,7 @@ export default {
|
||||||
title: `${this.settings.title} - ${this.$t('common.add_event')}`
|
title: `${this.settings.title} - ${this.$t('common.add_event')}`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: mapState(['tags', 'places', 'settings']),
|
||||||
...mapState(['tags', 'places', 'settings']),
|
|
||||||
mediaPreview () {
|
|
||||||
if (!this.event.image && !this.event.image_path) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const url = this.event.image ? URL.createObjectURL(this.event.image) : `/media/thumb/${this.event.image_path}`
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['updateMeta']),
|
...mapActions(['updateMeta']),
|
||||||
eventImported (event) {
|
eventImported (event) {
|
||||||
|
@ -170,9 +154,6 @@ export default {
|
||||||
}
|
}
|
||||||
this.openImportDialog = false
|
this.openImportDialog = false
|
||||||
},
|
},
|
||||||
cleanFile () {
|
|
||||||
this.event.image = {}
|
|
||||||
},
|
|
||||||
async done () {
|
async done () {
|
||||||
if (!this.$refs.form.validate()) {
|
if (!this.$refs.form.validate()) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
@ -187,9 +168,13 @@ export default {
|
||||||
|
|
||||||
formData.append('recurrent', JSON.stringify(this.date.recurrent))
|
formData.append('recurrent', JSON.stringify(this.date.recurrent))
|
||||||
|
|
||||||
if (this.event.image) {
|
if (this.event.media.length) {
|
||||||
formData.append('image', this.event.image)
|
formData.append('image', this.event.media[0].image)
|
||||||
|
formData.append('image_url', this.event.media[0].url)
|
||||||
|
formData.append('image_name', this.event.media[0].name)
|
||||||
|
formData.append('image_focalpoint', this.event.media[0].focalpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.append('title', this.event.title)
|
formData.append('title', this.event.title)
|
||||||
formData.append('place_name', this.event.place.name)
|
formData.append('place_name', this.event.place.name)
|
||||||
formData.append('place_address', this.event.place.address)
|
formData.append('place_address', this.event.place.address)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
nuxt-link.embed_event(:to='`/event/${event.slug || event.id}`' target='_blank' :class='{ withImg: event.image_path }')
|
nuxt-link.embed_event(:to='`/event/${event.slug || event.id}`' target='_blank' :class='{ withImg: event.media }')
|
||||||
|
|
||||||
//- image
|
//- image
|
||||||
img.float-left(:src='`/media/thumb/${event.image_path || "logo.png"}`')
|
img.float-left(:src='event | mediaURL("thumb")')
|
||||||
.event-info
|
.event-info
|
||||||
//- title
|
//- title
|
||||||
.date {{event|when}}<br/>
|
.date {{event|when}}<br/>
|
||||||
|
|
|
@ -11,13 +11,14 @@ v-container#event.pa-0.pa-sm-2
|
||||||
v-row
|
v-row
|
||||||
v-col.col-12.col-lg-8
|
v-col.col-12.col-lg-8
|
||||||
//- fake image to use u-featured in h-event microformat
|
//- fake image to use u-featured in h-event microformat
|
||||||
img.u-featured(v-show='false' v-if='event.image_path' :src='`${settings.baseurl}${imgPath}`')
|
img.u-featured(v-show='false' v-if='event.media' :src='event | mediaURL')
|
||||||
v-img.main_image.mb-3(
|
v-img.main_image.mb-3(
|
||||||
contain
|
contain
|
||||||
:src='imgPath'
|
:alt='event | mediaURL("alt")'
|
||||||
:lazy-src='thumbImgPath'
|
:src='event | mediaURL'
|
||||||
v-if='event.image_path')
|
:lazy-src='event | mediaURL("thumb")'
|
||||||
.p-description.text-body-1.pa-3.grey.darken-4.rounded(v-else v-html='event.description')
|
v-if='event.media && event.media.length')
|
||||||
|
.p-description.text-body-1.pa-3.grey.darken-4.rounded(v-if='!event.media && event.description' v-html='event.description')
|
||||||
|
|
||||||
v-col.col-12.col-lg-4
|
v-col.col-12.col-lg-4
|
||||||
v-card
|
v-card
|
||||||
|
@ -60,7 +61,7 @@ v-container#event.pa-0.pa-sm-2
|
||||||
:href='`/api/event/${event.slug || event.id}.ics`')
|
:href='`/api/event/${event.slug || event.id}.ics`')
|
||||||
v-icon mdi-calendar-export
|
v-icon mdi-calendar-export
|
||||||
|
|
||||||
.p-description.text-body-1.pa-3.grey.darken-4.rounded(v-if='event.image_path && event.description' v-html='event.description')
|
.p-description.text-body-1.pa-3.grey.darken-4.rounded(v-if='event.media && event.description' v-html='event.description')
|
||||||
|
|
||||||
//- resources from fediverse
|
//- resources from fediverse
|
||||||
#resources.mt-1(v-if='settings.enable_federation')
|
#resources.mt-1(v-if='settings.enable_federation')
|
||||||
|
@ -197,7 +198,7 @@ export default {
|
||||||
{ property: 'og:type', content: 'event' },
|
{ property: 'og:type', content: 'event' },
|
||||||
{
|
{
|
||||||
property: 'og:image',
|
property: 'og:image',
|
||||||
content: this.thumbImgPath
|
content: this.$options.filters.mediaURL(this.event)
|
||||||
},
|
},
|
||||||
{ property: 'og:site_name', content: this.settings.title },
|
{ property: 'og:site_name', content: this.settings.title },
|
||||||
{
|
{
|
||||||
|
@ -213,7 +214,7 @@ export default {
|
||||||
{ property: 'twitter:title', content: this.event.title },
|
{ property: 'twitter:title', content: this.event.title },
|
||||||
{
|
{
|
||||||
property: 'twitter:image',
|
property: 'twitter:image',
|
||||||
content: this.thumbImgPath
|
content: this.$options.filters.mediaURL(this.event, 'thumb')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
property: 'twitter:description',
|
property: 'twitter:description',
|
||||||
|
@ -221,7 +222,7 @@ export default {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
link: [
|
link: [
|
||||||
{ rel: 'image_src', href: this.thumbImgPath },
|
{ rel: 'image_src', href: this.$options.filters.mediaURL(this.event, 'thumb') },
|
||||||
{
|
{
|
||||||
rel: 'alternate',
|
rel: 'alternate',
|
||||||
type: 'application/rss+xml',
|
type: 'application/rss+xml',
|
||||||
|
@ -241,12 +242,6 @@ export default {
|
||||||
currentAttachmentLabel () {
|
currentAttachmentLabel () {
|
||||||
return get(this.selectedResource, `data.attachment[${this.currentAttachment}].name`, '')
|
return get(this.selectedResource, `data.attachment[${this.currentAttachment}].name`, '')
|
||||||
},
|
},
|
||||||
imgPath () {
|
|
||||||
return '/media/' + this.event.image_path
|
|
||||||
},
|
|
||||||
thumbImgPath () {
|
|
||||||
return this.settings.baseurl + '/media/thumb/' + this.event.image_path
|
|
||||||
},
|
|
||||||
is_mine () {
|
is_mine () {
|
||||||
if (!this.$auth.user) {
|
if (!this.$auth.user) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -184,7 +184,7 @@ export default {
|
||||||
// Message({ message: this.$t('email_notification_activated'), showClose: true, type: 'success' })
|
// Message({ message: this.$t('email_notification_activated'), showClose: true, type: 'success' })
|
||||||
},
|
},
|
||||||
imgPath (event) {
|
imgPath (event) {
|
||||||
return event.image_path && event.image_path
|
return event.media && event.media[0].url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,18 @@ export default ({ app, store }) => {
|
||||||
|
|
||||||
// shown in mobile homepage
|
// shown in mobile homepage
|
||||||
Vue.filter('day', value => dayjs.unix(value).locale(store.state.locale).format('dddd, D MMM'))
|
Vue.filter('day', value => dayjs.unix(value).locale(store.state.locale).format('dddd, D MMM'))
|
||||||
|
Vue.filter('mediaURL', (event, type) => {
|
||||||
|
if (event.media && event.media.length) {
|
||||||
|
if (type === 'alt') {
|
||||||
|
return event.media[0].name
|
||||||
|
} else {
|
||||||
|
return store.state.settings.baseurl + '/media/' + (type === 'thumb' ? 'thumb/' : '') + event.media[0].url
|
||||||
|
}
|
||||||
|
} else if (type !== 'alt') {
|
||||||
|
return store.state.settings.baseurl + '/media/' + (type === 'thumb' ? 'thumb/' : '') + 'logo.svg'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
Vue.filter('from', timestamp => dayjs.unix(timestamp).fromNow())
|
Vue.filter('from', timestamp => dayjs.unix(timestamp).fromNow())
|
||||||
|
|
||||||
|
|
|
@ -289,10 +289,21 @@ const eventController = {
|
||||||
is_visible: !!req.user
|
is_visible: !!req.user
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.file) {
|
if (req.file || body.image_url) {
|
||||||
eventDetails.image_path = req.file.filename
|
let url
|
||||||
} else if (body.image_url) {
|
if (req.file) {
|
||||||
eventDetails.image_path = await helpers.getImageFromURL(body.image_url)
|
url = req.file.filename
|
||||||
|
} else {
|
||||||
|
url = await helpers.getImageFromURL(body.image_url)
|
||||||
|
}
|
||||||
|
|
||||||
|
const focalpoint = body.image_focalpoint ? body.image_focalpoint.split(',') : [0, 0]
|
||||||
|
|
||||||
|
eventDetails.media = [{
|
||||||
|
url,
|
||||||
|
name: body.image_name || '',
|
||||||
|
focalpoint: [parseFloat(focalpoint[0]), parseFloat(focalpoint[1].toFixed(2))]
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = await Event.create(eventDetails)
|
const event = await Event.create(eventDetails)
|
||||||
|
@ -343,28 +354,29 @@ const eventController = {
|
||||||
if (req.err) {
|
if (req.err) {
|
||||||
return res.status(400).json(req.err.toString())
|
return res.status(400).json(req.err.toString())
|
||||||
}
|
}
|
||||||
const body = req.body
|
|
||||||
const event = await Event.findByPk(body.id)
|
|
||||||
if (!event) { return res.sendStatus(404) }
|
|
||||||
if (!req.user.is_admin && event.userId !== req.user.id) {
|
|
||||||
return res.sendStatus(403)
|
|
||||||
}
|
|
||||||
|
|
||||||
const recurrent = body.recurrent ? JSON.parse(body.recurrent) : null
|
try {
|
||||||
const eventDetails = {
|
const body = req.body
|
||||||
title: body.title,
|
const event = await Event.findByPk(body.id)
|
||||||
// remove html tags
|
if (!event) { return res.sendStatus(404) }
|
||||||
description: helpers.sanitizeHTML(linkifyHtml(body.description, { target: '_blank' })),
|
if (!req.user.is_admin && event.userId !== req.user.id) {
|
||||||
multidate: body.multidate,
|
return res.sendStatus(403)
|
||||||
start_datetime: body.start_datetime,
|
}
|
||||||
end_datetime: body.end_datetime,
|
|
||||||
recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.file) {
|
const recurrent = body.recurrent ? JSON.parse(body.recurrent) : null
|
||||||
if (event.image_path && !event.recurrent) {
|
const eventDetails = {
|
||||||
const old_path = path.resolve(config.upload_path, event.image_path)
|
title: body.title,
|
||||||
const old_thumb_path = path.resolve(config.upload_path, 'thumb', event.image_path)
|
// remove html tags
|
||||||
|
description: helpers.sanitizeHTML(linkifyHtml(body.description, { target: '_blank' })),
|
||||||
|
multidate: body.multidate,
|
||||||
|
start_datetime: body.start_datetime,
|
||||||
|
end_datetime: body.end_datetime,
|
||||||
|
recurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((req.file || /^https?:\/\//.test(body.image_url)) && !event.recurrent && event.media.length) {
|
||||||
|
const old_path = path.resolve(config.upload_path, event.media[0].url)
|
||||||
|
const old_thumb_path = path.resolve(config.upload_path, 'thumb', event.media[0].url)
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(old_path)
|
fs.unlinkSync(old_path)
|
||||||
fs.unlinkSync(old_thumb_path)
|
fs.unlinkSync(old_thumb_path)
|
||||||
|
@ -372,34 +384,55 @@ const eventController = {
|
||||||
log.info(e.toString())
|
log.info(e.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eventDetails.image_path = req.file.filename
|
let url
|
||||||
} else if (body.image_url) {
|
if (req.file) {
|
||||||
eventDetails.image_path = await helpers.getImageFromURL(body.image_url)
|
url = req.file.filename
|
||||||
}
|
} else if (body.image_url) {
|
||||||
|
if (/^https?:\/\//.test(body.image_url)) {
|
||||||
|
url = await helpers.getImageFromURL(body.image_url)
|
||||||
|
} else {
|
||||||
|
url = body.image_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await event.update(eventDetails)
|
if (body.image_focalpoint) {
|
||||||
const [place] = await Place.findOrCreate({
|
const focalpoint = body.image_focalpoint ? body.image_focalpoint.split(',') : [0, 0]
|
||||||
where: { name: body.place_name },
|
eventDetails.media = [{
|
||||||
defaults: { address: body.place_address }
|
url,
|
||||||
})
|
name: body.image_name || '',
|
||||||
|
focalpoint: [parseFloat(focalpoint[0].slice(0, 6)), parseFloat(focalpoint[1].slice(0, 6))]
|
||||||
|
}]
|
||||||
|
} else {
|
||||||
|
eventDetails.media = []
|
||||||
|
}
|
||||||
|
|
||||||
await event.setPlace(place)
|
await event.update(eventDetails)
|
||||||
await event.setTags([])
|
const [place] = await Place.findOrCreate({
|
||||||
if (body.tags) {
|
where: { name: body.place_name },
|
||||||
await Tag.bulkCreate(body.tags.map(t => ({ tag: t })), { ignoreDuplicates: true })
|
defaults: { address: body.place_address }
|
||||||
const tags = await Tag.findAll({ where: { tag: { [Op.in]: body.tags } } })
|
})
|
||||||
await event.addTags(tags)
|
|
||||||
}
|
|
||||||
const newEvent = await Event.findByPk(event.id, { include: [Tag, Place] })
|
|
||||||
res.json(newEvent)
|
|
||||||
|
|
||||||
// create recurrent instances of event if needed
|
await event.setPlace(place)
|
||||||
// without waiting for the task manager
|
await event.setTags([])
|
||||||
if (event.recurrent) {
|
if (body.tags) {
|
||||||
eventController._createRecurrent()
|
await Tag.bulkCreate(body.tags.map(t => ({ tag: t })), { ignoreDuplicates: true })
|
||||||
} else {
|
const tags = await Tag.findAll({ where: { tag: { [Op.in]: body.tags } } })
|
||||||
const notifier = require('../../notifier')
|
await event.addTags(tags)
|
||||||
notifier.notifyEvent('Update', event.id)
|
}
|
||||||
|
const newEvent = await Event.findByPk(event.id, { include: [Tag, Place] })
|
||||||
|
res.json(newEvent)
|
||||||
|
|
||||||
|
// create recurrent instances of event if needed
|
||||||
|
// without waiting for the task manager
|
||||||
|
if (event.recurrent) {
|
||||||
|
eventController._createRecurrent()
|
||||||
|
} else {
|
||||||
|
const notifier = require('../../notifier')
|
||||||
|
notifier.notifyEvent('Update', event.id)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log.error('[EVENT UPDATE]', e)
|
||||||
|
res.sendStatus(400)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -407,9 +440,9 @@ const eventController = {
|
||||||
const event = await Event.findByPk(req.params.id)
|
const event = await Event.findByPk(req.params.id)
|
||||||
// check if event is mine (or user is admin)
|
// check if event is mine (or user is admin)
|
||||||
if (event && (req.user.is_admin || req.user.id === event.userId)) {
|
if (event && (req.user.is_admin || req.user.id === event.userId)) {
|
||||||
if (event.image_path && !event.recurrent) {
|
if (event.media && event.media.length && !event.recurrent) {
|
||||||
const old_path = path.join(config.upload_path, event.image_path)
|
const old_path = path.join(config.upload_path, event.media[0].url)
|
||||||
const old_thumb_path = path.join(config.upload_path, 'thumb', event.image_path)
|
const old_thumb_path = path.join(config.upload_path, 'thumb', event.media[0].url)
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(old_thumb_path)
|
fs.unlinkSync(old_thumb_path)
|
||||||
fs.unlinkSync(old_path)
|
fs.unlinkSync(old_path)
|
||||||
|
@ -504,6 +537,7 @@ const eventController = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure we have the next instance of a recurrent event
|
* Ensure we have the next instance of a recurrent event
|
||||||
|
* TODO: create a future instance if the next one is skipped
|
||||||
*/
|
*/
|
||||||
_createRecurrentOccurrence (e) {
|
_createRecurrentOccurrence (e) {
|
||||||
log.debug(`Create recurrent event [${e.id}] ${e.title}"`)
|
log.debug(`Create recurrent event [${e.id}] ${e.title}"`)
|
||||||
|
@ -511,7 +545,7 @@ const eventController = {
|
||||||
parentId: e.id,
|
parentId: e.id,
|
||||||
title: e.title,
|
title: e.title,
|
||||||
description: e.description,
|
description: e.description,
|
||||||
image_path: e.image_path,
|
media: e.media,
|
||||||
is_visible: true,
|
is_visible: true,
|
||||||
userId: e.userId,
|
userId: e.userId,
|
||||||
placeId: e.placeId
|
placeId: e.placeId
|
||||||
|
|
|
@ -44,6 +44,7 @@ Event.init({
|
||||||
index: true
|
index: true
|
||||||
},
|
},
|
||||||
image_path: DataTypes.STRING,
|
image_path: DataTypes.STRING,
|
||||||
|
media: DataTypes.JSON,
|
||||||
is_visible: DataTypes.BOOLEAN,
|
is_visible: DataTypes.BOOLEAN,
|
||||||
recurrent: DataTypes.JSON,
|
recurrent: DataTypes.JSON,
|
||||||
likes: { type: DataTypes.JSON, defaultValue: [] },
|
likes: { type: DataTypes.JSON, defaultValue: [] },
|
||||||
|
|
|
@ -4,9 +4,9 @@ block content
|
||||||
p 📍 Dove: #{event.place.name} - #{event.place.address}
|
p 📍 Dove: #{event.place.name} - #{event.place.address}
|
||||||
p ⏰ Quando: #{datetime(event.start_datetime)}
|
p ⏰ Quando: #{datetime(event.start_datetime)}
|
||||||
br
|
br
|
||||||
if event.image_path
|
if event.media
|
||||||
<center>
|
<center>
|
||||||
<img style="height: 89vh; margin: 0 auto;" src="#{config.baseurl}/media/#{event.image_path}" />
|
<img style="height: 89vh; margin: 0 auto;" alt="#{event.media[0].name}" src="#{config.baseurl}/media/#{event.media[0].url}" />
|
||||||
</center>
|
</center>
|
||||||
p !{event.description}
|
p !{event.description}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ module.exports = {
|
||||||
start_datetime: dayjs(get(props, 'start[0]', '')).unix(),
|
start_datetime: dayjs(get(props, 'start[0]', '')).unix(),
|
||||||
end_datetime: dayjs(get(props, 'end[0]', '')).unix(),
|
end_datetime: dayjs(get(props, 'end[0]', '')).unix(),
|
||||||
tags: get(props, 'category', []),
|
tags: get(props, 'category', []),
|
||||||
image_path: get(props, 'featured[0]')
|
media: { url: get(props, 'featured[0]') }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res.json(events)
|
return res.json(events)
|
||||||
|
|
25
server/migrations/20210705183419-add_event_media.js
Normal file
25
server/migrations/20210705183419-add_event_media.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
up: async (queryInterface, Sequelize) => {
|
||||||
|
return Promise.all(
|
||||||
|
[
|
||||||
|
await queryInterface.addColumn('events', 'media', { type: Sequelize.JSON }),
|
||||||
|
await queryInterface.sequelize.query("UPDATE events set media=JSON('[{ \"url\": \"' || image_path || '\" }]')")
|
||||||
|
])
|
||||||
|
/**
|
||||||
|
* Add altering commands here.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* await queryInterface.createTable('users', { id: Sequelize.INTEGER });
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
|
||||||
|
down: async (queryInterface, Sequelize) => {
|
||||||
|
/**
|
||||||
|
* Add reverting commands here.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* await queryInterface.dropTable('users');
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,8 @@ rss(version='2.0' xmlns:atom="http://www.w3.org/2005/Atom")
|
||||||
| <h4>#{event.title}</h4>
|
| <h4>#{event.title}</h4>
|
||||||
| <strong>#{event.place.name} - #{event.place.address}</strong>
|
| <strong>#{event.place.name} - #{event.place.address}</strong>
|
||||||
| <small>(#{moment.unix(event.start_datetime).format("dddd, D MMMM HH:mm")})</small><br/>
|
| <small>(#{moment.unix(event.start_datetime).format("dddd, D MMMM HH:mm")})</small><br/>
|
||||||
if (event.image_path)
|
if (event.media)
|
||||||
| <img src="#{settings.baseurl}/media/#{event.image_path}"/>
|
| <img alt="#{event.media[0].name}" src="#{settings.baseurl}/media/#{event.media[0].url}"/>
|
||||||
| <pre>!{event.description}</pre>
|
| <pre>!{event.description}</pre>
|
||||||
| ]]>
|
| ]]>
|
||||||
pubDate= new Date(event.updatedAt).toUTCString()
|
pubDate= new Date(event.updatedAt).toUTCString()
|
||||||
|
|
Loading…
Reference in a new issue