propagate from branch 'ca.inverse.sogo.1_3_15' (head fc9e1cf3f4988bae25443b6d072add3f344d30f0)

to branch 'ca.inverse.sogo' (head 6331064cc925005acad759e8c6eac99b6b7071cd)

Monotone-Parent: 6331064cc925005acad759e8c6eac99b6b7071cd
Monotone-Parent: fc9e1cf3f4988bae25443b6d072add3f344d30f0
Monotone-Revision: 1a1393f78ba372cce09b37d46908cc3e7553d869

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2012-04-24T11:48:06
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Ludovic Marcotte 2012-04-24 11:48:06 +00:00
commit fc7157b3dc
8 changed files with 61 additions and 26 deletions

View File

@ -1,3 +1,13 @@
2012-04-24 Ludovic Marcotte <lmarcotte@inverse.ca>
* 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 <lmarcotte@inverse.ca> 2012-04-23 Ludovic Marcotte <lmarcotte@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentObject.m: We now * SoObjects/Appointments/SOGoAppointmentObject.m: We now

View File

@ -118,7 +118,7 @@
- (NSException *) writeContent: (NSString *) _content - (NSException *) writeContent: (NSString *) _content
toName: (NSString *) _name toName: (NSString *) _name
baseVersion: (unsigned int) _baseVersion; baseVersion: (unsigned int *) _baseVersion;
- (NSException *) writeContent: (NSString *) _content - (NSException *) writeContent: (NSString *) _content
toName: (NSString *) _name; toName: (NSString *) _name;
- (NSException *) deleteContentWithName: (NSString *) _name; - (NSException *) deleteContentWithName: (NSString *) _name;

View File

