Added a foreign key field (user) to StashServer to keep track who
authorMikko Värri <vmj@linuxbox.fi>
Tue, 2 Feb 2010 00:36:00 +0000 (02:36 +0200)
committerMikko Värri <vmj@linuxbox.fi>
Tue, 2 Feb 2010 00:36:00 +0000 (02:36 +0200)
created which server.

Replaced management.py (post_syncdb callback) with management command
createstashserver to accomodate the more involved first server
creation.

recycloid_models/management.py [deleted file]
recycloid_models/management/__init__.py [new file with mode: 0644]
recycloid_models/management/commands/__init__.py [new file with mode: 0644]
recycloid_models/management/commands/createstashserver.py [new file with mode: 0644]
recycloid_models/models.py

diff --git a/recycloid_models/management.py b/recycloid_models/management.py
deleted file mode 100644 (file)
index 39b7453..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-from django.db.models.signals import post_syncdb
-
-from recycloid_models import models
-
-
-def post_syncdb_cb(sender, **kwargs):
-    """Callback for post_syncdb signal.
-
-    Creates the 'current stash server' object.
-    """
-    verbosity = kwargs.get('verbosity', 0)
-    interactive = kwargs.get('interactive', False)
-
-    if models.StashServer in kwargs.get('created_models', []):
-        server = models.StashServer()
-        if verbosity:
-            print "You just installed Recycloid's models, which means you don't have any servers defined."
-        if interactive:
-            url = raw_input("Give API URL of the recycloid server: ")
-            server.url = url
-        else:
-            if verbosity:
-                print "Be sure to add API URL to the database."
-        server.save() # we want the ID
-        if verbosity or server.id != 1:
-            print "Be sure to add RECYCLOID_SERVER_ID=%s to settings.py." % server.id
-
-
-post_syncdb.connect(post_syncdb_cb, sender=models)
diff --git a/recycloid_models/management/__init__.py b/recycloid_models/management/__init__.py
new file mode 100644 (file)
index 0000000..0508c57
--- /dev/null
@@ -0,0 +1,32 @@
+from django.db.models import signals
+from recycloid_models import models as recycloid_models_app
+
+
+def create_stashserver(sender, **kwargs):
+    """Callback for post_syncdb signal.
+
+    Offers to call the createstashserver management command when
+    recycloid_models is first installed.
+    """
+    from django.core.management import call_command
+    from recycloid_models.models import StashServer
+
+    interactive = kwargs.get('interactive', False)
+    created_models = kwargs.get('created_models', [])
+
+    if interactive and StashServer in created_models:
+        msg = "\nYou just installed Recycloid's models, which means " \
+              "you don't have any servers defined.\nWould you like " \
+              "to create one now? (yes/no): "
+        confirm = raw_input(msg)
+        while 1:
+            if confirm not in ('yes', 'no'):
+                confirm = raw_input('Please enter either "yes" or "no": ')
+                continue
+            if confirm == 'yes':
+                call_command("createstashserver", interactive=True)
+            break
+
+signals.post_syncdb.connect(create_stashserver,
+                            sender=recycloid_models_app,
+                            dispatch_uid="recycloid_models.management.create_stashserver")
diff --git a/recycloid_models/management/commands/__init__.py b/recycloid_models/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..1b84c45
--- /dev/null
@@ -0,0 +1,95 @@
+from django.contrib.auth.models import User
+
+def select_user():
+    """Displays a user selection dialog and returns user ID.
+
+    :return: django.contrib.auth.models.User.id
+    """
+    user = None
+
+    count = User.objects.count()
+    if count == 0:
+        raise User.DoesNotExist
+
+    # Try to figure out some useful default
+    default_user = None
+
+    if count == 1:
+        default_user = User.objects.all()[0].id
+
+    if default_user is None:
+        staff = User.objects.filter(staff=True)
+        if staff.count() == 1:
+            default_user = staff[0].id
+
+    if default_user is None:
+        superusers = User.objects.filter(superuser=True)
+        if superusers.count() == 1:
+            default_user = superusers[0].id
+
+    if default_user:
+        msg = "User ID (leave blank to use the default '%s'; '?' for help): " % default_user
+    else:
+        msg = "User ID ('n' for a list of first page of users; '?' for help): "
+    offset = 0
+    while user is None:
+        assert(len(msg) > 0)
+        user = raw_input(msg)
+        if user == "" and default_user:
+            user = default_user
+            break
+        try:
+            user = int(user)
+            User.objects.get(pk=user)
+        except ValueError:
+            command = user
+            user = None
+
+            limit = 10
+            assert(limit > 0)
+            if command not in ('N', 'P', 'n', 'p'):
+                if command != '?':
+                    print "Unknown command '%s'." % command
+                print "  N: List first page of users (%s users)" % min(limit, count)
+                if count > limit:
+                    print "  P: List last page of users (%s users)" % (count - (count / limit * limit))
+                if count > offset + limit:
+                    print "  n: List next page of users (users %s-%s)" % ((offset + limit), (offset + limit * 2 - 1))
+                if offset > 0:
+                    print "  p: List previous page of users (users %s-%s)" % ((offset - limit), (offset - 1))
+                continue
+
+            default_user = None
+            if command == 'N':
+                offset = 0
+                if count > limit:
+                    msg = "User ID ('n' for next page of users; '?' for help): "
+                else:
+                    msg = "User ID ('?' for help): "
+            elif command == 'P':
+                offset = count / limit * limit
+                if offset > 0:
+                    msg = "User ID ('p' for previous page of users; '?' for help): "
+                else:
+                    msg = "User ID ('?' for help): "
+            elif command == 'n':
+                offset = min(count / limit * limit, offset + limit)
+                if offset == (count / limit * limit):
+                    msg = "User ID ('?' for help): "
+                else:
+                    msg = "User ID ('n' for next page of users; '?' for help): "
+            elif command == 'p':
+                offset = max(0, offset - limit)
+                if offset == 0:
+                    msg = "User ID ('?' for help): "
+                else:
+                    msg = "User ID ('p' for previous page of users; '?' for help): "
+
+            users = User.objects.all()[offset:offset+limit]
+            for u in users:
+                print "%s   %s" % (u.id, u.username)
+        except User.DoesNotExist:
+            print "User with ID %s does not exist." % user
+            user = None
+
+    return user
diff --git a/recycloid_models/management/commands/createstashserver.py b/recycloid_models/management/commands/createstashserver.py
new file mode 100644 (file)
index 0000000..23e57c6
--- /dev/null
@@ -0,0 +1,100 @@
+import sys
+from optparse import make_option
+from django.core.exceptions import ValidationError
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import User
+from recycloid_models.models import StashServer, StashOwner
+from recycloid_models.management.commands import select_user
+
+def is_valid_url(value):
+    #[TODO] Validate against URLField
+    try:
+        StashServer.objects.get(url=value)
+    except StashServer.DoesNotExist:
+        pass
+    else:
+        raise ValidationError('URL is already taken.')
+    return True
+
+
+def is_valid_user(value):
+    try:
+        User.objects.get(pk=value)
+    except User.DoesNotExist:
+        raise ValidationError('User does not exist.')
+    return True
+
+
+class Command(BaseCommand):
+    option_list = BaseCommand.option_list + (
+        make_option('--url',
+                    dest='url',
+                    default=None,
+                    help='Specified the API URL for the server.'),
+        make_option('--user',
+                    dest="user",
+                    default=None,
+                    help='Specifies the django.contrib.auth.User (by ID) who creates this server.'),
+        make_option('--noinput',
+                    dest='interactive',
+                    default=True,
+                    help='Tells Django to NOT prompt the user for input of any kind. ' \
+                         'You must use --url and --user with --noinput.'),
+        )
+    help = 'Used to create a stash server.'
+
+    def handle(self, *args, **options):
+        url = options.get('url', None)
+        user = options.get('user', None)
+        interactive = options.get('interactive', True)
+
+        # Just validate when --noinput
+        if not interactive:
+            if not url or not user:
+                raise CommandError('You must use --url and --user with --noinput.')
+            try:
+                is_valid_url(url)
+                is_valid_user(user)
+            except ValidationError, e:
+                raise CommentError(str(e))
+
+
+        # Prompt for url/user.  Enclose this whole thing in a
+        # try/except to trap keyboard interrupt and exit gracefully.
+        if interactive:
+            try:
+                # Get URL
+                while 1:
+                    if not url:
+                        url = raw_input('API URL: ')
+                    try:
+                        is_valid_url(url)
+                    except ValidationError, e:
+                        sys.stderr.write("Error: %s\n" % str(e))
+                        url = None
+                    else:
+                        break
+
+                # Get user
+                while 1:
+                    if not user:
+                        user = select_user()
+                    try:
+                        is_valid_user(user)
+                    except ValidationError, e:
+                        sys.stderr.write("Error: %s\n" % str(e))
+                        user = None
+                    else:
+                        break
+            except KeyboardInterrupt:
+                sys.stderr.write("\nOperation cancelled.\n")
+                sys.exit(1)
+
+        user = User.objects.get(pk=user)
+        server = StashServer.objects.create(user=user, url=url)
+        print "StashServer created succesfully."
+        try:
+            owner = StashOwner.objects.get(user=user)
+        except StashOwner.DoesNotExist:
+            StashOwner.objects.create(server=server, user=user)
+            print "StashOwner extension for selected User created succesfully."
index 5ec9482..a438c33 100644 (file)
@@ -28,6 +28,9 @@ class StashServer(IdentifiedModel):
     """Stash server.
     """
 
+    user = models.ForeignKey(User,
+                             help_text='User who created this server')
+
     url = models.URLField(unique=True, help_text='API URL of this server')
 
     objects = StashServerManager()