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.sogomaint-2.0.2
commit
fc7157b3dc
10
ChangeLog
10
ChangeLog
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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>
|
||||||
*
|
*
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue