Skip to content

Commit

Permalink
fix(events): fix save and publish
Browse files Browse the repository at this point in the history
publish must run only after locking otherwise
it won't persist changes to event state

SDESK-1620
  • Loading branch information
petrjasek committed Jul 28, 2017
1 parent 8d0dde7 commit 5cc0eab
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 83 deletions.
82 changes: 33 additions & 49 deletions client/actions/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { SubmissionError, getFormInitialValues } from 'redux-form'
import { saveLocation as _saveLocation } from './index'
import { showModal, fetchSelectedAgendaPlannings } from './index'
import { EventUpdateMethods } from '../components/fields'
import { PRIVILEGES, EVENTS, ITEM_STATE } from '../constants'
import { checkPermission, getErrorMessage, retryDispatch } from '../utils'
import { EVENTS, ITEM_STATE } from '../constants'
import { getErrorMessage, retryDispatch } from '../utils'

import eventsApi from './events/api'
import eventsUi from './events/ui'
Expand All @@ -25,58 +25,45 @@ const duplicateEvent = (event) => (
}
)

const _setEventStatus = ({ eventId, status }) => (
(dispatch, getState) => {
// clone event in order to not modify the store
const event = { ...selectors.getEvents(getState())[eventId] }
event.pubstatus = status
return dispatch(saveEvent(event))
.then((events) => {
dispatch(eventsUi.previewEvent(events[0]))
return events
})
}
)

