Restrict usernames to lowercase, digits, and hyphens.
[zzz-floof.git] / floof / controllers / tag.py
1 import logging
2 import re
3
4 from pylons import request, response, session, tmpl_context as c, url
5 from pylons.controllers.util import abort, redirect
6
7 import elixir
8 from floof.model import Art, ArtUser, ArtUserType, Tag, TagText, User
9 from floof.lib.base import BaseController, render
10 from floof.lib.dbhelpers import find_or_create
11 from floof.lib import helpers as h
12 from sqlalchemy import func
13
14 log = logging.getLogger(__name__)
15
16 class TagController(BaseController):
17
18 # TODO: login required
19 def delete(self, art_id, id):
20 tag = h.get_object_or_404(Tag, id=id)
21 elixir.session.delete(tag)
22 elixir.session.commit()
23 redirect(url('show_art', id=art_id))
24
25 # TODO: login required
26 def create(self, art_id):
27 c.art = h.get_object_or_404(Art, id=art_id)
28
29 tag_string = request.params.get('tags', '')
30
31 # Add or remove tags
32 bad_tags = []
33 for tag_text in tag_string.split():
34 original_tag_text = tag_text
35 tag_text = tag_text.lower()
36
37 # Adding or removing a tag?
38 if tag_text[0] == '-':
39 add = False
40 tag_text = tag_text[1:]
41 else:
42 # Allow "+foo" to mean "add foo"
43 if tag_text[0] == '+':
44 tag_text = tag_text[1:]
45 add = True
46
47 # Check for special namespaces
48 prefix = None
49 if ':' in tag_text:
50 prefix, tag_text = tag_text.split(':', 1)
51 if prefix not in ['by', 'for', 'of']:
52 # This is bogus. Skip it.
53 bad_tags.append(original_tag_text)
54 continue
55
56 if prefix == 'by':
57 # XXX this needs supporting. silently ignore for now
58 continue
59
60 # Must be 3-50 alphanumeric characters
61 if not re.match('^[a-z0-9]{3,50}$', tag_text):
62 bad_tags.append(original_tag_text)
63 continue
64
65 # Do work!
66 if prefix:
67 target_user = User.query.filter(func.lower(User.name) == tag_text) \
68 .one()
69
70 # Special tag; at the moment, just a relationship
71 if prefix == 'by':
72 rel = ArtUserType.BY
73 elif prefix == 'for':
74 rel = ArtUserType.FOR
75 elif prefix == 'of':
76 rel = ArtUserType.OF
77
78 user_assoc_data = dict(art=c.art, user=target_user, type=rel)
79 if add:
80 find_or_create(ArtUser, **user_assoc_data)
81
82 else:
83 # XXX this will die for nonassociations
84 user_assoc = ArtUser.get_by(art=c.art, **user_assoc_data)
85 user_assoc.delete()
86
87 else:
88 # Regular tag
89 if add:
90 tag = find_or_create(TagText, text=tag_text)
91 find_or_create(Tag, art=c.art, tagger=c.user, tagtext=tag)
92
93 else:
94 tag = TagText.get_by(text=tag_text)
95 if tag:
96 # XXX this will die
97 tag_assoc = Tag.get_by(art=c.art, tagger=c.user, tagtext=tag)
98 tag_assoc.delete()
99
100 elixir.session.commit()
101 redirect(url('show_art', id=c.art.id))