Added for:/of: tagging capability.
[zzz-floof.git] / floof / controllers / tag.py
index e5ce85b..e57d0c5 100644 (file)
@@ -1,16 +1,18 @@
 import logging
+import re
 
-from pylons import request, response, session, tmpl_context as c, h
+from pylons import request, response, session, tmpl_context as c, url
 from pylons.controllers.util import abort, redirect
 
+import elixir
+from floof.model import Art, ArtUser, ArtUserType, Tag, TagText, User
 from floof.lib.base import BaseController, render
-from pylons import url
+from floof.lib.dbhelpers import find_or_create
+from floof.lib import helpers as h
+from sqlalchemy import func
 
 log = logging.getLogger(__name__)
 
-import elixir
-from floof.model import Art, Tag
-
 class TagController(BaseController):
 
     # TODO: login required
@@ -23,7 +25,77 @@ class TagController(BaseController):
     # TODO: login required
     def create(self, art_id):
         c.art = h.get_object_or_404(Art, id=art_id)
-        c.art.add_tags(request.params.get("tags",""), c.user)
+
+        tag_string = request.params.get('tags', '')
+
+        # Add or remove tags
+        bad_tags = []
+        for tag_text in tag_string.split():
+            original_tag_text = tag_text
+            tag_text = tag_text.lower()
+
+            # Adding or removing a tag?
+            if tag_text[0] == '-':
+                add = False
+                tag_text = tag_text[1:]
+            else:
+                # Allow "+foo" to mean "add foo"
+                if tag_text[0] == '+':
+                    tag_text = tag_text[1:]
+                add = True
+
+            # Check for special namespaces
+            prefix = None
+            if ':' in tag_text:
+                prefix, tag_text = tag_text.split(':', 1)
+                if prefix not in ['by', 'for', 'of']:
+                    # This is bogus.  Skip it.
+                    bad_tags.append(original_tag_text)
+                    continue
+
+                if prefix == 'by':
+                    # XXX this needs supporting.  silently ignore for now
+                    continue
+
+            # Must be 3-50 alphanumeric characters
+            if not re.match('^[a-z0-9]{3,50}$', tag_text):
+                bad_tags.append(original_tag_text)
+                continue
+
+            # Do work!
+            if prefix:
+                target_user = User.query.filter(func.lower(User.name) == tag_text) \
+                                  .one()
+
+                # Special tag; at the moment, just a relationship
+                if prefix == 'by':
+                    rel = ArtUserType.BY
+                elif prefix == 'for':
+                    rel = ArtUserType.FOR
+                elif prefix == 'of':
+                    rel = ArtUserType.OF
+
+                user_assoc_data = dict(art=c.art, user=target_user, type=rel)
+                if add:
+                    find_or_create(ArtUser, **user_assoc_data)
+
+                else:
+                    # XXX this will die for nonassociations
+                    user_assoc = ArtUser.get_by(art=c.art, **user_assoc_data)
+                    user_assoc.delete()
+
+            else:
+                # Regular tag
+                if add:
+                    tag = find_or_create(TagText, text=tag_text)
+                    find_or_create(Tag, art=c.art, tagger=c.user, tagtext=tag)
+
+                else:
+                    tag = TagText.get_by(text=tag_text)
+                    if tag:
+                        # XXX this will die
+                        tag_assoc = Tag.get_by(art=c.art, tagger=c.user, tagtext=tag)
+                        tag_assoc.delete()
+
         elixir.session.commit()
         redirect(url('show_art', id=c.art.id))
-