From 5886e82c794e118e402aff260e4eba309872867e Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 9 Jul 2008 15:42:22 +0000 Subject: [PATCH] Monotone-Parent: 1ffb41682368b46b7d5dfbe50eb430e0859f6837 Monotone-Revision: 9402acf99e73ef8bdcad7719c88dc1d6a3ee27d4 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2008-07-09T15:42:22 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 9 ++ SoObjects/SOGo/SOGoContentObject.h | 4 +- SoObjects/SOGo/SOGoContentObject.m | 168 +++++++++++++++-------------- 3 files changed, 100 insertions(+), 81 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8bd2072ff..da0efac1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-07-09 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject + -PUTAction:_ctx]): the version passed to + saveContentString:baseVersion: is the current value of "version". + If the operation is succesful, the version is incremented from + here since no refresh is done from GCS. The returned etag has thus + now the correct value. + 2008-07-08 Wolfgang Sourdeau * SoObjects/Appointments/SOGoAppointmentFolder.m diff --git a/SoObjects/SOGo/SOGoContentObject.h b/SoObjects/SOGo/SOGoContentObject.h index 9aa5ccbbb..0961ae2a4 100644 --- a/SoObjects/SOGo/SOGoContentObject.h +++ b/SoObjects/SOGo/SOGoContentObject.h @@ -45,8 +45,8 @@ andContent: (NSString *) newContent inContainer: (SOGoGCSFolder *) newContainer; - (id) initWithRecord: (NSDictionary *) objectRecord - inContainer: (id) newContainer; -+ (id) initWithName: (NSString *) newName + inContainer: (SOGoGCSFolder *) newContainer; +- (id) initWithName: (NSString *) newName andContent: (NSString *) newContent inContainer: (SOGoGCSFolder *) newContainer; diff --git a/SoObjects/SOGo/SOGoContentObject.m b/SoObjects/SOGo/SOGoContentObject.m index b68ce50e6..d4c6e82db 100644 --- a/SoObjects/SOGo/SOGoContentObject.m +++ b/SoObjects/SOGo/SOGoContentObject.m @@ -53,13 +53,13 @@ return newObject; } -+ (id) objectWithName: (NSDictionary *) objectRecord ++ (id) objectWithName: (NSString *) newName andContent: (NSString *) newContent inContainer: (SOGoGCSFolder *) newContainer { SOGoContentObject *newObject; - newObject = [[self alloc] initWithName: objectRecord + newObject = [[self alloc] initWithName: newName andContent: newContent inContainer: newContainer]; [newObject autorelease]; @@ -104,7 +104,7 @@ } - (id) initWithRecord: (NSDictionary *) objectRecord - inContainer: (id) newContainer + inContainer: (SOGoGCSFolder *) newContainer { NSString *newName; @@ -119,7 +119,7 @@ - (id) initWithName: (NSString *) newName andContent: (NSString *) newContent - inContainer: (id) newContainer + inContainer: (SOGoGCSFolder *) newContainer { if ((self = [self initWithName: newName inContainer: newContainer])) { @@ -233,88 +233,98 @@ - (id) PUTAction: (WOContext *) _ctx { - WORequest *rq; - NSException *error; + WORequest *rq; + NSException *error; unsigned int baseVersion; - id etag, tmp; - BOOL needsLocation; - - if ((error = [self matchesRequestConditionInContext:_ctx]) != nil) - return error; - - rq = [_ctx request]; - - /* check whether its a request to the 'special' 'new' location */ - /* - Note: this is kinda hack. The OGo ZideStore detects writes to 'new' as - object creations and will assign a server side identifier. Most - current GroupDAV clients rely on this behaviour, so we reproduce it - here. - A correct client would loop until it has a name which doesn't not - yet exist (by using if-none-match). - */ - needsLocation = NO; - tmp = [[self nameInContainer] stringByDeletingPathExtension]; - if ([tmp isEqualToString:@"new"]) { - tmp = [self globallyUniqueObjectId]; - needsLocation = YES; - - [self debugWithFormat: - @"reassigned a new location for special new-location: %@", tmp]; - - /* kinda dangerous */ - ASSIGNCOPY(nameInContainer, tmp); - } - - /* determine base version from etag in if-match header */ - /* - Note: The -matchesRequestConditionInContext: already checks whether the - etag matches and returns an HTTP exception in case it doesn't. - We retrieve the etag again here to _ensure_ a transactionally save - commit. - (between the check and the update a change could have been done) - */ - tmp = [rq headerForKey:@"if-match"]; - tmp = [self parseETagList:tmp]; - etag = nil; - if ([tmp count] > 0) { - if ([tmp count] > 1) { - /* - Note: we would have to attempt a save for _each_ of the etags being - passed in! In practice most WebDAV clients submit exactly one - etag. - */ - [self warnWithFormat: - @"Got multiple if-match etags from client, only attempting to " - @"save with the first: %@", tmp]; - } - - etag = [tmp objectAtIndex:0]; - } - baseVersion = ([etag length] > 0) - ? [etag unsignedIntValue] - : 0 /* 0 means 'do not check' */; - - /* attempt a save */ + id etag, tmp; + BOOL needsLocation; + WOResponse *response; - if ((error = [self saveContentString: [rq contentAsString] - baseVersion: baseVersion]) != nil) - return error; + error = [self matchesRequestConditionInContext: _ctx]; + if (error) + response = (WOResponse *) error; + else + { + rq = [_ctx request]; - /* setup response */ + /* check whether its a request to the 'special' 'new' location */ + /* + Note: this is kinda hack. The OGo ZideStore detects writes to 'new' as + object creations and will assign a server side identifier. Most + current GroupDAV clients rely on this behaviour, so we reproduce it + here. + A correct client would loop until it has a name which doesn't not + yet exist (by using if-none-match). + */ + needsLocation = NO; + + tmp = [[self nameInContainer] stringByDeletingPathExtension]; + if ([tmp isEqualToString: @"new"]) + { + tmp = [self globallyUniqueObjectId]; + needsLocation = YES; + + [self debugWithFormat: + @"reassigned a new location for special new-location: %@", tmp]; + + /* kinda dangerous */ + ASSIGNCOPY (nameInContainer, tmp); + } - // TODO: this should be automatic in the SoDispatcher if we return nil? - [[_ctx response] setStatus: 201 /* Created */]; + /* determine base version from etag in if-match header */ + /* + Note: The -matchesRequestConditionInContext: already checks whether the + etag matches and returns an HTTP exception in case it doesn't. + We retrieve the etag again here to _ensure_ a transactionally save + commit. + (between the check and the update a change could have been done) + */ + tmp = [rq headerForKey: @"if-match"]; + tmp = [self parseETagList: tmp]; + etag = nil; + if ([tmp count] > 0) { + if ([tmp count] > 1) { + /* + Note: we would have to attempt a save for _each_ of the etags being + passed in! In practice most WebDAV clients submit exactly one + etag. + */ + [self warnWithFormat: + @"Got multiple if-match etags from client, only attempting to " + @"save with the first: %@", tmp]; + } + + etag = [tmp objectAtIndex: 0]; + } + baseVersion = (isNew ? 0 : version); - if ((etag = [self davEntityTag]) != nil) - [[_ctx response] setHeader:etag forKey:@"etag"]; + /* attempt a save */ + + error = [self saveContentString: [rq contentAsString] + baseVersion: baseVersion]; + if (error) + response = (WOResponse *) error; + else + { + version++; + response = [_ctx response]; + /* setup response */ - if (needsLocation) { - [[_ctx response] setHeader:[self baseURLInContext:_ctx] - forKey:@"location"]; - } + // TODO: this should be automatic in the SoDispatcher if we return nil? + [response setStatus: 201 /* Created */]; - return [_ctx response]; + etag = [self davEntityTag]; + if (etag) + { + [response setHeader: etag forKey: @"etag"]; + if (needsLocation) + [response setHeader: [self baseURLInContext:_ctx] + forKey: @"location"]; + } + } + } + + return response; } /* E-Tags */