Skip to content

Commit

Permalink
Merge pull request #622 from rezk2ll/#611
Browse files Browse the repository at this point in the history
#611 move events between calendars #618
  • Loading branch information
renaudboyer authored Jan 10, 2022
2 parents cc8a51d + 9f8d156 commit 9f4a8a2
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ function CalEventFormController(
_.find(calendars, 'selected');
}

// when editing an event exclude delegated calendars from the possible target calendars
// that can be used to move events into
$scope.calendars = calendars.filter(calendar => calendar.isOwner(session.user._id));

return _getCalendarByUniqueId($scope.editedEvent.calendarUniqueId);
})
.then(function(selectedCalendar) {
Expand Down Expand Up @@ -372,7 +376,7 @@ function CalEventFormController(

$scope.editedEvent.attendees = getUpdatedAttendees();

if (!calEventUtils.hasAnyChange($scope.editedEvent, $scope.event)) {
if (!calEventUtils.hasAnyChange($scope.editedEvent, $scope.event) && !_calendarHasChanged()) {
_hideModal();

return;
Expand All @@ -397,6 +401,10 @@ function CalEventFormController(
.then(cacheAttendees)
.then(denormalizeAttendees)
.then(function() {
if (!calEventUtils.hasAnyChange($scope.editedEvent, $scope.event)) {
return $q.when(true);
}

return calEventService.modifyEvent(
$scope.event.path || calPathBuilder.forCalendarPath($scope.calendarHomeId, _getCalendarByUniqueId($scope.selectedCalendar.uniqueId).id),
$scope.editedEvent,
Expand All @@ -406,6 +414,7 @@ function CalEventFormController(
{ graceperiod: true, notifyFullcalendar: $state.is('calendar.main') }
);
})
.then(canPerformCalendarMove)
.then(onEventCreateUpdateResponse)
.finally(function() {
$scope.restActive = false;
Expand Down Expand Up @@ -672,4 +681,38 @@ function CalEventFormController(
placement: 'center'
});
}

/**
* Checks if an event can be moved into another calendar
*
* @param {boolean} success - true if the previous response was successful
*
* @returns {Promise}
*/
function canPerformCalendarMove(success) {
if (!success) return $q.when(false);

return _calendarHasChanged() ? changeCalendar() : $q.when();
}

/**
* moves the event to the new calendar
*
* @returns {Promise} - resolves to true if the event calendar has changed
*/
function changeCalendar() {
const destinationPath = calPathBuilder.forEventId($scope.calendarHomeId, _getCalendarByUniqueId($scope.selectedCalendar.uniqueId).id, $scope.editedEvent.uid);
const sourcePath = $scope.event.path;

return calEventService.moveEvent(sourcePath, destinationPath);
}

/**
* Checks if the selected calendar differs from the original event calendar
*
* @returns {Boolean} - true if the event calendar and the selected calendar are different
*/
function _calendarHasChanged() {
return _getCalendarByUniqueId($scope.selectedCalendar.uniqueId).id !== $scope.editedEvent.calendarId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ describe('The CalEventFormController controller', function() {
sendCounter: sinon.spy(function() {
return $q.when(true);
}),
removeEvent: sinon.stub().returns($q.when())
removeEvent: sinon.stub().returns($q.when()),
moveEvent: sinon.stub().returns($q.when(true))
};

calendarHomeId = 'calendarHomeId';
Expand Down Expand Up @@ -1223,9 +1224,6 @@ describe('The CalEventFormController controller', function() {
scope.event = {
title: 'oldtitle',
path: '/path/to/event',
rrule: {
equals: _.constant(false)
},
etag: '123123',
clone: _.constant(editedEvent)
};
Expand Down Expand Up @@ -1258,6 +1256,7 @@ describe('The CalEventFormController controller', function() {
});

calEventServiceMock.modifyEvent = sinon.stub().returns($q.when(true));
calEventServiceMock.moveEvent = sinon.stub().returns($q.when(true));
scope.modifyEvent();
scope.$digest();

Expand Down Expand Up @@ -1297,6 +1296,56 @@ describe('The CalEventFormController controller', function() {
expect(restoreSpy).to.not.have.been.called;
expect(calOpenEventFormMock).to.have.been.calledWith(sinon.match.any, scope.editedEvent);
});

it('should attempt to move the event to another calendar if the organizer changed it', function() {
const fakeEvent = {
start: start,
end: end,
title: 'oldtitle',
path: '/calendars/owner/id.json',
etag: '123123'
};

scope.event = CalendarShell.fromIncompleteShell(fakeEvent);
initController();

scope.editedEvent = CalendarShell.fromIncompleteShell({ ...fakeEvent, title: 'new title' });
scope.selectedCalendar.uniqueId = '/calendars/owner/id2.json';
scope.calendarHomeId = 'owner';

scope.modifyEvent();
scope.$digest();

expect(calEventServiceMock.moveEvent).to.have.been.calledWith(
'/calendars/owner/id.json',
`/calendars/owner/id2/${scope.editedEvent.uid}.ics`
);
});

it('should attempt to move the event to another calendar when the other fields were left intact', function() {
const fakeEvent = {
start: start,
end: end,
title: 'oldtitle',
path: '/calendars/owner/id.json',
etag: '123123'
};

scope.event = CalendarShell.fromIncompleteShell(fakeEvent);
initController();

scope.editedEvent = CalendarShell.fromIncompleteShell(fakeEvent);
scope.selectedCalendar.uniqueId = '/calendars/owner/id2.json';
scope.calendarHomeId = 'owner';

scope.modifyEvent();
scope.$digest();

expect(calEventServiceMock.moveEvent).to.have.been.calledWith(
'/calendars/owner/id.json',
`/calendars/owner/id2/${scope.editedEvent.uid}.ics`
);
});
});

describe('as an attendee', function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ form.event-form(role="form", name="form", aria-hidden="true", ng-class="{ 'reado
i.mdi.mdi-calendar-multiple
.fg-line
md-input-container(ng-click="changeBackdropZIndex()")
md-select(ng-disabled="!isNew(editedEvent) || !canModifyEvent", ng-model="selectedCalendar.uniqueId", md-container-class="cal-select-dropdown" aria-label="calendar")
md-option(ng-value="calendar.getUniqueId()" ng-repeat="calendar in calendars | filter: (isNew(editedEvent) || canModifyEvent) ? { readOnly: false } : {}")
md-select(ng-disabled="!canModifyEvent", ng-model="selectedCalendar.uniqueId", md-container-class="cal-select-dropdown" aria-label="calendar")
md-option(ng-value="calendar.getUniqueId()" ng-repeat="calendar in calendars | filter: { readOnly: false }")
cal-select-calendar-item(calendar="calendar")
cal-event-date-edition(event="editedEvent", disabled='!canModifyEvent', use-24hour-format='use24hourFormat', on-date-change='onDateChange')
cal-entities-autocomplete-input.cal-user-autocomplete-input(
Expand Down
19 changes: 18 additions & 1 deletion src/esn.calendar.libs/app/services/calendar-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ require('./http-response-handler.js');
changeParticipation: changeParticipation,
modifyPublicRights: modifyPublicRights,
exportCalendar,
getSecretAddress
getSecretAddress,
moveEvent
};

////////////
Expand Down Expand Up @@ -331,5 +332,21 @@ require('./http-response-handler.js');
return $q.reject(error);
});
}

/**
* Move an event from one calendar to another
*
* @param {String} eventPath the path of the event.
* @param {String} destinationCalendarId the calendar id
* @returns {Object} the http response.
*/
function moveEvent(originalEventPath, destinationEventPath) {
const headers = {
Destination: destinationEventPath,
Overwrite: 'F'
};

return calDavRequest('move', originalEventPath, headers);
}
}
})(angular);
18 changes: 18 additions & 0 deletions src/esn.calendar.libs/app/services/calendar-api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -688,4 +688,22 @@ describe('The calendar module apis', function() {
});
});

describe('The moveEvent request', function() {
it('should send a MOVE request with the correct headers', function() {
const originalEventPath = '/calendars/user/calendar1/event.json';
const destinationEventPath = '/calendars/user/calendar2/event.json';
const expectedHeaders = {
Destination: destinationEventPath,
Overwrite: 'F',
Authorization: 'Bearer jwt',
Accept: 'application/json, text/plain, */*'
};

this.$httpBackend.expect('MOVE', originalEventPath, null, expectedHeaders)
.respond(201, {});

this.calendarAPI.moveEvent(originalEventPath, destinationEventPath);
this.$httpBackend.flush();
});
});
});
5 changes: 5 additions & 0 deletions src/esn.calendar.libs/app/services/event-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function calEventService(
self.getEventByUID = getEventByUID;
self.getEventFromICSUrl = getEventFromICSUrl;
self.onEventCreatedOrUpdated = onEventCreatedOrUpdated;
self.moveEvent = moveEvent;

////////////

Expand Down Expand Up @@ -575,4 +576,8 @@ function calEventService(
return new CalendarShell(ICAL.Component.fromString(response.data));
});
}

function moveEvent(source, destination) {
return calendarAPI.moveEvent(source, destination);
}
}
11 changes: 11 additions & 0 deletions src/esn.calendar.libs/app/services/event-service.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2041,4 +2041,15 @@ describe('The calEventService service', function() {
self.$rootScope.$digest();
});
});

describe('the moveEvent function', function() {
it('should call the calendarAPI.moveEvent function', function() {
const spy = sinon.stub(self.calendarAPI, 'moveEvent').returns($q.when());

self.calEventService.moveEvent('/path/to/event.ics', '/path/to/new/event.ics')
.then(function() {
expect(spy).to.have.been.calledWith('/path/to/event.ics', '/path/to/new/event.ics');
});
});
});
});

0 comments on commit 9f4a8a2

Please sign in to comment.