/* Copyright (C) 2000-2005 SKYRIX Software AG This file is part of OpenGroupware.org. OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. OGo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with OGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #import "common.h" #include @interface LSDeleteAppointmentCommand : LSDBObjectDeleteCommand { @protected BOOL deleteAllCyclic; BOOL checkPermissions; } @end @implementation LSDeleteAppointmentCommand - (id)initForOperation:(NSString *)_operation inDomain:(NSString *)_domain { if ((self = [super initForOperation:_operation inDomain:_domain])) { self->deleteAllCyclic = NO; self->checkPermissions = YES; } return self; } - (NSArray *)relations { NSArray *myRelations; NSEnumerator *enumerator; NSMutableArray *relevantRelations; EORelationship *rs; myRelations = [[self entity] relationships]; enumerator = [myRelations objectEnumerator]; relevantRelations = [NSMutableArray arrayWithCapacity:4]; rs = nil; while ((rs = [enumerator nextObject]) != nil) { if (![[rs name] isEqualToString:@"toDateInfo"] && ![[rs name] isEqualToString:@"toDate"]) { [relevantRelations addObject:rs]; } } return relevantRelations; } /* command methods */ - (void)_deleteDateInfo:(id)_ctx { BOOL isOk = YES; id dateInfo = nil; LSRunCommandV(_ctx, @"appointment", @"get-comment", @"object", [self object], @"relationKey", @"dateInfo", nil); dateInfo = [[self object] valueForKey:@"dateInfo"]; if ([dateInfo isKindOfClass:[NSArray class]]) dateInfo = [dateInfo lastObject]; if (dateInfo) { if ([self reallyDelete]) isOk = [[self databaseChannel] deleteObject:dateInfo]; else { [dateInfo takeValue:@"archived" forKey:@"dbStatus"]; isOk = [[self databaseChannel] updateObject:dateInfo]; } } [self assert:isOk reason:[sybaseMessages description]]; } - (void)_separateNotesInContext:(id)_context { id notes; int i, cnt; notes = [[self object] valueForKey:@"toNote"]; for (i = 0, cnt = [notes count]; i < cnt; i++) { /* detach if project is assigned delete if nothing assigned access to delete notes should be granted since the notes are assigend to the appointment */ id note = [notes objectAtIndex:i]; if ([[note valueForKey:@"projectId"] isNotNull]) { // project still assigned LSRunCommandV(_context, @"note", @"set", @"object", note, @"dateId", [EONull null], @"dontCheckAccess", [NSNumber numberWithBool:YES], nil); } else { LSRunCommandV(_context, @"note", @"delete", @"object", note, nil); } } if ([notes respondsToSelector:@selector(clear)]) [notes clear]; } - (BOOL)checkDeletePermissionInContext:(id)_context { NSString *permissions; EOGlobalID *gid; id obj; obj = [self object]; gid = [obj valueForKey:@"globalID"]; [self assert:(gid != nil) format:@"got no global-id for appointment object: %@", obj]; permissions = LSRunCommandV(_context, @"appointment", @"access", @"gid", gid, nil); return ([permissions rangeOfString:@"d"].length > 0) ? YES : NO; } - (NSException *)_removeObjectLogsInContext:(id)_context { id obj; obj = [self object]; [self assert:(obj != nil) reason:@"no object available"]; LSRunCommandV(_context, @"object", @"remove-logs", @"object", obj, nil); return nil; } - (NSArray *)_getCyclicForAppointment:(id)_apt inContext:(id)_context { return LSRunCommandV(_context, @"appointment", @"get-cyclic", @"object", _apt, nil); } - (NSArray *)_getCyclicInContext:(id)_context { id obj; obj = [self object]; [self assert:(obj != nil) reason:@"no object available"]; return [self _getCyclicForAppointment:obj inContext:_context]; } - (NSException *)_deleteAppointment:(id)_apt physically:(BOOL)_physically inContext:(id)_context { if (!_physically) { LSRunCommandV(_context, @"appointment", @"delete", @"object", _apt, nil); } else { LSRunCommandV(_context, @"appointment", @"delete", @"object", _apt, @"reallyDelete", [NSNumber numberWithBool:YES], nil); } return nil; } - (NSException *)_deleteNoCyclicInContext:(id)_context { NSArray *cyclics = nil; id firstCyclic = nil; id obj; int i, cnt; obj = [self object]; [self assert:(obj != nil) reason:@"no object available"]; cyclics = [self _getCyclicInContext:_context]; if ([cyclics count] == 0) return nil; firstCyclic = [cyclics objectAtIndex:0]; LSRunCommandV(_context, @"appointment", @"set", @"object", firstCyclic, @"parentDateId", [EONull null], @"type" , [obj valueForKey:@"type"], @"cycleEndDate", [obj valueForKey:@"cycleEndDate"], @"ownerId" , [firstCyclic valueForKey:@"ownerId"], @"accessTeamId", [firstCyclic valueForKey:@"accessTeamId"], @"startDate" , [firstCyclic valueForKey:@"startDate"], @"endDate" , [firstCyclic valueForKey:@"endDate"], @"location" , [firstCyclic valueForKey:@"location"], @"title" , [firstCyclic valueForKey:@"title"], @"absence" , [firstCyclic valueForKey:@"absence"], @"isAbsence", [firstCyclic valueForKey:@"isAbsence"], @"isAttendance", [firstCyclic valueForKey:@"isAttendance"], @"resourceNames", [firstCyclic valueForKey:@"resourceNames"], @"isWarningIgnored", [NSNumber numberWithBool:YES], nil); for (i = 1, cnt = [cyclics count]; i < cnt; i++) { id apmt; apmt = [cyclics objectAtIndex:i]; /* TODO: this is expensive, use a mutable dictionary for the params and clear/refill instead of doing the vargs parsing over and over again. */ LSRunCommandV(_context, @"appointment", @"set", @"object", apmt, @"parentDateId", [firstCyclic valueForKey:@"dateId"], @"ownerId" , [apmt valueForKey:@"ownerId"], @"accessTeamId", [apmt valueForKey:@"accessTeamId"], @"startDate" , [apmt valueForKey:@"startDate"], @"endDate" , [apmt valueForKey:@"endDate"], @"location" , [apmt valueForKey:@"location"], @"title" , [apmt valueForKey:@"title"], @"absence" , [apmt valueForKey:@"absence"], @"isAbsence", [apmt valueForKey:@"isAbsence"], @"isAttendance", [apmt valueForKey:@"isAttendance"], @"resourceNames" , [apmt valueForKey:@"resourceNames"], @"isWarningIgnored", [NSNumber numberWithBool:YES], nil); } return nil; } - (NSException *)_deleteCyclicInContext:(id)_context { EODatabaseContext *dbCtx; NSArray *cyclics = nil; NSNumber *pId = nil; id firstCyclic = nil; id obj; int i, cnt; obj = [self object]; [self assert:(obj != nil) reason:@"no object available"]; pId = [obj valueForKey:@"parentDateId"]; dbCtx = [_context valueForKey:LSDatabaseContextKey]; if (pId == nil) { cyclics = [self _getCyclicInContext:_context]; } else { NSMutableArray *c; c = [NSMutableArray array]; firstCyclic= LSRunCommandV(_context, @"appointment", @"get", @"dateId", pId, nil); if ([firstCyclic count] == 1) firstCyclic = [firstCyclic objectAtIndex:0]; cyclics = [self _getCyclicForAppointment:firstCyclic inContext:_context]; [c addObjectsFromArray:cyclics]; [c removeObject:[self object]]; cyclics = c; } for (i = 0, cnt = [cyclics count]; i < cnt; i++) { id appointment; appointment = [cyclics objectAtIndex:i]; [self _deleteAppointment:appointment physically:YES inContext:_context]; } [self _removeObjectLogsInContext:_context]; /* TODO: hh asks: why is that?? Shouldn't the caller (execute) commit the transaction? And why doesn't happen everything in a single transaction? */ [(EODatabaseContext *)dbCtx commitTransaction]; [(EODatabaseContext *)dbCtx beginTransaction]; [super _executeInContext:_context]; if (firstCyclic) [self _deleteAppointment:firstCyclic physically:YES inContext:_context]; return nil; } - (void)_executeInContext:(id)_context { id obj; NSNumber *pId = nil; NSString *type = nil; EODatabaseContext *dbCtx; obj = [self object]; [self assert:(obj != nil) reason:@"no object available"]; dbCtx = [_context valueForKey:LSDatabaseContextKey]; if (self->checkPermissions) { [self assert:[self checkDeletePermissionInContext:_context] format:@"denied permission to delete appointment '%@'", [obj valueForKey:@"title"]]; } pId = [obj valueForKey:@"parentDateId"]; type = [obj valueForKey:@"type"]; [[_context propertyManager] removeAllPropertiesForGlobalID: [obj valueForKey:@"globalID"]]; [self _deleteDateInfo:_context]; [self _separateNotesInContext:_context]; [self _deleteRelations:[self relations] inContext:_context]; /* TODO: document the following section */ if (!self->deleteAllCyclic) { /* TODO: doc! I guess this will reset the "anker" appointment? */ [[self _deleteNoCyclicInContext:_context] raise]; [[self _removeObjectLogsInContext:_context] raise]; if ([dbCtx commitTransaction]) { [self assert:[dbCtx beginTransaction] reason:@"couldn't begin tx .."]; [super _executeInContext:_context]; } else [dbCtx rollbackTransaction]; } else { [[self _deleteCyclicInContext:_context] raise]; } } /* entity name for DB-delete-command (superclass) */ - (NSString *)entityName { return @"Date"; } /* accessors */ - (void)setDeleteAllCyclic:(BOOL)_flag { self->deleteAllCyclic = _flag; } - (BOOL)deleteAllCyclic { return self->deleteAllCyclic; } /* key/value coding */ - (void)takeValue:(id)_value forKey:(NSString *)_key { if ([_key isEqualToString:@"deleteAllCyclic"]) [self setDeleteAllCyclic:[_value boolValue]]; if ([_key isEqualToString:@"checkPermissions"]) self->checkPermissions = [_value boolValue]; else [super takeValue:_value forKey:_key]; } - (id)valueForKey:(NSString *)_key { if ([_key isEqualToString:@"deleteAllCyclic"]) return [NSNumber numberWithBool:[self deleteAllCyclic]]; else if ([_key isEqualToString:@"checkPermissions"]) return [NSNumber numberWithBool:self->checkPermissions]; return [super valueForKey:_key]; } @end /* LSDeleteAppointmentCommand */