diff --git a/components/admin/Cohorts.vue b/components/admin/Collections.vue
similarity index 73%
rename from components/admin/Cohorts.vue
rename to components/admin/Collections.vue
index 81b8f7ec..ea577484 100644
--- a/components/admin/Cohorts.vue
+++ b/components/admin/Collections.vue
@@ -1,41 +1,41 @@
v-container
- v-card-title {{$t('common.blobs')}}
+ v-card-title {{$t('common.collections')}}
v-spacer
v-text-field(v-model='search'
:append-icon='mdiMagnify' outlined rounded
label='Search'
single-line hide-details)
- v-card-subtitle(v-html="$t('admin.blobs_description')")
+ v-card-subtitle(v-html="$t('admin.collections_description')")
- v-btn(color='primary' text @click='newCohort') {{$t('admin.new_blob')}}
+ v-btn(color='primary' text @click='newCollection') {{$t('admin.new_collection')}}
v-dialog(v-model='dialog' width='800' destroy-on-close :fullscreen='$vuetify.breakpoint.xsOnly')
v-card(color='secondary')
- v-card-title {{$t('admin.edit_blob')}}
+ v-card-title {{$t('admin.edit_collection')}}
v-card-text
v-form(v-model='valid' ref='form')
v-text-field(
- v-if='!cohort.id'
+ v-if='!collection.id'
:rules="[$validators.required('common.name')]"
:label="$t('common.name')"
- v-model='cohort.name'
+ v-model='collection.name'
:placeholder='$t("common.name")')
- template(v-slot:append-outer v-if='!cohort.id')
- v-btn(text @click='saveCohort' color='primary' :loading='loading'
- :disabled='!valid || loading || !!cohort.id') {{$t('common.save')}}
- h3(v-else class='text-h5' v-text='cohort.name')
+ template(v-slot:append-outer v-if='!collection.id')
+ v-btn(text @click='saveCollection' color='primary' :loading='loading'
+ :disabled='!valid || loading || !!collection.id') {{$t('common.save')}}
+ h3(v-else class='text-h5' v-text='collection.name')
v-row
v-col(cols=5)
v-autocomplete(v-model='filterTags'
cache-items
:prepend-icon="mdiTagMultiple"
-
chips small-chips multiple deletable-chips hide-no-data hide-selected persistent-hint
- :disabled="!cohort.id"
+ :disabled="!collection.id"
placeholder='Tutte'
@input.native='searchTags'
+ @focus='searchTags'
:delimiters="[',', ';']"
:items="tags"
:label="$t('common.tags')")
@@ -52,7 +52,7 @@ v-container
clearable
return-object
item-text='name'
- :disabled="!cohort.id"
+ :disabled="!collection.id"
@input.native="searchPlaces"
:delimiters="[',', ';']"
:items="places"
@@ -68,7 +68,7 @@ v-container
//- v-list-item-subtitle(v-text='item.address')
v-col(cols=2)
- v-btn(color='primary' text @click='addFilter' :disabled='!cohort.id || !filterPlaces.length && !filterTags.length') add
+ v-btn(color='primary' text @click='addFilter' :disabled='!collection.id || !filterPlaces.length && !filterTags.length') add
v-data-table(
@@ -91,17 +91,17 @@ v-container
v-card-text
v-data-table(
- :headers='cohortHeaders'
- :items='cohorts'
- :hide-default-footer='cohorts.length<5'
+ :headers='collectionHeaders'
+ :items='collections'
+ :hide-default-footer='collections.length<5'
:footer-props='{ prevIcon: mdiChevronLeft, nextIcon: mdiChevronRight }'
:search='search')
template(v-slot:item.filters='{item}')
- span {{cohortFilters(item)}}
+ span {{collectionFilters(item)}}
template(v-slot:item.actions='{item}')
- v-btn(@click='editCohort(item)' color='primary' icon)
+ v-btn(@click='editCollection(item)' color='primary' icon)
v-icon(v-text='mdiPencil')
- v-btn(@click='removeCohort(item)' color='error' icon)
+ v-btn(@click='removeCollection(item)' color='error' icon)
v-icon(v-text='mdiDeleteForever')
@@ -118,16 +118,16 @@ export default {
dialog: false,
valid: false,
search: '',
- cohort: { name: '', id: null },
+ collection: { name: '', id: null },
filterTags: [],
filterPlaces: [],
tags: [],
places: [],
- cohorts: [],
+ collections: [],
filters: [],
tagName: '',
placeName: '',
- cohortHeaders: [
+ collectionHeaders: [
{ value: 'name', text: 'Name' },
{ value: 'filters', text: 'Filters' },
{ value: 'actions', text: 'Actions', align: 'right' }
@@ -140,7 +140,7 @@ export default {
}
},
async fetch () {
- this.cohorts = await this.$axios.$get('/cohorts?withFilters=true')
+ this.collections = await this.$axios.$get('/collections?withFilters=true')
},
methods: {
@@ -150,8 +150,8 @@ export default {
searchPlaces: debounce(async function (ev) {
this.places = await this.$axios.$get(`/place?search=${ev.target.value}`)
}, 100),
- cohortFilters (cohort) {
- return cohort.filters.map(f => {
+ collectionFilters (collection) {
+ return collection.filters.map(f => {
return '(' + f.tags?.join(', ') + f.places?.map(p => p.name).join(', ') + ')'
}).join(' - ')
},
@@ -159,28 +159,28 @@ export default {
this.loading = true
const tags = this.filterTags
const places = this.filterPlaces.map(p => ({ id: p.id, name: p.name }))
- const filter = await this.$axios.$post('/filter', { cohortId: this.cohort.id, tags, places })
+ const filter = await this.$axios.$post('/filter', { collectionId: this.collection.id, tags, places })
this.$fetch()
this.filters.push(filter)
this.filterTags = []
this.filterPlaces = []
this.loading = false
},
- async editCohort (cohort) {
- this.cohort = { ...cohort }
- this.filters = await this.$axios.$get(`/filter/${cohort.id}`)
+ async editCollection (collection) {
+ this.collection = { ...collection }
+ this.filters = await this.$axios.$get(`/filter/${collection.id}`)
this.dialog = true
},
- newCohort () {
- this.cohort = { name: '', id: null }
+ newCollection () {
+ this.collection = { name: '', id: null }
this.filters = []
this.dialog = true
},
- async saveCohort () {
+ async saveCollection () {
if (!this.$refs.form.validate()) return
this.loading = true
- this.cohort.name = this.cohort.name.trim()
- this.cohort = await this.$axios.$post('/cohorts', this.cohort)
+ this.collection.name = this.collection.name.trim()
+ this.collection = await this.$axios.$post('/collections', this.collection)
this.$fetch()
this.loading = false
},
@@ -195,12 +195,12 @@ export default {
this.loading = false
}
},
- async removeCohort (cohort) {
- const ret = await this.$root.$confirm('admin.delete_cohort_confirm', { cohort: cohort.name })
+ async removeCollection (collection) {
+ const ret = await this.$root.$confirm('admin.delete_collection_confirm', { collection: collection.name })
if (!ret) { return }
try {
- await this.$axios.$delete(`/cohort/${cohort.id}`)
- this.cohorts = this.cohorts.filter(c => c.id !== cohort.id)
+ await this.$axios.$delete(`/collection/${collection.id}`)
+ this.collections = this.collections.filter(c => c.id !== collection.id)
} catch (e) {
const err = get(e, 'response.data.errors[0].message', e)
this.$root.$message(this.$t(err), { color: 'error' })
diff --git a/locales/en.json b/locales/en.json
index 6381d8bb..29228af6 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -87,7 +87,7 @@
"import": "Import",
"max_events": "N. max events",
"label": "Label",
- "blobs": "Blobs",
+ "collections": "Collections",
"close": "Close"
},
"login": {
@@ -235,9 +235,9 @@
"admin_email": "Admin e-mail",
"widget": "Widget",
"wrong_domain_warning": "The baseurl configured in config.json ({baseurl}) differs from the one you're visiting ({url})",
- "new_blob": "New blob",
- "blobs_description": "Blobs are groupings of events by tags and places. They will be displayed on the home page",
- "edit_blob": "Edit Blob"
+ "new_collection": "New collection",
+ "collections_description": "Collections are groupings of events by tags and places. They will be displayed on the home page",
+ "edit_collection": "Edit Collection"
},
"auth": {
"not_confirmed": "Not confirmed yet…",
diff --git a/locales/it.json b/locales/it.json
index 2328c0ae..84b2caf2 100644
--- a/locales/it.json
+++ b/locales/it.json
@@ -87,7 +87,7 @@
"import": "Importa",
"max_events": "N. massimo eventi",
"label": "Etichetta",
- "blobs": "Bolle"
+ "collections": "Bolle"
},
"login": {
"description": "Entrando puoi pubblicare nuovi eventi.",
@@ -232,10 +232,10 @@
"smtp_test_success": "Una mail di test è stata inviata all'indirizzo {admin_email}, controlla la tua casella di posta",
"smtp_test_button": "Invia una mail di prova",
"admin_email": "E-mail dell'admin",
- "new_blob": "Crea bolla",
+ "new_collection": "Crea bolla",
"wrong_domain_warning": "Il \"baseurl\" configurato in config.json ({baseurl}) è diverso da quello che stai visitando ({url})",
- "blobs_description": "Le bolle sono raggruppamenti di eventi per tag e posti.",
- "edit_blob": "Modifica bolla"
+ "collections_description": "Le bolle sono raggruppamenti di eventi per tag e posti.",
+ "edit_collection": "Modifica bolla"
},
"auth": {
"not_confirmed": "Non ancora confermato…",
diff --git a/pages/collection/_collection.vue b/pages/collection/_collection.vue
new file mode 100644
index 00000000..eb410bc6
--- /dev/null
+++ b/pages/collection/_collection.vue
@@ -0,0 +1,43 @@
+
+
+
+ {{collection}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/g/_cohort.vue b/pages/g/_cohort.vue
deleted file mode 100644
index fadc7b68..00000000
--- a/pages/g/_cohort.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
- {{cohort}}
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/server/api/controller/cohort.js b/server/api/controller/collection.js
similarity index 58%
rename from server/api/controller/cohort.js
rename to server/api/controller/collection.js
index 34f8ea60..a186a13c 100644
--- a/server/api/controller/cohort.js
+++ b/server/api/controller/collection.js
@@ -1,38 +1,42 @@
-const Cohort = require('../models/cohort')
+const Collection = require('../models/collection')
const Filter = require('../models/filter')
const Event = require('../models/event')
const Tag = require('../models/tag')
const Place = require('../models/place')
const log = require('../../log')
const dayjs = require('dayjs')
-
+const { col: Col } = require('../../helpers')
const { Op, Sequelize } = require('sequelize')
-const cohortController = {
+const collectionController = {
async getAll (req, res) {
const withFilters = req.query.withFilters
- let cohorts
+ let collections
if (withFilters) {
- cohorts = await Cohort.findAll({ include: [Filter] })
+ collections = await Collection.findAll({ include: [Filter] })
} else {
- cohorts = await Cohort.findAll()
+ collections = await Collection.findAll()
}
- return res.json(cohorts)
+ return res.json(collections)
},
- // return events from cohort
+ // return events from collection
async getEvents (req, res) {
+ const format = req.params.format || 'json'
const name = req.params.name
- const cohort = await Cohort.findOne({ where: { name } })
- if (!cohort) {
+ const collection = await Collection.findOne({ where: { name } })
+ if (!collection) {
return res.sendStatus(404)
}
- const filters = await Filter.findAll({ where: { cohortId: cohort.id } })
+ const filters = await Filter.findAll({ where: { collectionId: collection.id } })
+ if (!filters.length) {
+ return res.json([])
+ }
const start = dayjs().unix()
const where = {
// do not include parent recurrent event
@@ -42,24 +46,16 @@ const cohortController = {
is_visible: true,
// [Op.or]: {
- start_datetime: { [Op.gte]: start },
+ start_datetime: { [Op.gte]: start },
// end_datetime: { [Op.gte]: start }
// }
}
- // if (!show_recurrent) {
- // where.parentId = null
- // }
-
- // if (end) {
- // where.start_datetime = { [Op.lte]: end }
- // }
-
const replacements = []
const ors = []
filters.forEach(f => {
if (f.tags && f.tags.length) {
- const tags = Sequelize.fn('EXISTS', Sequelize.literal('SELECT 1 FROM event_tags WHERE "event_tags"."eventId"="event".id AND "tagTag" in (?)'))
+ const tags = Sequelize.fn('EXISTS', Sequelize.literal(`SELECT 1 FROM event_tags WHERE ${Col('event_tags.eventId')}=event.id AND ${Col('tagTag')} in (?)`))
replacements.push(f.tags)
if (f.places && f.places.length) {
ors.push({ [Op.and]: [ { placeId: f.places.map(p => p.id) },tags] })
@@ -71,21 +67,7 @@ const cohortController = {
}
})
- // if (tags && places) {
- // where[Op.or] = {
- // placeId: places ? places.split(',') : [],
- // // '$tags.tag$': Sequelize.literal(`EXISTS (SELECT 1 FROM event_tags WHERE tagTag in ( ${Sequelize.QueryInterface.escape(tags)} ) )`)
- // }
- // } else if (tags) {
- // where[Op.and] = Sequelize.literal(`EXISTS (SELECT 1 FROM event_tags WHERE event_tags.eventId=event.id AND tagTag in (?))`)
- // replacements.push(tags)
- // } else if (places) {
- // where.placeId = places.split(',')
- // }
-
- if (ors.length) {
- where[Op.or] = ors
- }
+ where[Op.and] = { [Op.or]: ors }
const events = await Event.findAll({
where,
@@ -96,7 +78,7 @@ const cohortController = {
include: [
{
model: Tag,
- order: [Sequelize.literal('(SELECT COUNT("tagTag") FROM event_tags WHERE tagTag = tag) DESC')],
+ // order: [Sequelize.literal('(SELECT COUNT("tagTag") FROM event_tags WHERE tagTag = tag) DESC')],
attributes: ['tag'],
through: { attributes: [] }
},
@@ -120,43 +102,43 @@ const cohortController = {
},
async add (req, res) {
- const cohortDetail = {
+ const collectionDetail = {
name: req.body.name,
isActor: true,
isTop: true
}
// TODO: validation
- log.info('Create cohort: ' + req.body.name)
- const cohort = await Cohort.create(cohortDetail)
- res.json(cohort)
+ log.info('Create collection: ' + req.body.name)
+ const collection = await Collection.create(collectionDetail)
+ res.json(collection)
},
async remove (req, res) {
- const cohort_id = req.params.id
- log.info('Remove cohort', cohort_id)
+ const collection_id = req.params.id
+ log.info('Remove collection', collection_id)
try {
- const cohort = await Cohort.findByPk(cohort_id)
- await cohort.destroy()
+ const collection = await Collection.findByPk(collection_id)
+ await collection.destroy()
res.sendStatus(200)
} catch (e) {
- log.error('Remove cohort failed:', e)
+ log.error('Remove collection failed:', e)
res.sendStatus(404)
}
},
async getFilters (req, res) {
- const cohortId = req.params.cohort_id
- const filters = await Filter.findAll({ where: { cohortId } })
+ const collectionId = req.params.collection_id
+ const filters = await Filter.findAll({ where: { collectionId } })
return res.json(filters)
},
async addFilter (req, res) {
- const cohortId = req.body.cohortId
+ const collectionId = req.body.collectionId
const tags = req.body.tags
const places = req.body.places
try {
- const filter = await Filter.create({ cohortId, tags, places })
+ const filter = await Filter.create({ collectionId, tags, places })
return res.json(filter)
} catch (e) {
log.error(String(e))
@@ -183,4 +165,4 @@ const cohortController = {
-module.exports = cohortController
\ No newline at end of file
+module.exports = collectionController
\ No newline at end of file
diff --git a/server/api/models/cohort.js b/server/api/models/collection.js
similarity index 72%
rename from server/api/models/cohort.js
rename to server/api/models/collection.js
index 93f7ecb2..16a38b87 100644
--- a/server/api/models/cohort.js
+++ b/server/api/models/collection.js
@@ -1,9 +1,9 @@
const { Model, DataTypes } = require('sequelize')
const sequelize = require('./index').sequelize
-class Cohort extends Model {}
+class Collection extends Model {}
-Cohort.init({
+Collection.init({
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
@@ -21,7 +21,7 @@ Cohort.init({
isTop: {
type: DataTypes.BOOLEAN
}
-}, { sequelize, modelName: 'cohort', timestamps: false })
+}, { sequelize, modelName: 'collection', timestamps: false })
-module.exports = Cohort
+module.exports = Collection
diff --git a/server/migrations/20220617203517-collection.js b/server/migrations/20220617203517-collection.js
new file mode 100644
index 00000000..5262e049
--- /dev/null
+++ b/server/migrations/20220617203517-collection.js
@@ -0,0 +1,30 @@
+'use strict';
+
+module.exports = {
+ async up (queryInterface, Sequelize) {
+ return Promise.all(
+ [
+ await queryInterface.renameTable('cohorts', 'collections'),
+ await queryInterface.renameColumn('filters', 'cohortId', 'collectionId'),
+ await queryInterface.changeColumn('filters', 'collectionId', {
+ type: Sequelize.INTEGER,
+ allowNull: true,
+ references: {
+ model: 'collections',
+ key: 'id'
+ },
+ onUpdate: 'CASCADE',
+ onDelete: 'SET NULL'
+ }),
+ ])
+ },
+
+ async down (queryInterface, Sequelize) {
+ /**
+ * Add reverting commands here.
+ *
+ * Example:
+ * await queryInterface.dropTable('users');
+ */
+ }
+};