@ -882,7 +882,7 @@ andAttribute: (EOAttribute *)_attribute
- (NSException *) writeContent: (NSString *) _content - (NSException *) writeContent: (NSString *) _content
toName: (NSString *) _name toName: (NSString *) _name
baseVersion: (unsigned int) _baseVersion baseVersion: (unsigned int *) _baseVersion
{ {
EOAdaptorChannel *storeChannel, *quickChannel; EOAdaptorChannel *storeChannel, *quickChannel;
NSMutableDictionary *quickRow, *contentRow; NSMutableDictionary *quickRow, *contentRow;
@ -939,8 +939,8 @@ andAttribute: (EOAttribute *)_attribute
/* check whether sequence matches */ /* check whether sequence matches */
/* use version = 0 to override check */ /* use version = 0 to override check */
if (_baseVersion == 0 if (*_baseVersion == 0
|| _baseVersion == [storedVersion unsignedIntValue]) || *_baseVersion == [storedVersion unsignedIntValue])
{ {
/* extract quick info */ /* extract quick info */
extractor = [folderInfo quickExtractor]; extractor = [folderInfo quickExtractor];
@ -1040,16 +1040,16 @@ andAttribute: (EOAttribute *)_attribute
error = (hasUpdateDelegate error = (hasUpdateDelegate
? [storeChannel updateRowX: contentRow ? [storeChannel updateRowX: contentRow
describedByQualifier: [self _qualifierUsingWhereColumn: @"c_name" isEqualTo: _name describedByQualifier: [self _qualifierUsingWhereColumn: @"c_name" isEqualTo: _name
andColumn: (_baseVersion != 0 ? (id)@"c_version" : (id)nil) andColumn: (*_baseVersion != 0 ? (id)@"c_version" : (id)nil)
isEqualTo: (_baseVersion != 0 ? [NSNumber numberWithUnsignedInt:_baseVersion] : (NSNumber *)nil) isEqualTo: (*_baseVersion != 0 ? [NSNumber numberWithUnsignedInt: *_baseVersion] : (NSNumber *)nil)
entity: storeTableEntity entity: storeTableEntity
withAdaptor: [[storeChannel adaptorContext] adaptor]]] withAdaptor: [[storeChannel adaptorContext] adaptor]]]
: [storeChannel evaluateExpressionX: [self _generateUpdateStatementForRow: contentRow : [storeChannel evaluateExpressionX: [self _generateUpdateStatementForRow: contentRow
adaptor: [[storeChannel adaptorContext] adaptor] adaptor: [[storeChannel adaptorContext] adaptor]
tableName:[self storeTableName] tableName:[self storeTableName]
whereColumn: @"c_name" isEqualTo: _name whereColumn: @"c_name" isEqualTo: _name
andColumn: (_baseVersion != 0 ? (id)@"c_version" : (id)nil) andColumn: (*_baseVersion != 0 ? (id)@"c_version" : (id)nil)
isEqualTo: (_baseVersion != 0 ? [NSNumber numberWithUnsignedInt: _baseVersion] : (NSNumber *)nil)]]); isEqualTo: (*_baseVersion != 0 ? [NSNumber numberWithUnsignedInt: *_baseVersion] : (NSNumber *)nil)]]);
} }
if (error) if (error)
@ -1063,6 +1063,9 @@ andAttribute: (EOAttribute *)_attribute
} }
else else
{ {
if (!isNewRecord)
*_baseVersion += 1;
[[storeChannel adaptorContext] commitTransaction]; [[storeChannel adaptorContext] commitTransaction];
[[quickChannel adaptorContext] commitTransaction]; [[quickChannel adaptorContext] commitTransaction];
} }
@ -1082,7 +1085,7 @@ andAttribute: (EOAttribute *)_attribute
else /* version mismatch (concurrent update) */ else /* version mismatch (concurrent update) */
error = [self errorVersionMismatchBetweenStoredVersion: error = [self errorVersionMismatchBetweenStoredVersion:
[storedVersion unsignedIntValue] [storedVersion unsignedIntValue]
andExpectedVersion: _baseVersion]; andExpectedVersion: *_baseVersion];
} }
else else
error = [NSException exceptionWithName:@"GCSStoreException" error = [NSException exceptionWithName:@"GCSStoreException"
@ -1100,7 +1103,8 @@ andAttribute: (EOAttribute *)_attribute
- (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name { - (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name {
/* this method does not check for concurrent writes */ /* 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 { - (NSException *)deleteContentWithName:(NSString *)_name {

View File

@ -1658,11 +1658,13 @@ inRecurrenceExceptionsForEvent: (iCalEvent *) theEvent
- (id) PUTAction: (WOContext *) _ctx - (id) PUTAction: (WOContext *) _ctx
{ {
NSException *ex; NSException *ex;
NSString *etag;
NSArray *roles; NSArray *roles;
WORequest *rq; WORequest *rq;
id response; id response;
unsigned int baseVersion;
rq = [_ctx request]; rq = [_ctx request];
roles = [[context activeUser] rolesForObject: self inContext: context]; 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 // We must NOT invoke [super PUTAction:] here as it'll resave
// E-Tags properly, as well as content versioning. // the content string and we could have etag mismatches.
response = [super PUTAction: _ctx]; 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; return response;
} }

View File

@ -1,14 +1,15 @@
/* /*
Copyright (C) 2006-2012 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG 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 the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any Free Software Foundation; either version 2, or (at your option) any
later version. 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 WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details. License for more details.

View File

@ -1,6 +1,6 @@
/* SOGoContactGCSEntry.h - this file is part of SOGo /* SOGoContactGCSEntry.h - this file is part of SOGo
* *
* Copyright (C) 2006-2011 Inverse inc. * Copyright (C) 2006-2012 Inverse inc.
* *
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* *

View File

@ -209,7 +209,7 @@
{ {
ex = [folder writeContent: newContent ex = [folder writeContent: newContent
toName: nameInContainer toName: nameInContainer
baseVersion: newVersion]; baseVersion: &version];
if (ex) if (ex)
[self errorWithFormat:@"write failed: %@", ex]; [self errorWithFormat:@"write failed: %@", ex];
} }
@ -225,7 +225,7 @@
- (NSException *) saveContentString: (NSString *) newContent - (NSException *) saveContentString: (NSString *) newContent
{ {
return [self saveContentString: newContent baseVersion: 0]; return [self saveContentString: newContent baseVersion: version];
} }
/* actions */ /* actions */
@ -347,8 +347,6 @@
response = (WOResponse *) error; response = (WOResponse *) error;
else else
{ {
if (!isNew)
version++;
response = [_ctx response]; response = [_ctx response];
/* setup response */ /* setup response */

View File

@ -1,6 +1,6 @@
/* SOGoToolRestore.m - this file is part of SOGo /* SOGoToolRestore.m - this file is part of SOGo
* *
* Copyright (C) 2009-2010 Inverse inc. * Copyright (C) 2009-2012 Inverse inc.
* *
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca> * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* *
@ -346,14 +346,16 @@ typedef enum SOGoToolRestoreMode {
- (BOOL) restoreRecords: (NSArray *) records - (BOOL) restoreRecords: (NSArray *) records
ofFolder: (GCSFolder *) gcsFolder ofFolder: (GCSFolder *) gcsFolder
{ {
BOOL rc;
NSDictionary *existingRecords, *currentRecord; NSDictionary *existingRecords, *currentRecord;
NSString *cName, *cContent; NSString *cName, *cContent;
NSException *ex; NSException *ex;
int count, max;
int count, max, version;
BOOL rc;
if (records) if (records)
{ {
version = 0;
rc = YES; rc = YES;
existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder]; existingRecords = [self fetchExistingRecordsFromFolder: gcsFolder];
max = [records count]; max = [records count];
@ -366,7 +368,7 @@ typedef enum SOGoToolRestoreMode {
NSLog (@"restoring record '%@'", cName); NSLog (@"restoring record '%@'", cName);
cContent = [currentRecord objectForKey: @"c_content"]; cContent = [currentRecord objectForKey: @"c_content"];
ex = [gcsFolder writeContent: cContent toName: cName ex = [gcsFolder writeContent: cContent toName: cName
baseVersion: 0]; baseVersion: &version];
} }
} }
} }