ff8035a37a113eee84c2a9677d08c4bbbea1e0b0
[zzz-floof.git] / floof / model / art.py
1 #
2 # floof/floof/model/art.py
3 #
4 # Copyright (c) 2009 Scribblr
5 #
6
7 # from elixir import Entity, Field, Integer, Unicode
8 from elixir import *
9 import elixir
10
11 from pylons import config
12
13 from floof.lib.file_storage import get_path, save_file
14 from floof.lib.dbhelpers import find_or_create, update_or_create
15 import floof.model.comments
16
17 class Art(Entity):
18 title = Field(Unicode(120))
19 original_filename = Field(Unicode(120))
20 hash = Field(String, unique=True, required=True)
21
22 uploader = ManyToOne('User', required=True)
23 tags = OneToMany('Tag')
24 discussion = ManyToOne('Discussion')
25
26 user_relations = OneToMany('UserRelation')
27
28
29 def set_file(self, file):
30 self.hash = save_file("art", file)
31 self.original_filename = file.filename
32
33 file = property(get_path, set_file)
34
35 def get_path(self):
36 if self.hash:
37 return get_path("art", self.hash)
38
39
40 def add_tags(self, tags, user):
41 for text in tags.split():
42 if text[0] == '-':
43 # Nega-tags
44 tagtext = TagText.get_by(text=text[1:])
45 if tagtext:
46 tag = Tag.get_by(art=self, tagger=user, tagtext=tagtext)
47 if tag:
48 elixir.session.delete(tag)
49
50 else:
51 if len(text) > 50:
52 raise "Long Tag!" # can we handle this more gracefully?
53 # sqlite seems happy to store strings much longer than the supplied limit...
54
55 # elixir should really have its own find_or_create.
56 tagtext = find_or_create(TagText, text=text)
57 tag = find_or_create(Tag, art=self, tagger=user, tagtext=tagtext)
58
59
60
61
62 def rate(self, score, user):
63 return update_or_create(Rating, {"rater":user, "art":self}, {"score":score})
64
65 def user_score(self, user):
66 rating = Rating.get_by(rater=user, art=self)
67 if rating:
68 return rating.score
69 return Rating.default
70
71 def __unicode__(self):
72 return self.get_path()
73
74
75 class Tag(Entity):
76 # look into how ondelete works. This just sets a database property.
77 art = ManyToOne('Art', ondelete='cascade')
78 tagger = ManyToOne('User', ondelete='cascade')
79 tagtext = ManyToOne('TagText')
80
81 def __unicode__(self):
82 if not self.tagtext:
83 return "(broken)"
84 return unicode(self.tagtext)
85
86
87 class TagText(Entity):
88 text = Field(Unicode(50)) # gotta enforce this somehow
89 tags = OneToMany('Tag')
90
91 def __unicode__(self):
92 return self.text
93
94
95 class Rating(Entity):
96 art = ManyToOne('Art', ondelete='cascade')
97 rater = ManyToOne('User', ondelete='cascade')
98 score = Field(Integer)
99
100 options = {-1:"sucks", 0:"undecided", 1:"good", 2:"great"}
101 default = 0
102
103 Rating.reverse_options = dict (zip(Rating.options.values(), Rating.options.keys()))
104
105
106
107 class UserRelation(Entity):
108 user = ManyToOne("User")
109 art = ManyToOne("Art")
110 kind = Field(String) # by for of
111 creator = ManyToOne("User")
112 confirmed_by_related_user = Field(Boolean)
113
114 # it is useful to record which authority figure on a given artwork
115 # confirmed the validity of this relation.
116 confirmed_by_authority = ManyToOne("User")
117
118 def __init__(self, **kwargs):
119 super(UserRelation, self).__init__(**kwargs)
120 assert self.user and self.art and self.kind and self.creator
121
122 if self.creator == self.user:
123 self.confirmed_by_related_user = True
124 # TODO: implement authorities
125 # if self.creator in self.art.authorities
126 # self.confirmed_by_authority = self.creator
127
128 def __unicode__(self):
129 return "%s: %s" % (self.kind, self.related_user)
130
131
132
133 # class CharacterRelation(Entity):
134 # pass