See ChangeLog
Monotone-Parent: 6d9c30b81605764388ff5243bba7631fe98636f0 Monotone-Revision: 4c570fedd8a0bf2a5ec231caa2b981bd796da85b Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2010-01-21T20:44:17 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
63f1af3b2f
commit
bd858817c5
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2010-01-21 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/Scheduler/UIxCalListingActions.m
|
||||
(_fetchFields:ofComponentType:): added field ownerIsOrganizer which
|
||||
identifies whether or not the calendar owner is the organizer of
|
||||
the event. Also added the field erasable which identifies if the
|
||||
active user can delete objects in the current calendar.
|
||||
* UI/WebServerResources/SchedulerUI.js
|
||||
(-_deleteCalendarEventBlocks): when the organizer deletes an
|
||||
event, also delete the event in the calendars of the attendees, if
|
||||
visible. Also, don't allow to delete an event if the user can't
|
||||
erase objects in the calendar.
|
||||
(-_deleteCalendarEventCache:): new function to update the events cache.
|
||||
|
||||
2010-01-20 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentInboxFolder.m
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* UIxCalListingActions.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2006-2009 Inverse inc.
|
||||
* Copyright (C) 2006-2010 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
@ -40,6 +40,7 @@
|
|||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <SOGo/SOGoDateFormatter.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
|
@ -81,14 +82,15 @@ static NSArray *tasksFields = nil;
|
|||
@"c_enddate", @"c_location", @"c_isallday",
|
||||
@"c_classification", @"c_partmails",
|
||||
@"c_partstates", @"c_owner", @"c_iscycle", @"c_nextalarm",
|
||||
@"c_recurrence_id", @"isException", nil];
|
||||
@"c_recurrence_id", @"isException", @"editable", @"erasable",
|
||||
@"ownerIsOrganizer", nil];
|
||||
[eventsFields retain];
|
||||
}
|
||||
if (!tasksFields)
|
||||
{
|
||||
tasksFields = [NSArray arrayWithObjects: @"c_name", @"c_folder",
|
||||
@"c_status", @"c_title", @"c_enddate",
|
||||
@"c_classification", @"editable", @"c_priority", nil];
|
||||
@"c_classification", @"editable", @"erasable", @"c_priority", nil];
|
||||
[tasksFields retain];
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +314,9 @@ static NSArray *tasksFields = nil;
|
|||
NSMutableArray *infos;
|
||||
NSNull *marker;
|
||||
SOGoAppointmentFolders *clientObject;
|
||||
NSString *role;
|
||||
SOGoUser *ownerUser;
|
||||
NSString *owner, *role;
|
||||
BOOL isErasable;
|
||||
|
||||
infos = [NSMutableArray array];
|
||||
marker = [NSNull null];
|
||||
|
@ -329,7 +333,10 @@ static NSArray *tasksFields = nil;
|
|||
to: endDate
|
||||
title: title
|
||||
component: component] objectEnumerator];
|
||||
|
||||
owner = [currentFolder ownerInContext: context];
|
||||
ownerUser = [SOGoUser userWithLogin: owner];
|
||||
isErasable = ([owner isEqualToString: userLogin]
|
||||
|| [[currentFolder aclsForUser: userLogin] containsObject: SOGoRole_ObjectEraser]);
|
||||
while ((newInfo = [currentInfos nextObject]))
|
||||
{
|
||||
if ([fields containsObject: @"editable"])
|
||||
|
@ -346,7 +353,24 @@ static NSArray *tasksFields = nil;
|
|||
[newInfo setObject: [NSNumber numberWithInt: 0]
|
||||
forKey: @"editable"];
|
||||
}
|
||||
[newInfo setObject: [currentFolder nameInContainer]
|
||||
if ([fields containsObject: @"ownerIsOrganizer"])
|
||||
{
|
||||
// Identifies whether the active user is the organizer
|
||||
// of this event.
|
||||
if ([ownerUser hasEmail: [newInfo objectForKey: @"c_orgmail"]])
|
||||
[newInfo setObject: [NSNumber numberWithInt: 1]
|
||||
forKey: @"ownerIsOrganizer"];
|
||||
else
|
||||
[newInfo setObject: [NSNumber numberWithInt: 0]
|
||||
forKey: @"ownerIsOrganizer"];
|
||||
}
|
||||
if (isErasable)
|
||||
[newInfo setObject: [NSNumber numberWithInt: 1]
|
||||
forKey: @"erasable"];
|
||||
else
|
||||
[newInfo setObject: [NSNumber numberWithInt: 0]
|
||||
forKey: @"erasable"];
|
||||
[newInfo setObject: [currentFolder nameInContainer]
|
||||
forKey: @"c_folder"];
|
||||
[newInfo setObject: [currentFolder ownerInContext: context]
|
||||
forKey: @"c_owner"];
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
cycles.plist,
|
||||
);
|
||||
|
||||
factories = {
|
||||
};
|
||||
factories = {
|
||||
};
|
||||
|
||||
categories = {
|
||||
SOGoAppointmentFolders = {
|
||||
|
@ -284,7 +284,7 @@
|
|||
pageName = "UIxOccurenceDialog";
|
||||
};
|
||||
confirmDeletion = {
|
||||
protectedBy = "ModifyComponent";
|
||||
protectedBy = "Delete Object";
|
||||
pageName = "UIxOccurenceDialog";
|
||||
actionName = "confirmDeletion";
|
||||
};
|
||||
|
@ -309,7 +309,7 @@
|
|||
actionName = "save";
|
||||
};
|
||||
delete = {
|
||||
protectedBy = "Delete Objects";
|
||||
protectedBy = "Delete Object";
|
||||
pageName = "UIxOccurenceDialog";
|
||||
actionName = "delete";
|
||||
};
|
||||
|
|
|
@ -108,6 +108,7 @@ function editEvent() {
|
|||
}
|
||||
|
||||
function _batchDeleteEvents() {
|
||||
// Delete the next event from the batch
|
||||
var events = eventsToDelete.shift();
|
||||
var calendar = calendarsOfEventsToDelete.shift();
|
||||
var urlstr = (ApplicationBaseURL + calendar
|
||||
|
@ -123,6 +124,10 @@ function deleteEvent() {
|
|||
var nodes = listOfSelection.getSelectedRows();
|
||||
if (nodes.length > 0) {
|
||||
var label = "";
|
||||
if (!nodes[0].erasable) {
|
||||
window.alert(getLabel("You don't have the required privileges to perform the operation."));
|
||||
return false;
|
||||
}
|
||||
if (listOfSelection == $("tasksList"))
|
||||
label = getLabel("taskDeleteConfirmation");
|
||||
else
|
||||
|
@ -140,7 +145,6 @@ function deleteEvent() {
|
|||
}
|
||||
var sortedNodes = [];
|
||||
var calendars = [];
|
||||
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var calendar = nodes[i].calendar;
|
||||
if (!sortedNodes[calendar]) {
|
||||
|
@ -161,6 +165,10 @@ function deleteEvent() {
|
|||
}
|
||||
}
|
||||
else if (selectedCalendarCell) {
|
||||
if (!selectedCalendarCell[0].erasable) {
|
||||
window.alert(getLabel("You don't have the required privileges to perform the operation."));
|
||||
return false;
|
||||
}
|
||||
if (selectedCalendarCell[0].recurrenceTime) {
|
||||
_editRecurrenceDialog(selectedCalendarCell[0], "confirmDeletion");
|
||||
}
|
||||
|
@ -239,59 +247,146 @@ function modifyEventCallback(http) {
|
|||
}
|
||||
}
|
||||
|
||||
function _deleteCalendarEventBlocks(calendar, cname) {
|
||||
function _deleteCalendarEventBlocks(calendar, cname, occurenceTime) {
|
||||
// Delete event (or occurence) from the specified calendar
|
||||
var ownerIsOrganizer = false;
|
||||
var events = calendarEvents[calendar];
|
||||
if (events) {
|
||||
var occurences = events[cname];
|
||||
if (occurences)
|
||||
if (occurences) {
|
||||
for (var i = 0; i < occurences.length; i++) {
|
||||
var nodes = occurences[i].blocks;
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
var node = nodes[j];
|
||||
node.parentNode.removeChild(node);
|
||||
if (occurenceTime == null
|
||||
|| occurenceTime == node.recurrenceTime) {
|
||||
ownerIsOrganizer = node.ownerIsOrganizer;
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _deleteEventFromTables(basename) {
|
||||
var tables = [ $("eventsList"), $("tasksList") ];
|
||||
for (var i = 0; i < 2; i++) {
|
||||
var table = tables[i];
|
||||
if (table.tBodies)
|
||||
rows = table.tBodies[0].rows;
|
||||
else
|
||||
rows = $(table).childNodesWithTag("li");
|
||||
for (var j = rows.length; j > 0; j--) {
|
||||
var row = $(rows[j - 1]);
|
||||
var id = row.getAttribute("id");
|
||||
if (id.indexOf(basename) == 0)
|
||||
row.parentNode.removeChild(row);
|
||||
if (ownerIsOrganizer)
|
||||
// Search for the same event in other calendars (using the cache)
|
||||
// only if the delete operation is triggered from the organizer's
|
||||
// calendar.
|
||||
for (var otherCalendar in calendarEvents) {
|
||||
if (calendar != otherCalendar) {
|
||||
occurences = calendarEvents[otherCalendar][cname];
|
||||
if (occurences) {
|
||||
for (var i = 0; i < occurences.length; i++) {
|
||||
var occurence = occurences[i];
|
||||
if (occurenceTime == null || occurenceTime == occurence[14]) {
|
||||
var nodes = occurence.blocks;
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
var node = nodes[j];
|
||||
if (node.parentNode)
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _deleteEventFromTables(calendar, cname, occurenceTime) {
|
||||
var basename = "-" + cname;
|
||||
if (occurenceTime) {
|
||||
basename = basename + "-" + occurenceTime;
|
||||
}
|
||||
var occurences = calendarEvents[calendar][cname];
|
||||
if (occurences) {
|
||||
var occurence = occurences.first();
|
||||
var ownerIsOrganizer = occurence[18];
|
||||
|
||||
// Delete event from events list
|
||||
var table = $("eventsList");
|
||||
var rows = table.tBodies[0].rows;
|
||||
for (var j = rows.length; j > 0; j--) {
|
||||
var row = $(rows[j - 1]);
|
||||
var id = row.getAttribute("id");
|
||||
var pos = id.indexOf(basename);
|
||||
if (pos > 0) {
|
||||
var otherCalendar = id.substr(0, pos);
|
||||
occurences = calendarEvents[otherCalendar][cname];
|
||||
if (occurences) {
|
||||
for (var k = 0; k < occurences.length; k++) {
|
||||
var occurence = occurences[k];
|
||||
if (calendar == otherCalendar || ownerIsOrganizer) {
|
||||
// This is the specified event or the same event in another
|
||||
// calendar. In this case, remove it only if the delete
|
||||
// operation is triggered from the organizer's calendar.
|
||||
if (occurenceTime == null || occurenceTime == occurence[14]) {
|
||||
row.parentNode.removeChild(row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete task from tasks list
|
||||
var row = $(calendar + basename);
|
||||
if (row) {
|
||||
row.parentNode.removeChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
function _deleteCalendarEventCache(calendar, cname, occurenceTime) {
|
||||
var ownerIsOrganizer = false;
|
||||
var occurences = calendarEvents[calendar][cname];
|
||||
if (occurences)
|
||||
ownerIsOrganizer = occurences[0][18];
|
||||
|
||||
for (var otherCalendar in calendarEvents) {
|
||||
var occurences = calendarEvents[otherCalendar][cname];
|
||||
if (occurences) {
|
||||
var newOccurences = [];
|
||||
for (var i = 0; i < occurences.length; i++) {
|
||||
var occurence = occurences[i];
|
||||
if (calendar == otherCalendar || ownerIsOrganizer) {
|
||||
// This is the specified event or the same event in another
|
||||
// calendar. In this case, remove it only if the delete
|
||||
// operation is triggered from the organizer's calendar.
|
||||
if (occurenceTime == null) {
|
||||
delete calendarEvents[otherCalendar][cname];
|
||||
}
|
||||
else if (occurenceTime != occurence[14]) {
|
||||
// || occurenceTime == occurence[14]) {
|
||||
newOccurences.push(occurence);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (occurenceTime)
|
||||
calendarEvents[otherCalendar][cname] = newOccurences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the Ajax callback function for _batchDeleteEvents.
|
||||
*/
|
||||
function deleteEventCallback(http) {
|
||||
if (http.readyState == 4) {
|
||||
if (isHttpStatus204(http.status)) {
|
||||
var isTask = false;
|
||||
var calendar = http.callbackData.calendar;
|
||||
var events = http.callbackData.events;
|
||||
|
||||
// log("calendar: " + calendar + "\n");
|
||||
// log("events: " + events.join(", " ) + "\n");
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var cname = events[i];
|
||||
_deleteCalendarEventBlocks(calendar, cname);
|
||||
_deleteEventFromTables(calendar + "-" + cname);
|
||||
delete calendarEvents[calendar][cname];
|
||||
_deleteEventFromTables(calendar, cname);
|
||||
_deleteCalendarEventCache(calendar, cname);
|
||||
}
|
||||
|
||||
if (eventsToDelete.length)
|
||||
_batchDeleteEvents();
|
||||
else {
|
||||
else
|
||||
document.deleteEventAjaxRequest = null;
|
||||
}
|
||||
}
|
||||
else if (parseInt(http.status) == 403)
|
||||
window.alert(getLabel("You don't have the required privileges to perform the operation."));
|
||||
|
@ -470,32 +565,10 @@ function performDeleteEventCallback(http) {
|
|||
var nodes = http.callbackData.nodes;
|
||||
var cname = nodes[0].cname;
|
||||
var calendar = nodes[0].calendar;
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
var basename = calendar + "-" + cname;
|
||||
if (occurenceTime) {
|
||||
var row = $(basename + "-" + occurenceTime);
|
||||
// log("rowID: " + basename + "-" + occurenceTime);
|
||||
if (row)
|
||||
row.parentNode.removeChild(row);
|
||||
|
||||
// Update calendar events cache
|
||||
var occurences = calendarEvents[calendar][cname];
|
||||
var newOccurences = [];
|
||||
for (var i = 0; i < occurences.length; i++) {
|
||||
var occurence = occurences[i];
|
||||
if (occurence[14] != occurenceTime)
|
||||
newOccurences.push(occurence);
|
||||
}
|
||||
calendarEvents[calendar][cname] = newOccurences;
|
||||
}
|
||||
else {
|
||||
// log("basename: " + basename);
|
||||
_deleteEventFromTables(basename);
|
||||
delete calendarEvents[calendar][cname];
|
||||
}
|
||||
|
||||
_deleteCalendarEventBlocks(calendar, cname, occurenceTime);
|
||||
_deleteEventFromTables(calendar, cname, occurenceTime);
|
||||
_deleteCalendarEventCache(calendar, cname, occurenceTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -610,6 +683,8 @@ function eventsListCallback(http) {
|
|||
if (rTime)
|
||||
row.recurrenceTime = escape(rTime);
|
||||
row.isException = data[i][15];
|
||||
row.editable = data[i][16];
|
||||
row.erasable = data[i][17];
|
||||
var startDate = new Date();
|
||||
startDate.setTime(data[i][4] * 1000);
|
||||
row.day = startDate.getDayString();
|
||||
|
@ -630,12 +705,12 @@ function eventsListCallback(http) {
|
|||
td = $(document.createElement("td"));
|
||||
row.appendChild(td);
|
||||
td.observe("mousedown", listRowMouseDownHandler, true);
|
||||
td.appendChild(document.createTextNode(data[i][16])); // start date
|
||||
td.appendChild(document.createTextNode(data[i][19])); // start date
|
||||
|
||||
td = $(document.createElement("td"));
|
||||
row.appendChild(td);
|
||||
td.observe("mousedown", listRowMouseDownHandler, true);
|
||||
td.appendChild(document.createTextNode(data[i][17])); // end date
|
||||
td.appendChild(document.createTextNode(data[i][20])); // end date
|
||||
|
||||
td = $(document.createElement("td"));
|
||||
row.appendChild(td);
|
||||
|
@ -1063,6 +1138,9 @@ function newBaseEventDIV(eventRep, event, eventText) {
|
|||
// log ("13 nextalarm = " + event[13]);
|
||||
// log ("14 recurrenceid = " + event[14]);
|
||||
// log ("15 isexception = " + event[15]);
|
||||
// log ("16 editable = " + event[16]);
|
||||
// log ("17 erasable = " + event[17]);
|
||||
// log ("18 ownerisorganizer = " + event[18]);
|
||||
|
||||
var eventDiv = $(document.createElement("div"));
|
||||
eventDiv.cname = event[0];
|
||||
|
@ -1070,6 +1148,9 @@ function newBaseEventDIV(eventRep, event, eventText) {
|
|||
if (eventRep.recurrenceTime)
|
||||
eventDiv.recurrenceTime = eventRep.recurrenceTime;
|
||||
eventDiv.isException = event[15];
|
||||
eventDiv.editable = event[16];
|
||||
eventDiv.erasable = event[17];
|
||||
eventDiv.ownerIsOrganizer = event[18];
|
||||
eventDiv.addClassName("event");
|
||||
if (event[13] > 0)
|
||||
eventDiv.addClassName("alarm");
|
||||
|
@ -1500,7 +1581,6 @@ function onYearMenuItemClick(event) {
|
|||
|
||||
function _eventBlocksMatching(calendar, cname, recurrenceTime) {
|
||||
var blocks = null;
|
||||
|
||||
var events = calendarEvents[calendar];
|
||||
if (events) {
|
||||
var occurences = events[cname];
|
||||
|
|
Loading…
Reference in New Issue