parent
f2ffb52318
commit
d56d9f8b08
|
@ -1,6 +1,6 @@
|
|||
/* SOGoComponentOccurence.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2008-2014 Inverse inc.
|
||||
* Copyright (C) 2008-2016 Inverse inc.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -211,6 +211,13 @@
|
|||
return [container saveComponent: newObject];
|
||||
}
|
||||
|
||||
- (NSException *) saveComponent: (iCalRepeatableEntityObject *) newObject
|
||||
force: (BOOL) forceSave
|
||||
{
|
||||
return [container saveComponent: newObject
|
||||
force: forceSave];
|
||||
}
|
||||
|
||||
#warning most of SOGoCalendarComponent and SOGoComponentOccurence share the same external interface... \
|
||||
they should be siblings or SOGoComponentOccurence the parent class of SOGoCalendarComponent...
|
||||
- (NSException *) changeParticipationStatus: (NSString *) newStatus
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NSObject+Values.h>
|
||||
|
||||
|
@ -68,6 +69,7 @@
|
|||
SOGoAppointmentFolder *targetCalendar, *sourceCalendar;
|
||||
SOGoAppointmentFolders *folders;
|
||||
BOOL forceSave;
|
||||
id error;
|
||||
|
||||
rq = [context request];
|
||||
params = [[rq contentAsString] objectFromJSONString];
|
||||
|
@ -76,7 +78,7 @@
|
|||
startDelta = [params objectForKey: @"start"];
|
||||
durationDelta = [params objectForKey: @"duration"];
|
||||
destionationCalendar = [params objectForKey: @"destination"];
|
||||
forceSave = NO;
|
||||
forceSave = [[params objectForKey: @"ignoreConflicts"] boolValue];
|
||||
|
||||
if (daysDelta || startDelta || durationDelta)
|
||||
{
|
||||
|
@ -150,8 +152,11 @@
|
|||
if ([ex respondsToSelector: @selector(httpStatus)])
|
||||
httpStatus = [ex httpStatus];
|
||||
|
||||
error = [[ex reason] objectFromJSONString];
|
||||
if (error == nil)
|
||||
error = [ex reason];
|
||||
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[ex reason], @"message",
|
||||
error, @"message",
|
||||
nil];
|
||||
|
||||
response = [self responseWithStatus: httpStatus
|
||||
|
|
|
@ -467,6 +467,7 @@
|
|||
SOGoAppointmentObject *co;
|
||||
SoSecurityManager *sm;
|
||||
WORequest *request;
|
||||
id error;
|
||||
|
||||
unsigned int httpStatus;
|
||||
BOOL forceSave;
|
||||
|
@ -490,7 +491,7 @@
|
|||
else
|
||||
{
|
||||
[self setAttributes: params];
|
||||
forceSave = NO;
|
||||
forceSave = [[params objectForKey: @"ignoreConflicts"] boolValue];
|
||||
|
||||
if ([event hasRecurrenceRules])
|
||||
[self _adjustRecurrentRules];
|
||||
|
@ -546,9 +547,11 @@
|
|||
if ([ex respondsToSelector: @selector(httpStatus)])
|
||||
httpStatus = [ex httpStatus];
|
||||
|
||||
error = [[ex reason] objectFromJSONString];
|
||||
if (error == nil)
|
||||
error = [ex reason];
|
||||
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[ex reason], @"message",
|
||||
nil];
|
||||
error, @"message", nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -275,7 +275,7 @@
|
|||
</div>
|
||||
</md-dialog-content>
|
||||
<!-- cancel/reset/save -->
|
||||
<md-dialog-actions>
|
||||
<md-dialog-actions ng-hide="editor.attendeeConflictError">
|
||||
<md-button type="button" ng-click="editor.cancel()">
|
||||
<var:string label:value="Cancel"/>
|
||||
</md-button>
|
||||
|
@ -287,6 +287,48 @@
|
|||
<var:string label:value="Save"/>
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
|
||||
<!-- attendee availability conflict -->
|
||||
<md-dialog-actions class="md-default-theme md-bg md-warn"
|
||||
ng-show="editor.attendeeConflictError">
|
||||
<div class="md-flex"><var:string label:value="A time conflict exists with one or more attendees.\nWould you like to keep the current settings anyway?"/></div>
|
||||
<md-button class="md-icon-button" ng-click="editor.attendeeConflictError = false">
|
||||
<md-icon label:aria-label="Close">close</md-icon>
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
<md-dialog-actions class="md-default-theme md-bg md-warn"
|
||||
ng-show="editor.attendeeConflictError">
|
||||
<div class="md-flex">
|
||||
<md-icon>person</md-icon> {{editor.attendeeConflictError.attendee_name}} ({{editor.attendeeConflictError.attendee_email}})
|
||||
</div>
|
||||
</md-dialog-actions>
|
||||
<md-dialog-actions class="md-default-theme md-bg md-warn"
|
||||
ng-show="editor.attendeeConflictError"
|
||||
ng-repeat="conflict in editor.attendeeConflictError.conflicts">
|
||||
<md-icon>schedule</md-icon>
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label"><var:string label:value="From"/></label>
|
||||
<div>{{conflict.startDate}} <md-icon>trending_flat</md-icon></div>
|
||||
</div>
|
||||
<div class="pseudo-input-container md-flex">
|
||||
<label class="pseudo-input-label"><var:string label:value="To"/></label>
|
||||
<div>{{conflict.endDate}}</div>
|
||||
</div>
|
||||
</md-dialog-actions>
|
||||
<md-dialog-actions ng-show="editor.attendeeConflictError">
|
||||
<md-button type="button" ng-click="editor.cancel()">
|
||||
<var:string label:value="Cancel"/>
|
||||
</md-button>
|
||||
<md-button type="button"
|
||||
ng-click="editor.attendeeConflictError = false">
|
||||
<var:string label:value="Edit"/>
|
||||
</md-button>
|
||||
<md-button class="md-warn" type="button"
|
||||
ng-click="editor.save(eventForm, { ignoreConflicts: true })"
|
||||
ng-disabled="editor.eventForm.$invalid">
|
||||
<var:string label:value="Save"/>
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
</form>
|
||||
</md-dialog>
|
||||
</container>
|
||||
|
|
|
@ -737,4 +737,39 @@
|
|||
</md-dialog>
|
||||
</script>
|
||||
|
||||
<!-- modal for attendee availability conflict -->
|
||||
<script type="text/ng-template" id="UIxAttendeeConflictDialog">
|
||||
<md-dialog flex="60" flex-xs="100">
|
||||
<md-dialog-content class="md-dialog-content">
|
||||
<h2 class="md-title">Warning</h2>
|
||||
<p><var:string label:value="A time conflict exists with one or more attendees.\nWould you like to keep the current settings anyway?"/></p>
|
||||
<md-list>
|
||||
<md-list-item>
|
||||
<md-icon>person</md-icon> {{$AttendeeConflictDialogController.conflictError.attendee_name}} ({{$AttendeeConflictDialogController.conflictError.attendee_email}})
|
||||
</md-list-item>
|
||||
<md-list-item ng-repeat="conflict in $AttendeeConflictDialogController.conflictError.conflicts">
|
||||
<md-icon>schedule</md-icon>
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label"><var:string label:value="From"/></label>
|
||||
<div>{{conflict.startDate}}</div>
|
||||
</div>
|
||||
<div class="pseudo-input-container md-flex">
|
||||
<label class="pseudo-input-label"><var:string label:value="To"/></label>
|
||||
<div>{{conflict.endDate}}</div>
|
||||
</div>
|
||||
</md-list-item>
|
||||
</md-list>
|
||||
</md-dialog-content>
|
||||
<md-dialog-actions>
|
||||
<md-button type="button" ng-click="$AttendeeConflictDialogController.cancel()">
|
||||
<var:string label:value="Cancel"/>
|
||||
</md-button>
|
||||
<md-button class="md-warn" type="button"
|
||||
ng-click="$AttendeeConflictDialogController.save()">
|
||||
<var:string label:value="Save"/>
|
||||
</md-button>
|
||||
</md-dialog-actions>
|
||||
</md-dialog>
|
||||
</script>
|
||||
|
||||
</var:component>
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
function onHttpError(event, response) {
|
||||
var message;
|
||||
if (response.data && response.data.message)
|
||||
if (response.data && response.data.message && angular.isString(response.data.message))
|
||||
message = response.data.message;
|
||||
else if (response.status)
|
||||
message = response.statusText;
|
||||
|
@ -85,7 +85,7 @@
|
|||
position: 'top right'
|
||||
});
|
||||
else
|
||||
console.debug('untrap error');
|
||||
$log.debug('untrap error');
|
||||
}
|
||||
|
||||
// Listen to HTTP errors broadcasted from HTTP interceptor
|
||||
|
|
|
@ -162,8 +162,7 @@
|
|||
component.setDelta(coordinates.duration * 15);
|
||||
newComponent(null, component).finally(function() {
|
||||
$timeout(function() {
|
||||
Component.$ghost.pointerHandler = null;
|
||||
Component.$ghost.component = null;
|
||||
Component.$resetGhost();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -186,8 +185,11 @@
|
|||
// Immediately perform the adjustments
|
||||
component.$adjust(params).then(function() {
|
||||
$rootScope.$emit('calendars:list');
|
||||
}, function(response) {
|
||||
onComponentAdjustError(response, component, params);
|
||||
}).finally(function() {
|
||||
$timeout(function() {
|
||||
Component.$ghost = {};
|
||||
Component.$resetGhost();
|
||||
});
|
||||
});
|
||||
else if (component.occurrenceId) {
|
||||
|
@ -199,7 +201,7 @@
|
|||
params: params
|
||||
},
|
||||
template: [
|
||||
'<md-dialog flex="50" md-flex="80" sm-flex="90">',
|
||||
'<md-dialog flex="50" sm-flex="80" xs-flex="90">',
|
||||
' <md-dialog-content class="md-dialog-content">',
|
||||
' <p>' + l('editRepeatingItem') + '</p>',
|
||||
' </md-dialog-content>',
|
||||
|
@ -214,7 +216,7 @@
|
|||
$rootScope.$emit('calendars:list');
|
||||
}).finally(function() {
|
||||
$timeout(function() {
|
||||
Component.$ghost = {};
|
||||
Component.$resetGhost();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -226,13 +228,58 @@
|
|||
RecurrentComponentDialogController.$inject = ['$scope', '$mdDialog', 'component', 'params'];
|
||||
function RecurrentComponentDialogController($scope, $mdDialog, component, params) {
|
||||
$scope.updateThisOccurrence = function() {
|
||||
component.$adjust(params).then($mdDialog.hide, $mdDialog.cancel);
|
||||
component.$adjust(params).then($mdDialog.hide, function(response) {
|
||||
$mdDialog.cancel().then(function() {
|
||||
onComponentAdjustError(response, component, params);
|
||||
});
|
||||
});
|
||||
};
|
||||
$scope.updateAllOccurrences = function() {
|
||||
delete component.occurrenceId;
|
||||
component.$adjust(params).then($mdDialog.hide, $mdDialog.cancel);
|
||||
component.$adjust(params).then($mdDialog.hide, function(response) {
|
||||
$mdDialog.cancel().then(function() {
|
||||
onComponentAdjustError(response, component, params);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function onComponentAdjustError(response, component, params) {
|
||||
if (response.status == 403 &&
|
||||
response.data && response.data.message && angular.isObject(response.data.message)) {
|
||||
$mdDialog.show({
|
||||
parent: angular.element(document.body),
|
||||
clickOutsideToClose: false,
|
||||
escapeToClose: false,
|
||||
templateUrl: 'UIxAttendeeConflictDialog',
|
||||
controller: AttendeeConflictDialogController,
|
||||
controllerAs: '$AttendeeConflictDialogController',
|
||||
locals: {
|
||||
component: component,
|
||||
params: params,
|
||||
conflictError: response.data.message
|
||||
}
|
||||
}).then(function() {
|
||||
$rootScope.$emit('calendars:list');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
AttendeeConflictDialogController.$inject = ['$scope', '$mdDialog', 'component', 'params', 'conflictError'];
|
||||
function AttendeeConflictDialogController($scope, $mdDialog, component, params, conflictError) {
|
||||
var vm = this;
|
||||
|
||||
vm.conflictError = conflictError;
|
||||
vm.cancel = $mdDialog.cancel;
|
||||
vm.save = save;
|
||||
|
||||
function save() {
|
||||
component.$adjust(angular.extend({ ignoreConflicts: true }, params)).then($mdDialog.hide);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function filter(filterpopup) {
|
||||
|
|
|
@ -414,6 +414,15 @@
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $resetGhost
|
||||
* @desc Prepare the ghost object for the next drag by resetting appropriate attributes
|
||||
*/
|
||||
Component.$resetGhost = function() {
|
||||
this.$ghost.pointerHandler = null;
|
||||
this.$ghost.component = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function $parseDate
|
||||
* @desc Parse a date string with format YYYY-MM-DDTHH:MM
|
||||
|
@ -1035,8 +1044,9 @@
|
|||
* @function $save
|
||||
* @memberof Component.prototype
|
||||
* @desc Save the component to the server.
|
||||
* @param {object} extraAttributes - additional attributes to send to the server
|
||||
*/
|
||||
Component.prototype.$save = function() {
|
||||
Component.prototype.$save = function(extraAttributes) {
|
||||
var _this = this, options, path, component, date, dlp;
|
||||
|
||||
component = this.$omit();
|
||||
|
@ -1106,6 +1116,8 @@
|
|||
if (this.occurrenceId)
|
||||
path.push(this.occurrenceId);
|
||||
|
||||
angular.extend(component, extraAttributes);
|
||||
|
||||
return Component.$$resource.save(path.join('/'), component, options)
|
||||
.then(function(data) {
|
||||
// Make a copy of the data for an eventual reset
|
||||
|
|
|
@ -162,6 +162,7 @@
|
|||
vm.addAttachUrl = addAttachUrl;
|
||||
vm.cancel = cancel;
|
||||
vm.save = save;
|
||||
vm.attendeeConflictError = false;
|
||||
vm.attendeesEditor = {
|
||||
days: getDays(),
|
||||
hours: getHours()
|
||||
|
@ -217,15 +218,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
function save(form) {
|
||||
function save(form, options) {
|
||||
if (form.$valid) {
|
||||
vm.component.$save()
|
||||
vm.component.$save(options)
|
||||
.then(function(data) {
|
||||
$rootScope.$emit('calendars:list');
|
||||
$mdDialog.hide();
|
||||
Alarm.getAlarms();
|
||||
}, function(data, status) {
|
||||
$log.debug('failed');
|
||||
}, function(response) {
|
||||
if (response.status == 403 &&
|
||||
response.data && response.data.message && angular.isObject(response.data.message)) {
|
||||
vm.attendeeConflictError = response.data.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue