1 from floof
.model
import Art
, ArtUser
, ArtUserType
, Tag
, TagText
, User
3 from dbhelpers
import find_or_create
6 def parse(search_string
, me
):
7 """Parses a search query, and returns a query object on Art.
11 - User relations: by:kalu, of:eevee, for:ootachi
12 - User relations relative to some user: by:me
13 Note that this necessitates a `me` parameter.
16 - Negative versions of anything above: -by:eevee, -dongs
19 # XXX doesn't do negative querying yet.
20 # XXX could use some sane limits.
22 # We'll be building this as we go.
25 terms
= search_string
.split()
28 # This is a special tag; at the moment, by/for/of to indicate
30 prefix
, tag
= tag
.split(':', 1)
35 # XXX what to do if this fails? abort? return empty query?
36 target_user
= User
.get_by(name
=tag
)
45 # Bogus tag. Not sure what to do here, so for the moment,
49 # Inner join to the ArtUser table
50 q
= q
.join(ArtUser
, aliased
=True) \
51 .filter(ArtUser
.user
== target_user
) \
52 .filter(ArtUser
.type == rel
)
56 q
= q
.join(Tag
, TagText
, aliased
=True) \
57 .filter(TagText
.text
== tag
)
61 def add_tags(art
, tag_string
, adding_user
, me
):
62 """Takes a string that looks like a tag query, and effectively modifies the
63 art's tags to match it.
66 # XXX what to do with invalid tags? just return them and let caller fix?
68 for tag_text
in tag_string
.split():
69 original_tag_text
= tag_text
70 tag_text
= tag_text
.lower()
72 # Adding or removing a tag?
73 if tag_text
[0] == '-':
75 tag_text
= tag_text
[1:]
77 # Allow "+foo" to mean "add foo"
78 if tag_text
[0] == '+':
79 tag_text
= tag_text
[1:]
82 # Check for special namespaces
85 prefix
, tag_text
= tag_text
.split(':', 1)
86 if prefix
not in ['by', 'for', 'of']:
87 # This is bogus. Skip it.
88 bad_tags
.append(original_tag_text
)
92 # XXX this needs supporting. silently ignore for now
95 # Must be 3-50 alphanumeric characters
96 if not re
.match('^[a-z0-9]{3,50}$', tag_text
):
97 bad_tags
.append(original_tag_text
)
105 target_user
= User
.get_by(name
=tag_text
)
107 # Special tag; at the moment, just a relationship
110 elif prefix
== 'for':
111 rel
= ArtUserType
.FOR
115 user_assoc_data
= dict(art
=art
, user
=target_user
, type=rel
)
117 find_or_create(ArtUser
, **user_assoc_data
)
120 # XXX this will die for nonassociations
121 user_assoc
= ArtUser
.get_by(**user_assoc_data
)
127 tag
= find_or_create(TagText
, text
=tag_text
)
128 find_or_create(Tag
, art
=art
, tagger
=adding_user
, tagtext
=tag
)
131 tag
= TagText
.get_by(text
=tag_text
)
134 tag_assoc
= Tag
.get_by(art
=art
, tagger
=adding_user
, tagtext
=tag
)
137 elixir
.session
.commit()