diff options
author | mltownsend <mltownsend@gmail.com> | 2009-08-11 17:00:46 +0000 |
---|---|---|
committer | mltownsend <mltownsend@gmail.com> | 2009-08-11 17:00:46 +0000 |
commit | 80f757d7f217ae836f6c8de60134bc2a5d005687 (patch) | |
tree | 6969e36a3bd1f63227d67d2f2bdb224c36b1aeed /Source | |
parent | f6afd1e9699b891f1deee9058a1737e8c5744bd7 (diff) | |
download | sequelpro-80f757d7f217ae836f6c8de60134bc2a5d005687.tar.gz sequelpro-80f757d7f217ae836f6c8de60134bc2a5d005687.tar.bz2 sequelpro-80f757d7f217ae836f6c8de60134bc2a5d005687.zip |
User Manager feature
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPArrayAdditions.h | 1 | ||||
-rw-r--r-- | Source/SPArrayAdditions.m | 15 | ||||
-rw-r--r-- | Source/SPStringAdditions.h | 2 | ||||
-rw-r--r-- | Source/SPStringAdditions.m | 36 | ||||
-rw-r--r-- | Source/SPUserMO.h | 41 | ||||
-rw-r--r-- | Source/SPUserMO.m | 72 | ||||
-rw-r--r-- | Source/SPUserManager.h | 73 | ||||
-rw-r--r-- | Source/SPUserManager.m | 680 | ||||
-rw-r--r-- | Source/SPUserManager.xcdatamodel/elements | bin | 0 -> 50142 bytes | |||
-rw-r--r-- | Source/SPUserManager.xcdatamodel/layout | bin | 0 -> 5707 bytes | |||
-rw-r--r-- | Source/TableDocument.h | 4 | ||||
-rw-r--r-- | Source/TableDocument.m | 23 |
12 files changed, 945 insertions, 2 deletions
diff --git a/Source/SPArrayAdditions.h b/Source/SPArrayAdditions.h index 45b81e03..473740fc 100644 --- a/Source/SPArrayAdditions.h +++ b/Source/SPArrayAdditions.h @@ -31,6 +31,7 @@ static inline id NSArrayObjectAtIndex(NSArray* self, NSUInteger i) { @interface NSArray (SPArrayAdditions) - (NSString *)componentsJoinedAndBacktickQuoted; +- (NSString *)componentsJoinedByCommas; - (NSArray *)subarrayWithIndexes:(NSIndexSet *)indexes; @end diff --git a/Source/SPArrayAdditions.m b/Source/SPArrayAdditions.m index 853421e0..37b1ba62 100644 --- a/Source/SPArrayAdditions.m +++ b/Source/SPArrayAdditions.m @@ -42,6 +42,21 @@ return result; } +- (NSString *)componentsJoinedByCommas +{ + NSString *result = [NSString string]; + for (NSString *component in self) + { + if ([result length]) + { + result = [result stringByAppendingString:@","]; + } + + result = [result stringByAppendingString:component]; + } + return result; +} + - (NSArray *)subarrayWithIndexes:(NSIndexSet *)indexes { NSMutableArray *subArray = [NSMutableArray arrayWithCapacity:[indexes count]]; diff --git a/Source/SPStringAdditions.h b/Source/SPStringAdditions.h index 764e6b24..6ee941c2 100644 --- a/Source/SPStringAdditions.h +++ b/Source/SPStringAdditions.h @@ -44,6 +44,8 @@ static inline const char* NSStringUTF8String(NSString* self) { + (NSString *)stringForTimeInterval:(float)timeInterval; - (NSString *)backtickQuotedString; +- (NSString *)tickQuotedString; +- (NSString *)replaceUnderscoreWithSpace; - (NSArray *)lineRangesForRange:(NSRange)aRange; - (NSString *)createViewSyntaxPrettifier; diff --git a/Source/SPStringAdditions.m b/Source/SPStringAdditions.m index 81c501f9..5ddc14f3 100644 --- a/Source/SPStringAdditions.m +++ b/Source/SPStringAdditions.m @@ -163,6 +163,42 @@ return quotedString; } +// ------------------------------------------------------------------------------- +// tickQuotedString +// +// Returns the string quoted with ticks as required for MySQL identifiers +// eg.: tablename => 'tablename' +// my'table => 'my''table' +// ------------------------------------------------------------------------------- +- (NSString *)tickQuotedString +{ + // mutableCopy automatically retains the returned string, so don't forget to release it later... + NSMutableString *workingCopy = [self mutableCopy]; + + // First double all backticks in the string to escape them + // I don't want to use "stringByReplacingOccurrencesOfString:withString:" because it's only available in 10.5 + [workingCopy replaceOccurrencesOfString: @"'" + withString: @"''" + options: NSLiteralSearch + range: NSMakeRange(0, [workingCopy length]) ]; + + // Add the quotes around the string + NSString *quotedString = [NSString stringWithFormat: @"'%@'", workingCopy]; + + [workingCopy release]; + + return quotedString; +} + +- (NSString *)replaceUnderscoreWithSpace +{ + NSMutableString *workingCopy = [self mutableCopy]; + [workingCopy replaceOccurrencesOfString:@"_" + withString:@" " + options:NSLiteralSearch + range:NSMakeRange(0, [workingCopy length])]; + return [workingCopy autorelease]; +} // ------------------------------------------------------------------------------- // createViewSyntaxPrettifier diff --git a/Source/SPUserMO.h b/Source/SPUserMO.h new file mode 100644 index 00000000..13837921 --- /dev/null +++ b/Source/SPUserMO.h @@ -0,0 +1,41 @@ +// +// $Id: SPUserMO.h 856 2009-06-12 05:31:39Z mltownsend $ +// +// SPUserMO.h +// sequel-pro +// +// Created by Mark Townsend on Jan 01, 2009 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// More info at <http://code.google.com/p/sequel-pro/> + +#import <CoreData/CoreData.h> + +@interface NSManagedObject (CoreDataGeneratedAccessors) + +@property(nonatomic, retain) NSString *user; +@property(nonatomic, retain) NSString *host; +@property(nonatomic, retain) NSManagedObject *parent; +@property (nonatomic, retain) NSSet *children; + +- (NSString *)displayName; +- (void)setDisplayName:(NSString *)value; + +// Access to-many relationship via -[NSObject mutableSetValueForKey:] +- (void)addChildrenObject:(NSManagedObject *)value; +- (void)removeChildrenObject:(NSManagedObject *)value; + +@end
\ No newline at end of file diff --git a/Source/SPUserMO.m b/Source/SPUserMO.m new file mode 100644 index 00000000..05d699ae --- /dev/null +++ b/Source/SPUserMO.m @@ -0,0 +1,72 @@ +// +// $Id: SPUserMO.m 856 2009-06-12 05:31:39Z mltownsend $ +// +// SPUserMO.m +// sequel-pro +// +// Created by Mark Townsend on Jan 01, 2009 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// More info at <http://code.google.com/p/sequel-pro/> + +#import "SPUserMO.h" + +@implementation NSManagedObject (CoreDataGeneratedAccessors) + +@dynamic user, host; +@dynamic parent; +@dynamic children; + +- (NSString *)displayName +{ + if ([self valueForKey:@"parent"] == nil) { + return self.user; + } else { + return self.host; + } +} + +- (void)setDisplayName:(NSString *)value +{ + [self setValue:value forKey:@"host"]; +} + +- (void)addChildrenObject:(NSManagedObject *)value +{ + NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1]; + + [self willChangeValueForKey:@"children" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects]; + [[self primitiveValueForKey:@"children"] addObject:value]; + [self didChangeValueForKey:@"children" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects]; + + [changedObjects release]; + value.user = self.user; +} + +- (void)removeChildrenObject:(NSManagedObject *)value +{ + NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1]; + + [self willChangeValueForKey:@"children" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects]; + [[self primitiveValueForKey:@"children"] removeObject:value]; + [self didChangeValueForKey:@"children" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects]; + + [changedObjects release]; +} +@end + + + diff --git a/Source/SPUserManager.h b/Source/SPUserManager.h new file mode 100644 index 00000000..febeb472 --- /dev/null +++ b/Source/SPUserManager.h @@ -0,0 +1,73 @@ +// +// $Id: SPUserManager.h 856 2009-06-12 05:31:39Z mltownsend $ +// +// SPUserManager.h +// sequel-pro +// +// Created by Mark Townsend on Jan 01, 2009 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// More info at <http://code.google.com/p/sequel-pro/> + +#import <Cocoa/Cocoa.h> + +@class MCPConnection; + +@interface SPUserManager : NSObject { + + NSPersistentStoreCoordinator *persistentStoreCoordinator; + NSManagedObjectModel *managedObjectModel; + NSManagedObjectContext *managedObjectContext; + NSDictionary *privColumnsMODict; + + BOOL isInitializing; + + MCPConnection* mySqlConnection; + + IBOutlet NSOutlineView* outlineView; + IBOutlet NSTabView *tabView; + IBOutlet NSTreeController *treeController; + IBOutlet NSWindow *window; + IBOutlet NSPanel *addHostSheet; +} + +- (NSPersistentStoreCoordinator *)persistentStoreCoordinator; +- (NSManagedObjectModel *)managedObjectModel; +- (NSManagedObjectContext *)managedObjectContext; + +- (id)initWithConnection:(MCPConnection *)connection; +- (void)setConnection:(MCPConnection *)connection; +- (MCPConnection *)connection; +- (void)show; +- (void)initializeChild:(NSManagedObject *)child withItem:(NSDictionary *)item; + +// Add/Remove Users +- (IBAction)addUser:(id)sender; +- (IBAction)removeUser:(id)sender; +- (IBAction)addHost:(id)sender; +- (IBAction)removeHost:(id)sender; + +// General +- (IBAction)doCancel:(id)sender; +- (IBAction)doApply:(id)sender; + +// Core Data Notifications +- (void)contextDidSave:(NSNotification *)notification; +- (BOOL)insertUsers:(NSArray *)insertedUsers; +- (BOOL)deleteUsers:(NSArray *)deletedUsers; +- (BOOL)updateUsers:(NSArray *)updatedUsers; +- (BOOL)grantPrivilegesToUser:(NSManagedObject *)user; +@end diff --git a/Source/SPUserManager.m b/Source/SPUserManager.m new file mode 100644 index 00000000..9ef3e8ba --- /dev/null +++ b/Source/SPUserManager.m @@ -0,0 +1,680 @@ +// +// $Id: SPUserManager.m 856 2009-06-12 05:31:39Z mltownsend $ +// +// SPUserManager.m +// sequel-pro +// +// Created by Mark Townsend on Jan 01, 2009 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// More info at <http://code.google.com/p/sequel-pro/> + +#import "SPUserManager.h" +#import "MCPConnection.h" +#import "SPUserMO.h" +#import "MCPResult.h" +#import "ImageAndTextCell.h" +#import "SPArrayAdditions.h" +#import "SPStringAdditions.h" + +#define COLUMNIDNAME @"NameColumn" + +@interface SPUserManager (PrivateMethods) +- (void)_initializeTree:(NSArray *)items; +- (void)_initializeUsers; +- (void)_selectParentFromSelection; +- (NSArray *)_fetchUserWithUserName:(NSString *)username; +- (NSManagedObject *)_createNewSPUser; +- (BOOL)checkAndDisplayMySqlError; +- (void)_clearData; +@end + +@implementation SPUserManager + +- (id)init +{ + [self dealloc]; + @throw [NSException exceptionWithName:@"BadInitCall" reason:@"Can't call init here" userInfo:nil]; + return nil; +} + +- (id)initWithConnection:(MCPConnection*) connection +{ + if (![super init]) { + return nil; + } + + [self setConnection:connection]; + + + privColumnsMODict = [[[NSDictionary alloc] initWithObjectsAndKeys: + @"grant_option_priv",@"Grant_priv", + @"show_databases_priv",@"Show_db_priv", + @"create_temporary_table_priv",@"Create_tmp_table_priv", + @"Replication_slave_priv",@"Repl_slave_priv", + @"Replication_client_priv",@"Repl_client_priv",nil] retain]; + + if (!outlineView) { + [NSBundle loadNibNamed:@"UserManagerView" owner:self]; + } + + return self; +} + +- (void)dealloc +{ + NSLog(@"SPUserManager dealloc."); + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [managedObjectContext release], managedObjectContext = nil; + [persistentStoreCoordinator release], persistentStoreCoordinator = nil; + [managedObjectModel release], managedObjectModel = nil; + [privColumnsMODict release], privColumnsMODict = nil; + + [mySqlConnection release]; + [super dealloc]; +} + +- (void)awakeFromNib +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contextDidSave:) + name:NSManagedObjectContextDidSaveNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contextDidChange:) + name:NSManagedObjectContextObjectsDidChangeNotification + object:nil]; + [tabView selectTabViewItemAtIndex:0]; + + NSTableColumn *tableColumn = [outlineView tableColumnWithIdentifier:COLUMNIDNAME]; + ImageAndTextCell *imageAndTextCell = [[[ImageAndTextCell alloc] init] autorelease]; + + [imageAndTextCell setEditable:NO]; + [tableColumn setDataCell:imageAndTextCell]; + + [NSThread detachNewThreadSelector:@selector(_initializeUsers) toTarget:self withObject:nil]; +} + +- (void)_initializeUsers +{ + isInitializing = TRUE; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSMutableArray *resultAsArray = [NSMutableArray array]; + NSMutableArray *usersResultArray = [NSMutableArray array]; + + [[self connection] selectDB:@"mysql"]; + MCPResult *result = [[[self connection] queryString:@"select * from user order by user"] retain]; + int rows = [result numOfRows]; + if (rows > 0) + { + // Go to the beginning + [result dataSeek:0]; + } + + for(int i = 0; i < rows; i++) + { + [resultAsArray addObject:[result fetchRowAsDictionary]]; + } + + [usersResultArray addObjectsFromArray:resultAsArray]; + + [self _initializeTree:usersResultArray]; + + [result release]; + [pool release]; + isInitializing = FALSE; +} + +- (void)_initializeTree:(NSArray *)items +{ + + for(int i = 0; i < [items count]; i++) + { + NSString *username = [[items objectAtIndex:i] objectForKey:@"User"]; + NSArray *array = [[self _fetchUserWithUserName:username] retain]; + NSDictionary *item = [items objectAtIndex:i]; + + if (array != nil && [array count] > 0) + { + // Add Children + NSManagedObject *parent = [array objectAtIndex:0]; + NSManagedObject *child = [self _createNewSPUser]; + [child setParent:parent]; + [parent addChildrenObject:child]; + + [self initializeChild:child withItem:item]; + + } else { + // Add Parent + NSManagedObject *parent = [self _createNewSPUser]; + NSManagedObject *child = [self _createNewSPUser]; + + [parent setValue:username forKey:@"user"]; + [parent setValue:[item objectForKey:@"Password"] forKey:@"password"]; + [parent addChildrenObject:child]; + [child setParent:parent]; + + [self initializeChild:child withItem:item]; + } + // Save the initialized objects so that any new changes will be tracked. + NSError *error = nil; + [[self managedObjectContext] save:&error]; + if (error != nil) + { + [[NSApplication sharedApplication] presentError:error]; + } + [array release]; + } +} + +- (void)initializeChild:(NSManagedObject *)child withItem:(NSDictionary *)item +{ + for (NSString *key in item) + { + NS_DURING + if ([key hasSuffix:@"_priv"]) + { + // Special case keys + if ([privColumnsMODict objectForKey:key] != nil) + { + key = [privColumnsMODict objectForKey:key]; + } + + BOOL value = [[item objectForKey:key] boolValue]; + [child setValue:[NSNumber numberWithBool:value] forKey:key]; + } + else if ([key hasPrefix:@"max"]) + { + NSNumber *value = [NSNumber numberWithInt:[[item objectForKey:key] intValue]]; + [child setValue:value forKey:key]; + } + else if (![key isEqualToString:@"User"] && ![key isEqualToString:@"Password"]) + { + NSString *value = [item objectForKey:key]; + [child setValue:value forKey:key]; + } + NS_HANDLER + NSLog(@"%@ not implemented yet.", key); + NS_ENDHANDLER + } + +} + +/** + Creates, retains, and returns the managed object model for the application + by merging all of the models found in the application bundle. + */ + +- (NSManagedObjectModel *)managedObjectModel { + + if (managedObjectModel != nil) { + return managedObjectModel; + } + + managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; + return managedObjectModel; +} + +/** + Returns the persistent store coordinator for the application. This + implementation will create and return a coordinator, having added the + store for the application to it. (The folder for the store is created, + if necessary.) + */ + +- (NSPersistentStoreCoordinator *) persistentStoreCoordinator { + + if (persistentStoreCoordinator != nil) { + return persistentStoreCoordinator; + } + + NSError *error; + + persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; + if (![persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&error]) + { + [[NSApplication sharedApplication] presentError:error]; + } + + return persistentStoreCoordinator; +} + +/** + Returns the managed object context for the application (which is already + bound to the persistent store coordinator for the application.) + */ + +- (NSManagedObjectContext *) managedObjectContext { + + if (managedObjectContext != nil) { + return managedObjectContext; + } + + NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; + if (coordinator != nil) { + managedObjectContext = [[NSManagedObjectContext alloc] init]; + [managedObjectContext setPersistentStoreCoordinator: coordinator]; + } + + return managedObjectContext; +} + +- (void)setConnection:(MCPConnection *)connection +{ + [connection retain]; + [mySqlConnection release]; + mySqlConnection = connection; +} + +- (MCPConnection* )connection +{ + return mySqlConnection; +} + +- (void)show +{ +// [NSThread detachNewThreadSelector:@selector(_initializeUsers) toTarget:self withObject:nil]; + [window makeKeyAndOrderFront:nil]; +} + +#pragma mark - +#pragma mark OutlineView Delegate Methods +- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + if ([cell isKindOfClass:[ImageAndTextCell class]]) + { + if ([(NSManagedObject *)[item representedObject] parent] != nil) + { + NSImage *image1 = [[NSImage imageNamed:NSImageNameNetwork] retain]; + [image1 setScalesWhenResized:YES]; + [image1 setSize:(NSSize){16,16}]; + [(ImageAndTextCell*)cell setImage:image1]; + [image1 release]; + + } + else + { + NSImage *image1 = [[NSImage imageNamed:NSImageNameUser] retain]; + [image1 setScalesWhenResized:YES]; + [image1 setSize:(NSSize){16,16}]; + [(ImageAndTextCell*)cell setImage:image1]; + [image1 release]; + } + } +} + +- (BOOL)outlineView:(NSOutlineView *)olv isGroupItem:(id)item +{ + return FALSE; +} + +- (BOOL)outlineView:(NSOutlineView *)olv shouldSelectItem:(id)item +{ + return TRUE; +} + +- (BOOL)outlineView:(NSOutlineView *)olv shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + if ([[[item representedObject] children] count] == 0) + { + return TRUE; + } + return FALSE; + +} + +- (void)outlineViewSelectionDidChange:(NSNotification *)notification +{ + id selectedObject = [[treeController selectedObjects] objectAtIndex:0]; + if ([selectedObject parent] == nil && !([[[tabView selectedTabViewItem] identifier] isEqualToString:@"General"])) + { + [tabView selectTabViewItemWithIdentifier:@"General"]; + } + else + { + if ([[[tabView selectedTabViewItem] identifier] isEqualToString:@"General"]) + { + [tabView selectTabViewItemWithIdentifier:@"Global Privileges"]; + } + } +} + +// General Action Methods +- (IBAction)doCancel:(id)sender +{ + [[self managedObjectContext] rollback]; + [window close]; +} + +- (IBAction)doApply:(id)sender +{ + NSError *error = nil; + [[self managedObjectContext] save:&error]; + if (error != nil) + { + [[NSApplication sharedApplication] presentError:error]; + } + else + { + [window close]; + } +// [self _clearData]; +} + +- (IBAction)addUser:(id)sender +{ + if ([[treeController selectedObjects] count] > 0) + { + if ([[[treeController selectedObjects] objectAtIndex:0] parent] != nil) + { + [self _selectParentFromSelection]; + } + } + NSManagedObject *newItem = [self _createNewSPUser]; + NSManagedObject *newChild = [self _createNewSPUser]; + [newChild setValue:@"localhost" forKey:@"host"]; + [newItem addChildrenObject:newChild]; + + [treeController addObject:newItem]; + [outlineView expandItem:[outlineView itemAtRow:[outlineView selectedRow]]]; +} + +- (IBAction)removeUser:(id)sender +{ + [treeController remove:sender]; +} + +- (IBAction)addHost:(id)sender +{ + if ([[treeController selectedObjects] count] > 0) + { + if ([[[treeController selectedObjects] objectAtIndex:0] parent] != nil) + { + [self _selectParentFromSelection]; + } + } + [treeController addChild:sender]; + // Need to figure out how to do this right. I want to be able to have the newly + // added item be in edit mode to change the host name. +// [outlineView editColumn:0 row:[outlineView selectedRow] withEvent:nil select:TRUE]; +} + +- (IBAction)removeHost:(id)sender +{ + [treeController remove:sender]; +} + + +- (void)_clearData +{ + [managedObjectContext reset]; + [managedObjectContext release]; + managedObjectContext = nil; +} + +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem +{ + if ([menuItem action] == @selector(addHost:) || + [menuItem action] == @selector(removeHost:)) + { + return (([[treeController selectedObjects] count] > 0) && + [[[treeController selectedObjects] objectAtIndex:0] parent] != nil); + } + return TRUE; +} + +- (void)_selectParentFromSelection +{ + if ([[treeController selectedObjects] count] > 0) + { + NSTreeNode *firstSelectedNode = [[treeController selectedNodes] objectAtIndex:0]; + NSTreeNode *parentNode = [firstSelectedNode parentNode]; + if (parentNode) + { + NSIndexPath *parentIndex = [parentNode indexPath]; + [treeController setSelectionIndexPath:parentIndex]; + } + else + { + NSArray *selectedIndexPaths = [treeController selectionIndexPaths]; + [treeController removeSelectionIndexPaths:selectedIndexPaths]; + } + } +} + +#pragma mark - +#pragma mark Notifications +- (void)contextDidSave:(NSNotification *)notification +{ + if (!isInitializing) + { + NSArray *updated = [[notification userInfo] valueForKey:NSUpdatedObjectsKey]; + NSArray *inserted = [[notification userInfo] valueForKey:NSInsertedObjectsKey]; + NSArray *deleted = [[notification userInfo] valueForKey:NSDeletedObjectsKey]; + + if ([inserted count] > 0) + { + [self insertUsers:inserted]; + } + + if ([updated count] > 0) + { + [self updateUsers:updated]; + } + + if ([deleted count] > 0) + { + [self deleteUsers:deleted]; + } + } +} + +- (void)contextDidChange:(NSNotification *)notification +{ + NSLog(@"contextDidChange:"); + + if (!isInitializing) + { + [outlineView reloadData]; + } +} + +- (BOOL)updateUsers:(NSArray *)updatedUsers +{ + for (NSManagedObject *user in updatedUsers) { + [self grantPrivilegesToUser:user]; + } + return TRUE; +} + +- (BOOL)deleteUsers:(NSArray *)deletedUsers +{ + [[self connection] selectDB:@"mysql"]; + NSMutableString *droppedUsers = [NSMutableString string]; + for (NSManagedObject *user in deletedUsers) + { + if ([user host] != nil) + { + [droppedUsers appendString:[NSString stringWithFormat:@"%@@%@, ", + [[user valueForKey:@"user"] backtickQuotedString], + [[user valueForKey:@"host"] backtickQuotedString]]]; + } + + } + droppedUsers = [[droppedUsers substringToIndex:[droppedUsers length]-2] mutableCopy]; + [[self connection] queryString:[NSString stringWithFormat:@"DROP USER %@", droppedUsers]]; + + return TRUE; +} + +- (BOOL)insertUsers:(NSArray *)insertedUsers +{ + [[self connection] selectDB:@"mysql"]; + for(NSManagedObject *user in insertedUsers) + { + NSString *createStatement = [NSString stringWithFormat:@"CREATE USER %@@%@ IDENTIFIED BY %@;", + [[[user parent] valueForKey:@"user"] tickQuotedString], + [[user valueForKey:@"host"] tickQuotedString], + [[[user parent] valueForKey:@"password"] tickQuotedString]]; + // Create user in database + [[self connection] queryString:[NSString stringWithFormat:createStatement]]; + + if ([self checkAndDisplayMySqlError]) + { + [self grantPrivilegesToUser:user]; + } + } + + return TRUE; + +} + +// Grant or Revoke privileges to the given user +- (BOOL)grantPrivilegesToUser:(NSManagedObject *)user +{ + if ([user valueForKey:@"parent"] != nil) + { + NSDictionary *attributesDict = [[user entity] attributesByName]; + NSMutableArray *grantPrivileges = [NSMutableArray array]; + NSMutableArray *revokePrivileges = [NSMutableArray array]; + + for(NSString *key in [attributesDict allKeys]) + { + if ([key hasSuffix:@"_priv"]) + { + NSString *privilege = [key stringByReplacingOccurrencesOfString:@"_priv" withString:@""]; + + if ([[user valueForKey:key] boolValue] == TRUE) + { + [grantPrivileges addObject:[NSString stringWithFormat:@"%@", [privilege replaceUnderscoreWithSpace]]]; + } + else + { + [revokePrivileges addObject:[NSString stringWithFormat:@"%@", [privilege replaceUnderscoreWithSpace]]]; + } + } + } + // Grant privileges + if ([grantPrivileges count] > 0) + { + NSString *grantStatement = [NSString stringWithFormat:@"GRANT %@ ON *.* TO %@@%@;", + [grantPrivileges componentsJoinedByCommas], + [[[user parent] valueForKey:@"user"] tickQuotedString], + [[user valueForKey:@"host"] tickQuotedString]]; + NSLog(@"%@", grantStatement); + [[self connection] queryString:[NSString stringWithFormat:grantStatement]]; + [self checkAndDisplayMySqlError]; + } + + // Revoke privileges + if ([revokePrivileges count] > 0) + { + NSString *revokeStatement = [NSString stringWithFormat:@"REVOKE %@ ON *.* TO %@@%@;", + [revokePrivileges componentsJoinedByCommas], + [[[user parent] valueForKey:@"user"] tickQuotedString], + [[user valueForKey:@"host"] tickQuotedString]]; + NSLog(@"%@", revokeStatement); + [[self connection] queryString:[NSString stringWithFormat:revokeStatement]]; + [self checkAndDisplayMySqlError]; + } + } + return TRUE; +} +- (NSArray *)_fetchUserWithUserName:(NSString *)username +{ + NSManagedObjectContext *moc = [self managedObjectContext]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user == %@ AND parent == nil", username]; + NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"SPUser" + inManagedObjectContext:moc]; + NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; + + [request setEntity:entityDescription]; + [request setPredicate:predicate]; + + NSError *error = nil; + NSArray *array = [moc executeFetchRequest:request error:&error]; + if (error != nil) + { + [[NSApplication sharedApplication] presentError:error]; + } + + return array; +} + +- (NSManagedObject *)_createNewSPUser +{ + NSManagedObject *user = [[NSEntityDescription insertNewObjectForEntityForName:@"SPUser" + inManagedObjectContext:[self managedObjectContext]] autorelease]; + + return user; +} + +- (BOOL)checkAndDisplayMySqlError +{ + if (![[[self connection] getLastErrorMessage] isEqualToString:@""]) + { + NSBeginAlertSheet(@"MySQL Error", + nil, + nil, + nil, + window, + self, + NULL, + NULL, + nil, + [[self connection] getLastErrorMessage]); + return FALSE; + } else { + return TRUE; + } +} + +#pragma mark - +#pragma mark Tab View Delegate methods +- (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem +{ + if ([[treeController selectedObjects] count] == 0) + return FALSE; + + id selectedObject = [[treeController selectedObjects] objectAtIndex:0]; + if ([[tabViewItem identifier] isEqualToString:@"General"]) + { + if ([selectedObject parent] == nil) { + return TRUE; + } else { + return FALSE; + } + } + else if ([[tabViewItem identifier] isEqualToString:@"Global Privileges"] || + [[tabViewItem identifier] isEqualToString:@"Resources"]) + { + if ([selectedObject parent] != nil) + { + return TRUE; + } + else + { + return FALSE; + } + } + + return TRUE; +} +@end diff --git a/Source/SPUserManager.xcdatamodel/elements b/Source/SPUserManager.xcdatamodel/elements Binary files differnew file mode 100644 index 00000000..6766bed3 --- /dev/null +++ b/Source/SPUserManager.xcdatamodel/elements diff --git a/Source/SPUserManager.xcdatamodel/layout b/Source/SPUserManager.xcdatamodel/layout Binary files differnew file mode 100644 index 00000000..07b18bfd --- /dev/null +++ b/Source/SPUserManager.xcdatamodel/layout diff --git a/Source/TableDocument.h b/Source/TableDocument.h index 42be9e5a..480ef810 100644 --- a/Source/TableDocument.h +++ b/Source/TableDocument.h @@ -53,6 +53,8 @@ enum { IBOutlet id databaseDataInstance; IBOutlet id spHistoryControllerInstance; IBOutlet id spExportControllerInstance; + IBOutlet id userManagerInstance; + IBOutlet NSSearchField *listFilterField; @@ -126,8 +128,8 @@ enum { - (NSString *)getHTMLforPrint; +- (IBAction)showUserManager:(id)sender; - (void)initQueryEditorWithString:(NSString *)query; - // Connection callback and methods - (void) setConnection:(MCPConnection *)theConnection; - (void)setShouldAutomaticallyConnect:(BOOL)shouldAutomaticallyConnect; diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 02212647..ee314b65 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -47,6 +47,7 @@ #import "SPPreferenceController.h" #import "SPPrintAccessory.h" #import "QLPreviewPanel.h" +#import "SPUserManager.h" // Used for printing #import "MGTemplateEngine.h" @@ -2174,7 +2175,15 @@ [toolbarItem setTarget:self]; [toolbarItem setAction:@selector(viewRelations:)]; - + } else if ([itemIdentifier isEqualToString:@"SwitchToUserManagerToolbarItemIdentifier"]) { + [toolbarItem setLabel:NSLocalizedString(@"Users", @"toolbar item label for switching to the User Manager tab")]; + [toolbarItem setPaletteLabel:NSLocalizedString(@"Users", @"toolbar item label for switching to the User Manager tab")]; + //set up tooltip and image + [toolbarItem setToolTip:NSLocalizedString(@"Switch to the User Manager tab", @"tooltip for toolbar item for switching to the User Manager tab")]; + [toolbarItem setImage:[NSImage imageNamed:NSImageNameEveryone]]; + //set up the target action + [toolbarItem setTarget:self]; + [toolbarItem setAction:@selector(showUserManager:)]; } else { //itemIdentifier refered to a toolbar item that is not provided or supported by us or cocoa toolbarItem = nil; @@ -2199,6 +2208,7 @@ @"SwitchToRunQueryToolbarItemIdentifier", @"SwitchToTableInfoToolbarItemIdentifier", @"SwitchToTableRelationsToolbarItemIdentifier", + @"SwitchToUserManagerToolbarItemIdentifier", NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, @@ -2220,6 +2230,7 @@ @"SwitchToRunQueryToolbarItemIdentifier", NSToolbarFlexibleSpaceItemIdentifier, @"HistoryNavigationToolbarItemIdentifier", + @"SwitchToUserManagerToolbarItemIdentifier", @"ShowConsoleIdentifier", nil]; } @@ -2542,6 +2553,16 @@ if(queryEditorInitString) [queryEditorInitString release]; [super dealloc]; } + +- (void)showUserManager:(id)sender +{ + if (userManagerInstance == nil) + { + userManagerInstance = [[SPUserManager alloc] initWithConnection:mySQLConnection]; + } else { + [userManagerInstance show]; + } +} @end |