diff --git a/ChangeLog b/ChangeLog index 5ffcf30ed..1b0275a94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-04-24 Ludovic Marcotte + + * SOPE/GDLContentStore/GCSFolder.m (-writeContent:toName:baseVersion:): + We now keep track of the saved version for all callers. Also updated + all callers to reflect that change. + + * SoObjects/Appointments/SOGoAppointmentObject.m (-PUTAction:) + Took some of the logic from SOGoContentObject's -PUTAction: to + avoid etag mismatches. + 2012-04-23 Ludovic Marcotte * SoObjects/Appointments/SOGoAppointmentObject.m: We now diff --git a/SOPE/GDLContentStore/GCSFolder.h b/SOPE/GDLContentStore/GCSFolder.h index eb547219a..ff940fd40 100644 --- a/SOPE/GDLContentStore/GCSFolder.h +++ b/SOPE/GDLContentStore/GCSFolder.h @@ -118,7 +118,7 @@ - (NSException *) writeContent: (NSString *) _content toName: (NSString *) _name - baseVersion: (unsigned int) _baseVersion; + baseVersion: (unsigned int *) _baseVersion; - (NSException *) writeContent: (NSString *) _content toName: (NSString *) _name; - (NSException *) deleteContentWithName: (NSString *) _name; diff --git a/SOPE/GDLContentStore/GCSFolder.m b/SOPE/GDLContentStore/GCSFolder.m index 8361ca683..6130ce810 100644 --- a/SOPE/GDLContentStore/GCSFolder.m +++ b/SOPE/GDLContentStore/GCSFolder.m @@ -882,7 +882,7 @@ andAttribute: (EOAttribute *)_attribute - (NSException *) writeContent: (NSString *) _content toName: (NSString *) _name - baseVersion: (unsigned int) _baseVersion + baseVersion: (unsigned int *) _baseVersion { EOAdaptorChannel *storeChannel, *quickChannel; NSMutableDictionary *quickRow, *contentRow; @@ -939,8 +939,8 @@ andAttribute: (EOAttribute *)_attribute /* check whether sequence matches */ /* use version = 0 to override check */ - if (_baseVersion == 0 - || _baseVersion == [storedVersion unsignedIntValue]) + if (*_baseVersion == 0 + || *_baseVersion == [storedVersion unsignedIntValue]) { /* extract quick info */ extractor = [folderInfo quickExtractor]; @@ -1040,16 +1040,16 @@ andAttribute: (EOAttribute *)_attribute error = (hasUpdateDelegate ? [storeChannel updateRowX: contentRow describedByQualifier: [self _qualifierUsingWhereColumn: @"c_name" isEqualTo: _name - andColumn: (_baseVersion != 0 ? (id)@"c_version" : (id)nil) - isEqualTo: (_baseVersion != 0 ? [NSNumber numberWithUnsignedInt:_baseVersion] : (NSNumber *)nil) + andColumn: (*_baseVersion != 0 ? (id)@"c_version" : (id)nil) + isEqualTo: (*_baseVersion != 0 ? [NSNumber numberWithUnsignedInt: *_baseVersion] : (NSNumber *)nil) entity: storeTableEntity withAdaptor: [[storeChannel adaptorContext] adaptor]]] : [storeChannel evaluateExpressionX: [self _generateUpdateStatementForRow: contentRow adaptor: [[storeChannel adaptorContext] adaptor] tableName:[self storeTableName] whereColumn: @"c_name" isEqualTo: _name - andColumn: (_baseVersion != 0 ? (id)@"c_version" : (id)nil) - isEqualTo: (_baseVersion != 0 ? [NSNumber numberWithUnsignedInt: _baseVersion] : (NSNumber *)nil)]]); + andColumn: (*_baseVersion != 0 ? (id)@"c_version" : (id)nil) + isEqualTo: (*_baseVersion != 0 ? [NSNumber numberWithUnsignedInt: *_baseVersion] : (NSNumber *)nil)]]); } if (error) @@ -1063,6 +1063,9 @@ andAttribute: (EOAttribute *)_attribute } else { + if (!isNewRecord) + *_baseVersion += 1; + [[storeChannel adaptorContext] commitTransaction]; [[quickChannel adaptorContext] commitTransaction]; } @@ -1082,7 +1085,7 @@ andAttribute: (EOAttribute *)_attribute else /* version mismatch (concurrent update) */ error = [self errorVersionMismatchBetweenStoredVersion: [storedVersion unsignedIntValue] - andExpectedVersion: _baseVersion]; + andExpectedVersion: *_baseVersion]; } else error = [NSException exceptionWithName:@"GCSStoreException" @@ -1100,7 +1103,8 @@ andAttribute: (EOAttribute *)_attribute - (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name { /* this method does not check for concurrent writes */ - return [self writeContent:_content toName:_name baseVersion:0]; + unsigned int v = 0; + return [self writeContent:_content toName:_name baseVersion:&v]; } - (NSException *)deleteContentWithName:(NSString *)_name { diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 55455a088..50f02bc98 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -1658,11 +1658,13 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent - (id) PUTAction: (WOContext *) _ctx { NSException *ex; + NSString *etag; NSArray *roles; WORequest *rq; - id response; + unsigned int baseVersion; + rq = [_ctx request]; roles = [[context activeUser] rolesForObject: self inContext: context]; @@ -1961,9 +1963,27 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent } } - // This will save the event into the database and also handle - // E-Tags properly, as well as content versioning. - response = [super PUTAction: _ctx]; + // We must NOT invoke [super PUTAction:] here as it'll resave + // the content string and we could have etag mismatches. + response = [_ctx response]; + + baseVersion = (isNew ? 0 : version); + + ex = [self saveContentString: [rq contentAsString] + baseVersion: baseVersion]; + if (ex) + response = (WOResponse *) ex; + else + { + if (isNew) + [response setStatus: 201 /* Created */]; + else + [response setStatus: 204 /* No Content */]; + + etag = [self davEntityTag]; + if (etag) + [response setHeader: etag forKey: @"etag"]; + } return response; } diff --git a/SoObjects/Appointments/SOGoTaskObject.m b/SoObjects/Appointments/SOGoTaskObject.m index 3749e17e1..398db5119 100644 --- a/SoObjects/Appointments/SOGoTaskObject.m +++ b/SoObjects/Appointments/SOGoTaskObject.m @@ -1,14 +1,15 @@ /* + Copyright (C) 2006-2012 Inverse inc. Copyright (C) 2004-2005 SKYRIX Software AG - This file is part of OpenGroupware.org. + This file is part of SOGo. - OGo is free software; you can redistribute it and/or modify it under + SOGo 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 + SOGo 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. diff --git a/SoObjects/Contacts/SOGoContactGCSEntry.m b/SoObjects/Contacts/SOGoContactGCSEntry.m index fd33f7cfc..436cb92c4 100644 --- a/SoObjects/Contacts/SOGoContactGCSEntry.m +++ b/SoObjects/Contacts/SOGoContactGCSEntry.m @@ -1,6 +1,6 @@ /* SOGoContactGCSEntry.h - this file is part of SOGo * - * Copyright (C) 2006-2011 Inverse inc. + * Copyright (C) 2006-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/SoObjects/SOGo/SOGoContentObject.m b/SoObjects/SOGo/SOGoContentObject.m index 7e8c88fa3..801ab2d33 100644 --- a/SoObjects/SOGo/SOGoContentObject.m +++ b/SoObjects/SOGo/SOGoContentObject.m @@ -209,7 +209,7 @@ { ex = [folder writeContent: newContent toName: nameInContainer - baseVersion: newVersion]; + baseVersion: &version]; if (ex) [self errorWithFormat:@"write failed: %@", ex]; } @@ -225,7 +225,7 @@ - (NSException *) saveContentString: (NSString *) newContent { - return [self saveContentString: newContent baseVersion: 0]; + return [self saveContentString: newContent baseVersion: version]; } /* actions */ @@ -347,8 +347,6 @@ response = (WOResponse *) error; else { - if (!isNew) - version++; response = [_ctx response]; /* setup response */ diff --git a/Tools/SOGoToolRestore.m b/Tools/SOGoToolRestore.m index 2949b4fc7..e8915ae77 100644 --- a/Tools/SOGoToolRestore.m +++ b/Tools/SOGoToolRestore.m @@ -1,6 +1,6 @@ /* SOGoToolRestore.m - this file is part of SOGo * - * Copyright (C) 2009-2010 Inverse inc. + * Copyright (C) 2009-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -346,14 +346,16 @@ typedef enum SOGoToolRestoreMode { - (BOOL) restoreRecords: (NSArray *) records ofFolder: (GCSFolder *) gcsFolder { - BOOL rc; NSDictionary *existingRecords, *currentRecord; NSString *cName, *cContent; NSException *ex; - int count, max; + + int count, max, version; + BOOL rc; if (records) { + version = 0; rc = YES; existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder]; max = [records count]; @@ -366,7 +368,7 @@ typedef enum SOGoToolRestoreMode { NSLog (@"restoring record '%@'", cName); cContent = [currentRecord objectForKey: @"c_content"]; ex = [gcsFolder writeContent: cContent toName: cName - baseVersion: 0]; + baseVersion: &version]; } } }