Newer
Older

jackie / Andrea Ida Malkah Klaura
committed
import axios from 'axios'
import { APIError, callOrReturn, handleApiError } from '../api-helper'
import { getISODateString, has } from '@/utilities'
import { useAuthStore } from '@/stores/auth'
import { createSteeringURL } from '@/api'

jackie / Andrea Ida Malkah Klaura
committed
const cloneMinimalShowObject = function (show) {
/* returns a new minimal object from the current show object with all
properties needed for a PUT request to the /show/ endpoint */
s.name = show.name
s.slug = show.slug
s.short_description = show.short_description
s.fundingcategory = show.fundingcategory
s.type = show.type
// we do not want the arrays do be passed as references, because the
// current show object should not get modified when the update object
// gets modified, therefore we use slice to clone the arrays
s.category = show.category.slice()
s.hosts = show.hosts.slice()
s.owners = show.owners.slice()
s.language = show.language.slice()
s.topic = show.topic.slice()
s.musicfocus = show.musicfocus.slice()
return s
}
shows: [],
schedule: null,
schedules: [],
scheduleTimeslots: [],
timeslots: [],
notes: [],
types: [],
fundingcategories: [],
categories: [],
topics: [],
musicfocus: [],
languages: [],
hosts: [],
loaded: {
shows: false,
timeslots: false,
notes: false,
schedule: false,
scheduleTimeslots: false,
schedules: false,
types: false,
fundingcategories: false,
categories: false,
topics: false,
musicfocus: false,
languages: false,
hosts: false,
},
selected: {
index: 0, // index of the currently selected show in our shows array
id: 0, // actual id of the currently selected show
},
}
const getters = {
shows: (state) => state.shows,
selectedShow: (state) => state.shows[state.selected.index],
schedule: (state) => state.schedule,
schedules: (state) => state.schedules,
scheduleTimeslots: (state) => state.scheduleTimeslots,
timeslots: (state) => state.timeslots,
notes: (state) => state.notes,
types: (state) => state.types,
fundingcategories: (state) => state.fundingcategories,
categories: (state) => state.categories,
topics: (state) => state.topics,
musicfocus: (state) => state.musicfocus,
languages: (state) => state.languages,
hosts: (state) => state.hosts,
getShowByDataParam: (state) => (data) => {
let show
if (data.id !== undefined) {
show = state.shows.find((s) => s.id === data.id)
if (show === undefined) {
console.error('getShowByDataParam: ID not found in store!')
}
} else if (data.index !== undefined) {
show = state.shows[data.index]
} else {
console.error('getShowByDataParam: no ID or index was provided')
}
return show
},
getTimeslotById: (state) => (id) => {
return state.timeslots.find((s) => s.id === id)
},

jackie / Andrea Ida Malkah Klaura
committed
const mutations = {
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
loading(state, item) {
state.loaded[item] = false
},
finishLoading(state, item) {
state.loaded[item] = true
},
setShows(state, shows) {
state.shows = shows
},
addShow(state, show) {
state.shows.push(show)
state.shows.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase())
},
setSchedule(state, schedule) {
state.schedule = schedule
},
setSchedules(state, schedules) {
state.schedules = schedules
},
setScheduleTimeslots(state, slots) {
state.scheduleTimeslots = slots
},
setTimeslots(state, slots) {
state.timeslots = slots
},
setTimeslot(state, slot) {
const index = state.timeslots.findIndex((s) => s.id === slot.id)
state.timeslots.splice(index, 1, slot)
},
setNotes(state, notes) {
state.notes = notes
},
addNote(state, note) {
state.notes.push(note)
},
setNote(state, note) {
const index = state.notes.findIndex((n) => n.id === note.id)
state.notes.splice(index, 1, note)
},
setName(state, data) {
const index = state.shows.findIndex((s) => s.id === data.id)
state.shows[index].name = data.text
},
setShortDescription(state, data) {
const index = state.shows.findIndex((s) => s.id === data.id)
state.shows[index].short_description = data.text
},
setDescription(state, data) {
const index = state.shows.findIndex((s) => s.id === data.id)
state.shows[index].description = data.text
},
setActive(state, data) {
const index = state.shows.findIndex((s) => s.id === data.id)
state.shows[index].is_active = data.active
},
setProperty(state, data) {
const index = state.shows.findIndex((s) => s.id === data.id)
state.shows[index][data.property] = data.value
},
setMetaArray(state, data) {
state[data.property] = data.value
},
switchShow(state, index) {
if (state.loaded.shows) {
state.selected.index = index
state.selected.id = state.shows[index].id
}
},
switchShowById(state, id) {
if (state.loaded.shows) {
state.selected.index = state.shows.findIndex((s) => s.id === id)
state.selected.id = id
}
},

jackie / Andrea Ida Malkah Klaura
committed
const actions = {
const authStore = useAuthStore()
const user = authStore.steeringUser
let uri = createSteeringURL('shows')
// normal users should only see their own shows, only superusers see all shows
if (!authStore.isSuperuser) {
uri += '?owner=' + user.id
.then((response) => {
ctx.commit('setShows', response.data)
ctx.commit('finishLoading', 'shows')
if (data && typeof data.callback === 'function') {
data.callback()
})
.catch((error) => {
handleApiError(this, error, 'could not load shows')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
fetchSchedule(ctx, data) {
ctx.commit('loading', 'schedule')
const uri = createSteeringURL('shows', data.show, 'schedules', data.schedule)
.then((response) => {
ctx.commit('setSchedule', response.data)
ctx.commit('finishLoading', 'schedule')
if (data && typeof data.callback === 'function') {
data.callback(response)
}
})
.catch((error) => {
handleApiError(this, error, 'could not load schedule')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
fetchSchedules(ctx, data) {
ctx.commit('loading', 'schedule')
const uri = createSteeringURL('shows', data.show, 'schedules')
.then((response) => {
ctx.commit('setSchedules', response.data)
ctx.commit('finishLoading', 'schedule')
if (data && typeof data.callback === 'function') {
data.callback(response)
})
.catch((error) => {
handleApiError(this, error, 'could not load schedule')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
fetchTimeslots(ctx, data) {
if (data.schedule !== undefined) {
ctx.commit('loading', 'scheduleTimeslots')
} else {
ctx.commit('loading', 'timeslots')
}
const query = new URLSearchParams()
if (data.surrounding) {
const date = data.surrounding instanceof Date ? data.surrounding : new Date()
query.set('surrounding', getISODateString(date))
if (has(data, 'start')) query.set('start', data.start)
if (has(data, 'end')) query.set('end', data.end)
if (has(data, 'limit')) query.set('limit', data.limit)
if (has(data, 'offset')) query.set('offset', data.offset)
const uri =
data.id && data.schedule
? createSteeringURL('shows', data.id, 'schedules', data.schedule, 'timeslots', query)
: data.id
? createSteeringURL('shows', data.id, 'timeslots', query)
: createSteeringURL('timeslots', query)
.then((response) => {
if (data.schedule !== undefined) {
ctx.commit('setScheduleTimeslots', response.data)
ctx.commit('finishLoading', 'scheduleTimeslots')
if (data.limit) {
ctx.commit('setTimeslots', response.data.results)
} else {
ctx.commit('setTimeslots', response.data)
}
ctx.commit('finishLoading', 'timeslots')
if (data && typeof data.callback === 'function') {
data.callback(response)
})
.catch((error) => {
handleApiError(this, error, 'could not load timeslots')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
})
},
fetchNotes(ctx, data) {
ctx.commit('loading', 'notes')
// we only have to make an API call if there are actually any notes
// otherwise the notes are just and empty array
if (data.notes.length === 0) {
ctx.commit('setNotes', [])
ctx.commit('finishLoading', 'notes')
return
}
const uri = createSteeringURL(
'shows',
data.id,
'notes',
new URLSearchParams({ ids: data.notes.join(',') }),
)
this.$log.debug('fetchNotes: uri:', uri)
axios
.then((response) => {
ctx.commit('setNotes', response.data)
ctx.commit('finishLoading', 'notes')
if (data && typeof data.callback === 'function') {
data.callback(response)
})
.catch((error) => {
handleApiError(this, error, 'could not load notes')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
})
},
fetchMetaArray(ctx, data) {
ctx.commit('loading', data.property)
let uri = createSteeringURL(data.property)
if (data.onlyActive === true) {
uri += '?active=true'
}
axios
.then((response) => {
ctx.commit('setMetaArray', { property: data.property, value: response.data })
ctx.commit('finishLoading', data.property)
if (data && typeof data.callback === 'function') {
data.callback()
}
})
.catch((error) => {
handleApiError(this, error, 'could not load ' + data.property)
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
})
},
submitSchedule(ctx, data) {
ctx.commit('loading', 'schedules')
const uri = createSteeringURL('shows', data.showId, 'schedules')
.post(uri, data.schedule)
.then((response) => {
ctx.commit('finishLoading', 'schedules')
return callOrReturn(response, data?.callback)
})
.catch((error) => {
APIError.handle(error, 'Unable to submit schedule', data, this)
})
},
submitShow(ctx, data) {
const uri = createSteeringURL('shows')
.then((response) => {
ctx.commit('addShow', response.data)
if (data && typeof data.callback === 'function') {
data.callback(response)
}
})
.catch((error) => {
handleApiError(this, error, 'could not add new show')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
submitNote(ctx, data) {
const NON_UPDATEABLE_PROPERTIES = ['thumbnails', 'width', 'height']
let uri = createSteeringURL(
'shows',
data.id,
'schedules',
data.scheduleID,
'timeslots',
data.timeslotID,
'note',
)
if (data.update) {
uri += data.note.id + '/'
}
const method = data.update ? 'put' : 'post'
const formData = new FormData()
// We serialize the data to a FormData object, so we can send the image
// as binary blob to the Steering API.
for (const [key, value] of Object.entries(data.note)) {
// When we're updating we don't want to include some properties that cause errors.
if (data.update && NON_UPDATEABLE_PROPERTIES.includes(key)) {
continue
}
axios
.request({
url: uri,
method: method,
data: formData,
responseType: 'json', // we need this explicitly here, as it does not seem to work automagically as in GET and PUT requests
})
.then((response) => {
if (data.update) {
ctx.commit('setNote', response.data)
} else {
ctx.commit('addNote', response.data)
}
if (data && typeof data.callback === 'function') {
data.callback(response)
}
})
.catch((error) => {
const msg = data.update ? 'could not update note' : 'could not add new note'
handleApiError(this, error, msg)
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
updateShow(ctx, data) {
const uri = createSteeringURL('shows', data.id)
.then((response) => {
if (data && typeof data.callback === 'function') {
data.callback(response)
}
})
.catch((error) => {
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel(error.response)
}
})
},
updateProperty(ctx, data) {
const show = cloneMinimalShowObject(ctx.getters.getShowByDataParam(data))
show[data.property] = data.value
ctx.dispatch('updateShow', {
id: data.id,
show: show,
callback: () => {
ctx.commit('setProperty', {
id: data.id,
property: data.property,
value: data.value,
if (typeof data.callback === 'function') {
data.callback()
}
},
callbackCancel: (error) => {
if (typeof data.callbackCancel === 'function') {
data.callbackCancel(error)
}
},
})
},
updateImage(ctx, data) {
const show = ctx.getters.getShowByDataParam(data)
const uri = createSteeringURL('shows', data.id)
const formData = new FormData()
// these propoerties have to be sent always (and they must not be null)
formData.append('name', show.name)
formData.append('slug', show.slug)
formData.append('short_description', show.short_description)
formData.append('type', show.type)
formData.append('fundingcategory', show.fundingcategory)
formData.append('is_active', show.is_active)
// now we append the new logo/image file (signified by data.type)
formData.append(data.type, data.file, data.file.name)
axios
.then((response) => {
ctx.commit('setProperty', {
id: data.id,
property: data.type,
// when updating images of a show the steering API does not return
// the full URI but only the path on the server
// TODO: create an issue in steering, to create consistency
value: import.meta.env.VUE_APP_BASEURI_STEERING + response.data[data.type],
if (data && typeof data.callback === 'function') {
data.callback(response)
}
})
.catch((error) => {
handleApiError(this, error, 'could not update show ' + data.type)
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
updateTimeslot(ctx, data) {
const uri = createSteeringURL(
'shows',
data.show,
'schedules',
data.schedule,
'timeslots',
data.timeslot.id,
)
.put(uri, data.timeslot)
.then(() => {
ctx.commit('setTimeslot', data.timeslot)
if (data && typeof data.callback === 'function') {
data.callback()
}
})
.catch((error) => {
handleApiError(this, error, 'could not update timeslot')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
deleteSchedule(ctx, data) {
const uri = createSteeringURL('shows', data.show, 'schedules', data.schedule)
.then(() => {
if (data && typeof data.callback === 'function') {
data.callback()
}
})
.catch((error) => {
handleApiError(this, error, 'could not delete full schedule')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
deleteTimeslot(ctx, data) {
const uri = createSteeringURL(
'shows',
data.show,
'schedules',
data.schedule,
'timeslots',
data.timeslot,
)
.then(() => {
if (data && typeof data.callback === 'function') {
data.callback()
}
})
.catch((error) => {
handleApiError(this, error, 'could not delete single timeslot')
if (data && typeof data.callbackCancel === 'function') {
data.callbackCancel()
}
})
},
}
export default {
namespaced: true,
state,
getters,
actions,
mutations,