Improve code and fix bugs
[pithos-macos] / pithos-macos / PithosAccountNode.m
index dc670be..42a210b 100644 (file)
 #import "ASIPithosAccount.h"
 #import "ASIPithosContainer.h"
 #import "ASIDownloadCache.h"
+#import "PithosAccount.h"
 #import "PithosUtilities.h"
 #import "PithosActivityFacility.h"
 
 static NSImage *sharedIcon = nil;
 
 @implementation PithosAccountNode
-@synthesize pithos, pithosAccount;
+@synthesize pithos, pithosAccount, translatedGroups;
 
 + (void)initialize {
        if (self == [PithosAccountNode class])
@@ -72,6 +73,37 @@ static NSImage *sharedIcon = nil;
 }
 
 #pragma mark -
+#pragma mark Internal
+
+- (void)updateGroups {
+    if (!pithosAccount) {
+        self.translatedGroups = [NSMutableDictionary dictionary];
+    } else if (pithosAccountManager) {
+        NSMutableSet *UUIDs = [NSMutableSet set];
+        for (NSString *groupName in pithosAccount.groups) {
+            [UUIDs addObjectsFromArray:[pithosAccount.groups objectForKey:groupName]];
+        }
+        [UUIDs removeObject:@""];
+        [UUIDs removeObject:@"*"];
+        if (UUIDs.count) {
+            [pithosAccountManager updateUserCatalogForForDisplaynames:nil UUIDs:[UUIDs allObjects]];
+        }
+        
+        NSMutableDictionary *newTranslatedGroups = [NSMutableDictionary dictionaryWithCapacity:pithosAccount.groups.count];
+        for (NSString *groupName in pithosAccount.groups) {
+            NSMutableArray *groupUsers = [NSMutableArray array];
+            for (NSString *UUID in [pithosAccount.groups objectForKey:groupName]) {
+                [groupUsers addObject:[pithosAccountManager displaynameForUUID:UUID safe:YES]];
+            }
+            [newTranslatedGroups setObject:groupUsers forKey:groupName];
+        }
+        self.translatedGroups = newTranslatedGroups;
+    } else {
+        self.translatedGroups = [pithosAccount.groups copy];
+    }
+}
+
+#pragma mark -
 #pragma mark Properties
 
 - (void)setPithos:(ASIPithos *)aPithos {
@@ -88,6 +120,13 @@ static NSImage *sharedIcon = nil;
     }
 }
 