/**
* Set event.pubstatus usable and publish event.
*
* @param {Object} event
*/
const publishEvent = (eventId) => (
(dispatch, getState, { api, notify }) => {
dispatch(setEventStatus({
eventId,
status: EVENTS.PUB_STATUS.USABLE,
}))
.then((events) => api.save('events_publish', {
event: eventId,
etag: events[0]._etag,
}))
function publishEvent(event) {
return function (dispatch, getState, { api, notify }) {
return api.save('events_publish', {
event: event._id,
etag: event._etag,
pubstatus: EVENTS.PUB_STATUS.USABLE,
})
.then(() => {
notify.success('The event has been published')
dispatch(eventsUi.refetchEvents())
dispatch(silentlyFetchEventsById([event._id], ITEM_STATE.ALL))
dispatch(eventsUi.closeEventDetails())
})
}
)
}

/**
* Set event.pubstatus canceled and publish event.
*
* @param {Object} event
*/
const unpublishEvent = (eventId) => (
(dispatch, getState, { api, notify }) => {
dispatch(setEventStatus({
eventId,
status: EVENTS.PUB_STATUS.CANCELED,
}))
.then((events) => api.save('events_publish', {
event: eventId,
etag: events[0]._etag,
}))
function unpublishEvent(event) {
return function (dispatch, getState, { api, notify }) {
return api.save('events_publish', {
event: event._id,
etag: event._etag,
pubstatus: EVENTS.PUB_STATUS.CANCELED,
})
.then(() => {
notify.success('The event has been unpublished')
dispatch(eventsUi.refetchEvents())
dispatch(silentlyFetchEventsById([event._id], ITEM_STATE.ALL))
dispatch(eventsUi.closeEventDetails())
})
}
)
}

const toggleEventSelection = ({ event, value }) => (
{
Expand Down Expand Up @@ -105,9 +92,9 @@ const askConfirmationBeforeSavingEvent = (event, publish=false) => (
// If this is not from a recurring series, then simply save this event
if (!get(originalEvent, 'recurrence_id')) {
return dispatch(uploadFilesAndSaveEvent(event))
.then(() => {
.then((events) => {
if (publish) {
dispatch(publishEvent(event._id))
dispatch(publishEvent(events[0]))
}
})
}
Expand Down Expand Up @@ -186,7 +173,8 @@ const uploadFilesAndSaveEvent = (event) => {
.then((events) => {
if (events.length > 0 && selectors.getShowEventDetails(getState()) === true) {
dispatch(eventsUi.closeEventDetails())
dispatch(eventsUi.openEventDetails(events[0]))
return dispatch(eventsUi.openEventDetails(events[0]))
.then(() => events)
}

return events
Expand Down Expand Up @@ -288,7 +276,9 @@ const saveEvent = (newEvent) => (
newEvent = cloneDeep(newEvent) || {}

// save the timezone. This is useful for recurring events
newEvent.dates.tz = moment.tz.guess()
if (newEvent.dates) {
newEvent.dates.tz = moment.tz.guess()
}

// remove all properties starting with _,
// otherwise it will fail for "unknown field" with `_type`
Expand Down Expand Up @@ -467,12 +457,6 @@ const toggleEventsList = () => (
{ type: EVENTS.ACTIONS.TOGGLE_EVENT_LIST }
)

const setEventStatus = checkPermission(
_setEventStatus,
PRIVILEGES.EVENT_MANAGEMENT,
'Unauthorised to change the status of an event!'
)

// WebSocket Notifications
/**
* Action Event when a new Event is created
Expand Down
3 changes: 2 additions & 1 deletion client/actions/events/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const _openEventDetails = (event) => (
return dispatch(eventsApi.lock(event)).then((item) => {
dispatch(openDetails)
dispatch(eventsApi.receiveEvents([item]))
return item
}, () => {
dispatch(openDetails)
})
Expand All @@ -42,7 +43,7 @@ const _openEventDetails = (event) => (
type: EVENTS.ACTIONS.OPEN_EVENT_DETAILS,
payload: true,
})
return Promise.resolve()
return Promise.resolve(event)
}
}
)
Expand Down
8 changes: 4 additions & 4 deletions client/components/EventForm/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,14 @@ export class Component extends React.Component {
<div>
{forcedReadOnly && !isPublished && !eventSpiked &&
<button
onClick={() => publish(id)}
onClick={() => publish(initialValues)}
type="button"
className="btn btn--success">
Publish</button>
}
{isPublished &&
<button
onClick={() => unpublish(id)}
onClick={() => unpublish(initialValues)}
type="button"
className="btn btn--hollow">
Unpublish</button>
Expand Down Expand Up @@ -552,8 +552,8 @@ const mapDispatchToProps = (dispatch) => ({
onSubmit: (event) => dispatch(actions.saveEventWithConfirmation(event)),
openEventDetails: (event) => dispatch(actions.events.ui.openEventDetails(event)),
saveAndPublish: (event) => dispatch(actions.saveAndPublish(event)),
publish: (eventId) => dispatch(actions.publishEvent(eventId)),
unpublish: (eventId) => dispatch(actions.unpublishEvent(eventId)),
publish: (event) => dispatch(actions.publishEvent(event)),
unpublish: (event) => dispatch(actions.unpublishEvent(event)),
spikeEvent: (event) => dispatch(actions.events.ui.openSpikeModal(event)),
unspikeEvent: (event) => dispatch(actions.events.ui.openUnspikeModal(event)),
addEventToCurrentAgenda: (event) => dispatch(actions.addEventToCurrentAgenda(event)),
Expand Down
4 changes: 2 additions & 2 deletions server/features/events.feature
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ Feature: Events
Then we get OK response
When we post to "/events/publish"
"""
{"event": "#events._id#", "etag": "#events._etag#"}
{"event": "#events._id#", "etag": "#events._etag#", "pubstatus": "usable"}
"""
When we get "/events_history"
Then we get a list with 2 items
Expand Down Expand Up @@ -326,7 +326,7 @@ Feature: Events
Then we get OK response
When we post to "/events/publish"
"""
{"event": "#events._id#", "etag": "#events._etag#"}
{"event": "#events._id#", "etag": "#events._etag#", "pubstatus": "usable"}
"""
When we post to "/events/#events._id#/duplicate"
"""
Expand Down
2 changes: 1 addition & 1 deletion server/features/events_recurring.feature
Original file line number Diff line number Diff line change
Expand Up @@ -1466,7 +1466,7 @@ Feature: Events Recurring
Then we store "EVENT5" with 5 item
When we post to "/events/publish"
"""
{"event": "#EVENT4._id#", "etag": "#EVENT4._etag#"}
{"event": "#EVENT4._id#", "etag": "#EVENT4._etag#", "pubstatus": "usable"}
"""
Then we get OK response
When we post to "planning"
Expand Down
27 changes: 2 additions & 25 deletions server/features/publish.feature
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Feature: Publish

When we post to "/events/publish"
"""
{"event": "#events._id#", "etag": "#events._etag#"}
{"event": "#events._id#", "etag": "#events._etag#", "pubstatus": "usable"}
"""
Then we get OK response
When we get "/events/#events._id#"
Expand All @@ -70,29 +70,6 @@ Feature: Publish
{"_issues": {"event": "__any_value__"}}
"""

@auth
Scenario: Publish non usable event
When we post to "/events" with success
"""
{
"guid": "123",
"unique_id": "123",
"unique_name": "123 name",
"name": "event 123",
"slugline": "event-123",
"pubstatus": "withhold",
"dates": {
"start": "2016-01-02",
"end": "2016-01-03"
}
}
"""
When we post to "/events/publish"
"""
{"event": "#events._id#", "etag": "#events._etag#"}
"""
Then we get error 409

@auth
Scenario: Publish canceled event
When we post to "/products" with success
Expand Down Expand Up @@ -138,7 +115,7 @@ Feature: Publish

When we post to "/events/publish"
"""
{"event": "#events._id#", "etag": "#events._etag#"}
{"event": "#events._id#", "etag": "#events._etag#", "pubstatus": "canceled"}
"""
Then we get OK response

Expand Down
4 changes: 3 additions & 1 deletion server/planning/events_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class EventsPublishResource(EventsResource):
schema = {
'event': Resource.rel('events', type='string', required=True),
'etag': {'type': 'string', 'required': True},
'pubstatus': {'type': 'string', 'required': True, 'allowed': [PUB_STATUS_USABLE, PUB_STATUS_CANCELED]},
}

url = 'events/publish'
Expand All @@ -29,6 +30,7 @@ def create(self, docs):
for doc in docs:
event = get_resource_service('events').find_one(req=None, _id=doc['event'], _etag=doc['etag'])
if event:
event['pubstatus'] = doc['pubstatus']
self.validate_event(event)
self.publish_event(event)
ids.append(doc['event'])
Expand All @@ -46,7 +48,7 @@ def publish_event(self, event):
event.setdefault(config.VERSION, 1)
event.setdefault('item_id', event['_id'])
get_enqueue_service('publish').enqueue_item(event, 'event')
updates = {'state': self._get_publish_state(event)}
updates = {'state': self._get_publish_state(event), 'pubstatus': event['pubstatus']}
get_resource_service('events').update(event['_id'], updates, event)
get_resource_service('events_history')._save_history(event, updates, 'publish')

Expand Down

0 comments on commit 5cc0eab

Please sign in to comment.