Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linagora/esn-frontend-calendar#611 move events between calendars #618

Merged
merged 2 commits into from
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -368,7 +372,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 @@ -393,6 +397,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 @@ -402,6 +410,7 @@ function CalEventFormController(
{ graceperiod: true, notifyFullcalendar: $state.is('calendar.main') }
);
})
.then(canPerformCalendarMove)
.then(onEventCreateUpdateResponse)
.finally(function() {
$scope.restActive = false;
Expand Down Expand Up @@ -668,4 +677,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');
});
});
});
});