+- (void)setPithosAccount:(ASIPithosAccount *)aPithosAccount {
+    if (![pithosAccount isEqualTo:aPithosAccount]) {
+        pithosAccount = aPithosAccount;
+        [self updateGroups];
+    }
+}
+
 - (NSString *)url {
     if (url == nil)
         url = [[NSString alloc] initWithFormat:@"%@%@", 
@@ -154,8 +193,15 @@ static NSImage *sharedIcon = nil;
 }
 
 - (NSString *)displayName {
-    if (displayName == nil)
-        return [NSString stringWithString:(sharingAccount ? sharingAccount : @"account")];
+    if (displayName == nil) {
+        if (!sharingAccount) {
+            return @"account";
+        } else if (pithosAccountManager) {
+            return [pithosAccountManager displaynameForUUID:sharingAccount safe:YES];
+        } else {
+            return [sharingAccount copy];
+        }
+    }
     return [displayName copy];
 }
 
@@ -189,7 +235,6 @@ static NSImage *sharedIcon = nil;
         } else {
             newChildren = nil;
             accountRequest = nil;
-            containers = nil;
             forcedRefresh = NO;
             @synchronized(self) {
                 freshness = PithosNodeStateRefreshNeeded;
@@ -205,9 +250,10 @@ static NSImage *sharedIcon = nil;
         if (accountRequest.responseStatusCode == 200) {
             self.pithosAccount = [accountRequest account];
             
+            NSMutableArray *containers = [accountRequest.userInfo objectForKey:@"containers"];
             NSArray *someContainers = [accountRequest containers];
             if (containers == nil) {
-                containers = [[NSMutableArray alloc] initWithArray:someContainers];
+                containers = [NSMutableArray arrayWithArray:someContainers];
             } else {
                 [containers addObjectsFromArray:someContainers];
             }
@@ -223,6 +269,7 @@ static NSImage *sharedIcon = nil;
                         node.shared = shared;
                         node.sharingAccount = sharingAccount;
                         node.inheritChildrenUpdatedNotificationName = inheritChildrenUpdatedNotificationName;
+                        node.pithosAccountManager = pithosAccountManager;
                         if (children) {
                             NSUInteger oldIndex = [children indexOfObject:node];
                             if (oldIndex != NSNotFound) {
@@ -244,7 +291,6 @@ static NSImage *sharedIcon = nil;
                 }
                 // Else cache was used and all results were fetched during this request, so existing children can be reused
                 accountRequest = nil;
-                containers = nil;
                 forcedRefresh = NO;
                 @synchronized(self) {
                     freshness = PithosNodeStateRefreshFinished;
@@ -268,14 +314,14 @@ static NSImage *sharedIcon = nil;
                                            [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
                                            [NSNumber numberWithUnsignedInteger:10], @"retries", 
                                            NSStringFromSelector(@selector(accountRequestFinished:)), @"didFinishSelector", 
-                                           NSStringFromSelector(@selector(accountRequestFailed:)), @"didFailSelector", 
+                                           NSStringFromSelector(@selector(accountRequestFailed:)), @"didFailSelector",
+                                           containers, @"containers",
                                            nil];
                 [[PithosUtilities prepareRequest:accountRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
             }
         } else if (accountRequest.responseStatusCode == 304) {
             // Account is not modified, so existing children can be reused
             accountRequest = nil;
-            containers = nil;
             forcedRefresh = NO;
             @synchronized(self) {
                 freshness = PithosNodeStateRefreshFinished;
@@ -344,10 +390,101 @@ static NSImage *sharedIcon = nil;
 - (void)applyInfo {
     @synchronized(self) {
         if (applyMetadataAccountRequest == nil) {
-            NSMutableDictionary *groups = pithosAccount.groups;
-            if ([groups count] == 0)
-                groups = [NSMutableDictionary dictionaryWithObject:@"" forKey:@"group"];
-            applyMetadataAccountRequest = [ASIPithosAccountRequest updateAccountMetadataRequestWithPithos:pithos 
+            NSMutableDictionary *groups = [NSMutableDictionary dictionary];
+            if (translatedGroups.count) {
+                for (NSString *groupName in translatedGroups) {
+                    if (!groupName.length ||
+                        [groupName rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@" -_~,;"]].location != NSNotFound) {
+                        NSAlert *alert = [[NSAlert alloc] init];
+                        [alert setMessageText:@"Invalid Input"];
+                        [alert setInformativeText:@"Group names cannot be empty or contain ' ', '-', '_', '~', ',' or ';'."];
+                        [alert addButtonWithTitle:@"OK"];
+                        [alert runModal];
+                        return;
+                    }
+                }
+                if (pithosAccountManager) {
+                    NSMutableSet *allGroupUsers = [NSMutableSet set];
+                    for (NSMutableArray *groupUsers in [translatedGroups objectEnumerator]) {
+                        [allGroupUsers addObjectsFromArray:groupUsers];
+                    }
+                    [allGroupUsers removeObject:@""];
+                    [allGroupUsers removeObject:@"*"];
+                    if (allGroupUsers.count) {
+                        ASIPithosRequest *userCatalogRequest = [pithosAccountManager updateUserCatalogForForDisplaynames:[allGroupUsers 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 *inexistentGroupUsers = [NSMutableArray array];
+                            for (NSString *groupUser in allGroupUsers) {
+                                if (![displaynameCatalog objectForKey:groupUser]) {
+                                    [inexistentGroupUsers addObject:groupUser];
+                                }
+                            }
+                            if (!inexistentGroupUsers.count) {
+                                // Create groups.
+                                for (NSString *groupName in translatedGroups) {
+                                    NSMutableArray *groupUsers = [NSMutableArray array];
+                                    for (NSString *groupUser in [translatedGroups objectForKey:groupName]) {
+                                        [groupUsers addObject:([groupUser isEqualToString:@"*"] ?
+                                                               @"*" : [displaynameCatalog objectForKey:groupUser])];
+                                    }
+                                    [groups setObject:groupUsers forKey:groupName];
+                                }
+                            } else {
+                                NSAlert *alert = [[NSAlert alloc] init];
+                                if (inexistentGroupUsers.count == 1) {
+                                    [alert setMessageText:@"Invalid User"];
+                                    [alert setInformativeText:[NSString stringWithFormat:@"User '%@' doesn't exist.", [inexistentGroupUsers objectAtIndex:0]]];
+                                } else {
+                                    [alert setMessageText:@"Invalid Users"];
+                                    [alert setInformativeText:[NSString stringWithFormat:@"Users '%@' don't exist.", [inexistentGroupUsers componentsJoinedByString:@"', '"]]];
+                                }
+                                [alert addButtonWithTitle:@"OK"];
+                                [alert runModal];
+                                return;
+                            }
+                        } else {
+                            // 404. Since we don't translate to UUIDs, check for invalid chars.
+                            BOOL valid = YES;
+                            for (NSString *groupUser in allGroupUsers) {
+                                if ([groupUser rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@" ~,;:"]].location != NSNotFound) {
+                                    valid = NO;
+                                    break;
+                                }
+                            }
+                            if (valid) {
+                                [groups addEntriesFromDictionary:translatedGroups];
+                            } else {
+                                NSAlert *alert = [[NSAlert alloc] init];
+                                [alert setMessageText:@"Invalid Input"];
+                                [alert setInformativeText:@"Users cannot contain ' ', '~', ',', ';' or ':'."];
+                                [alert addButtonWithTitle:@"OK"];
+                                [alert runModal];
+                                return;
+                            }
+                        }
+                    } else {
+                        for (NSString *groupName in translatedGroups) {
+                            if ([[translatedGroups objectForKey:groupName] containsObject:@"*"]) {
+                                [groups setObject:[NSMutableArray arrayWithObject:@"*"] forKey:groupName];
+                            }
+                        }
+                        if (!groups.count) {
+                            [groups setObject:[NSArray arrayWithObject:@""] forKey:@"group"];
+                        }
+                    }
+                } else {
+                    [groups addEntriesFromDictionary:translatedGroups];
+                }
+            } else {
+                [groups setObject:[NSArray arrayWithObject:@""] forKey:@"group"];
+            }
+            
+            applyMetadataAccountRequest = [ASIPithosAccountRequest updateAccountMetadataRequestWithPithos:pithos
                                                                                                     groups:groups 
                                                                                                   metadata:pithosAccount.metadata 
                                                                                                     update:NO];