X-Git-Url: https://code.grnet.gr/git/pithos-macos/blobdiff_plain/89dfe4a3399db8583aae9df94b1e112632d261ee..6d9d5dce6b6df63e7e44314f25ee2a39b953397d:/pithos-macos/PithosObjectNode.m diff --git a/pithos-macos/PithosObjectNode.m b/pithos-macos/PithosObjectNode.m index 7ee0181..ffe8fd1 100644 --- a/pithos-macos/PithosObjectNode.m +++ b/pithos-macos/PithosObjectNode.m @@ -2,7 +2,7 @@ // PithosObjectNode.m // pithos-macos // -// Copyright 2011-2012 GRNET S.A. All rights reserved. +// Copyright 2011-2013 GRNET S.A. All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the following @@ -41,63 +41,90 @@ #import "ASIPithosObjectRequest.h" #import "ASIPithosContainer.h" #import "ASIPithosObject.h" +#import "ASIPithosSharingUser.h" #import "ASIDownloadCache.h" +#import "PithosAccount.h" #import "PithosUtilities.h" #import "PithosObjectNodeInfoController.h" @implementation PithosObjectNode -@synthesize pithos, pithosContainer, pithosObject, versions; -@synthesize isPublic; +@synthesize pithosContainer, pithosObject, versions, applyMetadataObjectRequest, refreshMetadataObjectRequest, refreshVersionsObjectRequest; +@synthesize isPublic, translatedModifiedBy, translatedPermissions; #pragma mark - #pragma mark Object Lifecycle -- (id)initWithPithos:(ASIPithos *)aPithos - pithosContainer:(ASIPithosContainer *)aPithosContainer - pithosObject:(ASIPithosObject *)aPithosObject { - if ((self = [super init])) { - self.pithos = aPithos; +- (id)initWithPithosAccountManager:(PithosAccount *)aPithosAccountManager + pithosContainer:(ASIPithosContainer *)aPithosContainer + pithosObject:(ASIPithosObject *)aPithosObject { + if ((self = [super initWithPithosAccountManager:aPithosAccountManager])) { + isLeafItem = YES; self.pithosContainer = aPithosContainer; self.pithosObject = aPithosObject; - isLeafItem = YES; } return self; } - (void)dealloc { [refreshVersionsObjectRequest clearDelegatesAndCancel]; - [refreshVersionsObjectRequest release]; [refreshMetadataObjectRequest clearDelegatesAndCancel]; - [refreshMetadataObjectRequest release]; [applyMetadataObjectRequest clearDelegatesAndCancel]; - [applyMetadataObjectRequest release]; - [versions release]; - [pithosObject release]; - [pithosContainer release]; - [pithos release]; - [super dealloc]; } #pragma mark - -#pragma mark Properties +#pragma mark Internal -- (void)setPithos:(ASIPithos *)aPithos { - if (aPithos && ![aPithos isEqualTo:pithos]) { - [pithos release]; - pithos = [aPithos retain]; - [url release]; - url = nil; +- (void)updateModifiedBy { + if (!pithosObject.modifiedBy) { + self.translatedModifiedBy = nil; + } else if (pithosAccountManager) { + NSString *displayname = [pithosAccountManager displaynameForUUID:pithosObject.modifiedBy safe:NO]; + if (displayname) { + self.translatedModifiedBy = displayname; + } else { + [pithosAccountManager updateUserCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:pithosObject.modifiedBy]]; + self.translatedModifiedBy = [pithosAccountManager displaynameForUUID:pithosObject.modifiedBy safe:YES]; + } + } else { + self.translatedModifiedBy = [pithosObject.modifiedBy copy]; + } +} + +- (void)updatePermissions { + if (!pithosObject) { + self.translatedPermissions = [NSMutableArray array]; + } else if (pithosAccountManager) { + NSMutableSet *UUIDs = [NSMutableSet set]; + for (ASIPithosSharingUser *sharingUser in pithosObject.permissions) { + [UUIDs addObject:sharingUser.name]; + } + [UUIDs removeObject:@""]; + [UUIDs removeObject:@"*"]; + if (UUIDs.count) { + [pithosAccountManager updateUserCatalogForDisplaynames:nil UUIDs:[UUIDs allObjects]]; + } + + NSMutableArray *newTranslatedPermissions = [NSMutableArray arrayWithCapacity:pithosObject.permissions.count]; + for (ASIPithosSharingUser *sharingUser in pithosObject.permissions) { + ASIPithosSharingUser *translatedSharingUser = [sharingUser copy]; + translatedSharingUser.name = [pithosAccountManager displaynameForUUID:translatedSharingUser.name safe:YES]; + [newTranslatedPermissions addObject:translatedSharingUser]; + } + self.translatedPermissions = newTranslatedPermissions; + } else { + self.translatedPermissions = [NSMutableArray arrayWithArray:[pithosObject.permissions copy]]; } } +#pragma mark - +#pragma mark Properties + - (NSString *)url { - if (url == nil) - url = [[NSString alloc] initWithFormat:@"object %@/%@/%@%@", - (sharingAccount ? [pithos storageURLWithAuthUser:sharingAccount] : pithos.storageURL), - pithosContainer.name, - pithosObject.name, - (shared ? @"?shared" : @"")]; - return url; + return [NSString stringWithFormat:@"@object@%@/%@/%@%@", + (sharingAccount ? sharingAccount : pithosAccountManager.pithos.authUser), + pithosContainer.name, + pithosObject.name, + (shared ? @"?shared" : @"")]; } - (NSArray *)children { @@ -109,9 +136,8 @@ displayName = [pithosObject.name lastPathComponent]; if([pithosObject.name hasSuffix:@"/"]) displayName = [displayName stringByAppendingString:@"/"]; - [displayName retain]; } - return [[displayName copy] autorelease]; + return [displayName copy]; } - (void)setDisplayName:(NSString *)aDisplayName { @@ -119,19 +145,20 @@ - (NSImage *)icon { if (icon == nil) - icon = [[[NSWorkspace sharedWorkspace] iconForFileType:[pithosObject.name pathExtension]] retain]; + icon = [[NSWorkspace sharedWorkspace] iconForFileType:[pithosObject.name pathExtension]]; return icon; } - (void)setPithosObject:(ASIPithosObject *)aPithosObject { if (![pithosObject isEqualTo:aPithosObject]) { - [pithosObject release]; - pithosObject = [aPithosObject retain]; + pithosObject = aPithosObject; + [self updateModifiedBy]; + [self updatePermissions]; } self.isPublic = (pithosObject.publicURI != nil); // Refresh browser if the object is in my shared and is no longer shared if (shared && !pithosObject.sharing) - [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosBrowserRefreshNeeeded" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosBrowserRefreshNeeded" object:self]; } - (void)setLimitedPithosObject:(ASIPithosObject *)aPithosObject { @@ -153,6 +180,9 @@ self.pithosObject.sharing = aPithosObject.sharing; self.pithosObject.publicURI = aPithosObject.publicURI; self.pithosObject = pithosObject; + [self updatePermissions]; + } else { + [self updateModifiedBy]; } } } @@ -161,83 +191,75 @@ #pragma mark ASIHTTPRequestDelegate - (void)objectRequestFinished:(ASIPithosObjectRequest *)request { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSLog(@"URL: %@", [request url]); - NSLog(@"cached: %d", [request didUseCachedResponse]); - - if ([request isEqualTo:applyMetadataObjectRequest]) { - int responseStatusCode = applyMetadataObjectRequest.responseStatusCode; - if (responseStatusCode != 202) - [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; - @synchronized(self) { - [applyMetadataObjectRequest release]; - applyMetadataObjectRequest = nil; - } - if (responseStatusCode == 202) - [self refreshInfo]; - } else if ([request isEqualTo:refreshMetadataObjectRequest]) { - [[pithosNodeInfoController window] makeFirstResponder:nil]; - self.pithosObject = [refreshMetadataObjectRequest object]; - @synchronized(self) { - [refreshMetadataObjectRequest release]; - refreshMetadataObjectRequest = nil; - } - } else if ([request isEqualTo:refreshVersionsObjectRequest]) { - [[pithosNodeInfoController window] makeFirstResponder:nil]; - self.versions = [refreshVersionsObjectRequest versions]; - @synchronized(self) { - [refreshVersionsObjectRequest release]; - refreshVersionsObjectRequest = nil; - } - } - [pool drain]; -} - -- (void)objectRequestFailed:(ASIPithosObjectRequest *)request { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue]; - if (retries > 0) { - ASIPithosObjectRequest *newRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:request]; - [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + @autoreleasepool { + DLog(@"URL: %@", [request url]); + DLog(@"cached: %d", [request didUseCachedResponse]); + if ([request isEqualTo:applyMetadataObjectRequest]) { + int responseStatusCode = applyMetadataObjectRequest.responseStatusCode; + if (responseStatusCode != 202) + [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { - [applyMetadataObjectRequest release]; - applyMetadataObjectRequest = newRequest; + self.applyMetadataObjectRequest = nil; } + if (responseStatusCode == 202) + [self refreshInfo]; } else if ([request isEqualTo:refreshMetadataObjectRequest]) { + [[pithosNodeInfoController window] makeFirstResponder:nil]; + self.pithosObject = [refreshMetadataObjectRequest object]; @synchronized(self) { - [refreshMetadataObjectRequest release]; - refreshMetadataObjectRequest = newRequest; + self.refreshMetadataObjectRequest = nil; } } else if ([request isEqualTo:refreshVersionsObjectRequest]) { + [[pithosNodeInfoController window] makeFirstResponder:nil]; + self.versions = [refreshVersionsObjectRequest versions]; @synchronized(self) { - [refreshVersionsObjectRequest release]; - refreshVersionsObjectRequest = newRequest; + self.refreshVersionsObjectRequest = nil; } } - [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous]; - } else { - if ([request isEqualTo:applyMetadataObjectRequest]) { - [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; - @synchronized(self) { - [applyMetadataObjectRequest release]; - applyMetadataObjectRequest = nil; - } - } else if ([request isEqualTo:refreshMetadataObjectRequest]) { - [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; - @synchronized(self) { - [refreshMetadataObjectRequest release]; - refreshMetadataObjectRequest = nil; + } +} + +- (void)objectRequestFailed:(ASIPithosObjectRequest *)request { + @autoreleasepool { + NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue]; + if (retries > 0) { + ASIPithosObjectRequest *newRequest = (ASIPithosObjectRequest *)[PithosUtilities retryWithUpdatedURLRequest:request + andPithosAccountManager:pithosAccountManager]; + [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; + if ([request isEqualTo:applyMetadataObjectRequest]) { + @synchronized(self) { + self.applyMetadataObjectRequest = newRequest; + } + } else if ([request isEqualTo:refreshMetadataObjectRequest]) { + @synchronized(self) { + self.refreshMetadataObjectRequest = newRequest; + } + } else if ([request isEqualTo:refreshVersionsObjectRequest]) { + @synchronized(self) { + self.refreshVersionsObjectRequest = newRequest; + } } - } else if ([request isEqualTo:refreshVersionsObjectRequest]) { - [PithosUtilities httpRequestErrorAlertWithRequest:refreshVersionsObjectRequest]; - @synchronized(self) { - [refreshVersionsObjectRequest release]; - refreshVersionsObjectRequest = nil; + [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous]; + } else { + if ([request isEqualTo:applyMetadataObjectRequest]) { + [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; + @synchronized(self) { + self.applyMetadataObjectRequest = nil; + } + } else if ([request isEqualTo:refreshMetadataObjectRequest]) { + [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; + @synchronized(self) { + self.refreshMetadataObjectRequest = nil; + } + } else if ([request isEqualTo:refreshVersionsObjectRequest]) { + [PithosUtilities httpRequestErrorAlertWithRequest:refreshVersionsObjectRequest]; + @synchronized(self) { + self.refreshVersionsObjectRequest = nil; + } } } } - [pool drain]; } #pragma mark - @@ -248,28 +270,146 @@ if (applyMetadataObjectRequest == nil) { [[pithosNodeInfoController window] makeFirstResponder:nil]; if (sharingAccount) { - applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithPithos:pithos - containerName:pithosContainer.name - objectName:pithosObject.name - contentEncoding:nil - contentDisposition:nil - manifest:nil - sharing:nil - isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) - metadata:pithosObject.metadata - update:NO] retain]; - [applyMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos]; + self.applyMetadataObjectRequest = [ASIPithosObjectRequest updateObjectMetadataRequestWithPithos:pithosAccountManager.pithos + containerName:pithosContainer.name + objectName:pithosObject.name + contentEncoding:nil + contentDisposition:nil + manifest:nil + sharing:nil + isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) + metadata:pithosObject.metadata + update:NO]; + [applyMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithosAccountManager.pithos]; } else { - applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithPithos:pithos - containerName:pithosContainer.name - objectName:pithosObject.name - contentEncoding:pithosObject.contentEncoding - contentDisposition:pithosObject.contentDisposition - manifest:pithosObject.manifest - sharing:(pithosObject.sharing ? pithosObject.sharing : @"") - isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) - metadata:pithosObject.metadata - update:NO] retain]; + NSMutableArray *permissions = [NSMutableArray array]; + if (translatedPermissions.count) { + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if (translatedsSharingUser.group.length && + [translatedsSharingUser.group rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@" -_~,;"]].location != NSNotFound) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Invalid Input"]; + [alert setInformativeText:@"Group names cannot contain ' ', '-', '_', '~', ',' or ';'."]; + [alert addButtonWithTitle:@"OK"]; + [alert runModal]; + return; + } + } + if (pithosAccountManager) { + NSMutableSet *allUsers = [NSMutableSet set]; + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if (translatedsSharingUser.name.length) { + [allUsers addObject:translatedsSharingUser.name]; + } + } + [allUsers removeObject:@""]; + [allUsers removeObject:@"*"]; + if (allUsers.count) { + ASIPithosRequest *userCatalogRequest = [pithosAccountManager updateUserCatalogForDisplaynames:[allUsers allObjects] + UUIDs:nil]; + if (userCatalogRequest.error || ((userCatalogRequest.responseStatusCode != 200) && (userCatalogRequest.responseStatusCode != 404))) { + return; + } else if (userCatalogRequest.responseStatusCode == 200) { + // Check if all users exist. + NSDictionary *displaynameCatalog = [userCatalogRequest displaynameCatalog]; + NSMutableArray *inexistentUsers = [NSMutableArray array]; + for (NSString *user in allUsers) { + if (![displaynameCatalog objectForKey:user]) { + [inexistentUsers addObject:user]; + } + } + if (!inexistentUsers.count) { + // Create permissions. + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if (translatedsSharingUser.name.length) { + ASIPithosSharingUser *sharingUser = [translatedsSharingUser copy]; + if (![sharingUser.name isEqualToString:@"*"]) { + sharingUser.name = [displaynameCatalog objectForKey:sharingUser.name]; + } + if (!sharingUser.permission) { + sharingUser.permission = @"read"; + } + [permissions addObject:sharingUser]; + } + } + } else { + NSAlert *alert = [[NSAlert alloc] init]; + if (inexistentUsers.count == 1) { + [alert setMessageText:@"Invalid User"]; + [alert setInformativeText:[NSString stringWithFormat:@"User '%@' doesn't exist.", [inexistentUsers objectAtIndex:0]]]; + } else { + [alert setMessageText:@"Invalid Users"]; + [alert setInformativeText:[NSString stringWithFormat:@"Users '%@' don't exist.", [inexistentUsers componentsJoinedByString:@"', '"]]]; + } + [alert addButtonWithTitle:@"OK"]; + [alert runModal]; + return; + } + } else { + // 404. Since we don't translate to UUIDs, check for invalid chars. + BOOL valid = YES; + // Create permissions. + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if (translatedsSharingUser.name.length && + ([translatedsSharingUser.name rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@" ~,;:"]].location != NSNotFound)) { + valid = NO; + break; + } + } + if (valid) { + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if (translatedsSharingUser.name.length) { + ASIPithosSharingUser *sharingUser = [translatedsSharingUser copy]; + if (!sharingUser.permission) { + sharingUser.permission = @"read"; + } + [permissions addObject:sharingUser]; + } + } + } else { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Invalid Input"]; + [alert setInformativeText:@"Users cannot contain ' ', '~', ',', ';' or ':'."]; + [alert addButtonWithTitle:@"OK"]; + [alert runModal]; + return; + } + } + } else { + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if ([translatedsSharingUser.name isEqualToString:@"*"]) { + ASIPithosSharingUser *sharingUser = [translatedsSharingUser copy]; + if (!sharingUser.permission) { + sharingUser.permission = @"read"; + } + [permissions addObject:sharingUser]; + } + } + } + } else { + for (ASIPithosSharingUser *translatedsSharingUser in translatedPermissions) { + if (translatedsSharingUser.name.length) { + ASIPithosSharingUser *sharingUser = [translatedsSharingUser copy]; + if (!sharingUser.permission) { + sharingUser.permission = @"read"; + } + [permissions addObject:sharingUser]; + } + } + } + } + pithosObject.permissions = permissions; + + self.applyMetadataObjectRequest = [ASIPithosObjectRequest updateObjectMetadataRequestWithPithos:pithosAccountManager.pithos + containerName:pithosContainer.name + objectName:pithosObject.name + contentEncoding:pithosObject.contentEncoding + contentDisposition:pithosObject.contentDisposition + manifest:pithosObject.manifest + sharing:(pithosObject.sharing ? pithosObject.sharing : @"") + isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) + metadata:pithosObject.metadata + update:NO]; } applyMetadataObjectRequest.delegate = self; applyMetadataObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); @@ -288,11 +428,11 @@ - (void)refreshInfo { @synchronized(self) { if (refreshMetadataObjectRequest == nil) { - refreshMetadataObjectRequest = [[ASIPithosObjectRequest objectMetadataRequestWithPithos:pithos - containerName:pithosContainer.name - objectName:pithosObject.name] retain]; + self.refreshMetadataObjectRequest = [ASIPithosObjectRequest objectMetadataRequestWithPithos:pithosAccountManager.pithos + containerName:pithosContainer.name + objectName:pithosObject.name]; if (sharingAccount) - [refreshMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos]; + [refreshMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithosAccountManager.pithos]; refreshMetadataObjectRequest.delegate = self; refreshMetadataObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); refreshMetadataObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); @@ -302,7 +442,8 @@ NSStringFromSelector(@selector(objectRequestFinished:)), @"didFinishSelector", NSStringFromSelector(@selector(objectRequestFailed:)), @"didFailSelector", nil]; - refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; + if (!sharingAccount) + refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } @@ -315,11 +456,11 @@ - (void)refreshVersions { @synchronized(self) { if (refreshVersionsObjectRequest == nil) { - refreshVersionsObjectRequest = [[ASIPithosObjectRequest objectVersionsRequestWithPithos:pithos - containerName:pithosContainer.name - objectName:pithosObject.name] retain]; + self.refreshVersionsObjectRequest = [ASIPithosObjectRequest objectVersionsRequestWithPithos:pithosAccountManager.pithos + containerName:pithosContainer.name + objectName:pithosObject.name]; if (sharingAccount) - [refreshVersionsObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos]; + [refreshVersionsObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithosAccountManager.pithos]; refreshVersionsObjectRequest.delegate = self; refreshVersionsObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); refreshVersionsObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); @@ -329,7 +470,8 @@ NSStringFromSelector(@selector(objectRequestFinished:)), @"didFinishSelector", NSStringFromSelector(@selector(objectRequestFailed:)), @"didFailSelector", nil]; - refreshVersionsObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; + if (!sharingAccount) + refreshVersionsObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; [[PithosUtilities prepareRequest:refreshVersionsObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } }