5b347b35c037ba0c78ecb05371659f7998bd4066
3 from pylons
import config
, request
, response
, session
, tmpl_context
as c
, h
4 from pylons
.controllers
.util
import abort
, redirect
6 from floof
.lib
.base
import BaseController
, render
8 log
= logging
.getLogger(__name__
)
10 from floof
.lib
import file_storage
as storage
11 from floof
.model
.users
import User
12 from floof
.model
import Art
, Rating
, UserRelation
13 from floof
.model
.comments
import Discussion
14 from floof
.model
.users
import User
, UserRelationship
21 from sqlalchemy
import func
22 from sqlalchemy
.exceptions
import IntegrityError
23 from sqlalchemy
.orm
.exc
import NoResultFound
24 from wtforms
.validators
import ValidationError
28 class ArtUploadForm(Form
):
29 by
= TextField('Artists')
30 file = FileField('Upload')
31 url
= TextField('Link')
33 # TODO: make this general purpose
34 def validate_file(self
, field
):
36 raise ValidationError('File is required')
38 # Also make this into a general User List field validator
39 """ PLEASE NOTE! I just realized that I need to have a __str__ method on User
40 to get it to write the usernames back in the form when it redisplays them, since
41 this validator turns them into user objects instead. This fact actually sounds dangerous
42 to me in the future, since it means I proably shouldn't be changing the data input
43 by the user right here in the validator, or the user will see the post-mangled data instead
44 of what they actually typed. Hm.
46 One solution to this could be to only look up the users after normal validation is over,
47 and then manually add validation errors to the form if that fails. But I think that kind of
48 sucks. Perhaps the ideology in Formish, where they keep Validation and Conversion as
49 separate tasks, is a better way of doing it? That way there is less risk of changing the user's
50 input -- you do that at the conversiot stage -- yet it is still encapsulated in the form workflow.
51 Hm. But that means I'd have to query for the users in the validation step and throw them away,
52 or something equally stupid. Guess there's no perfect solution here, but I thought it was
55 Btw, this is meant to be used by a field with multi user autocompletion on it (like on stackoverflow tags),
56 so the user should never actually submit anything invalid unless they disable javascript and force it.
58 def validate_by(self
, field
):
60 raise ValidationError("Needs at least one creator")
61 user_names
= field
.data
.split()
63 # TODO: Could totally do a filter__in here instead of picking them out individually
64 for user_name
in user_names
:
65 user
= User
.get_by(name
=user_name
)
67 raise ValidationError("Couldn't find user %s" % user_name
)
71 class ArtController(BaseController
):
72 def __before__(self
, id=None):
73 super(ArtController
, self
).__before__()
74 # Awesome refactoring!
76 c
.art
= h
.get_object_or_404(Art
, id=id)
80 c
.form
= ArtUploadForm()
81 return render("/art/new.mako")
83 # TODO: login required
85 c
.form
= ArtUploadForm(request
.params
)
86 if not c
.form
.validate():
87 ## TODO: JavaScript should be added to the upload form so that it is
88 ## impossible to submit the form when it contains any invalid users,
89 ## so this never happens. Only autocompled usernames should be allowed.
90 return render("/art/new.mako")
93 upload
= request
.params
['file']
94 hash = storage
.save_file('art/original', upload
.file)
96 # Create a thumbnail and a medium view
98 config
['app_conf']['static_root']
99 + storage
.get_path('art/original', hash)[1:]
101 for subdir
, config_size
in [('medium', config
['medium_size']),
102 ('thumbnail', config
['thumbnail_size'])]:
103 path
= config
['app_conf']['static_root'] + storage
.get_path("art/{0}".format(subdir
), hash)
105 dir, _
= os
.path
.split(path
)
106 if not os
.path
.exists(dir):
109 size
= int(config_size
)
110 shrunken_img
= img
.copy()
111 shrunken_img
.thumbnail((size
, size
), PIL
.Image
.ANTIALIAS
)
112 shrunken_img
.save(path
, img
.format
)
114 #magicker = magic.Magic(mime=True)
115 buffer = upload
.file.read(64)
117 mimetype
= 'image/unknown' #magickery.from_buffer(buffer)
119 # XXX Ensure we can actually handle the mimetype
124 original_filename
=upload
.filename
,
128 c
.art
.discussion
= Discussion(count
=0)
130 for artist
in c
.form
.by
.data
:
131 UserRelation(user
=artist
, kind
="by", creator
=c
.user
, art
=c
.art
)
135 elixir
.session
.commit()
136 redirect(url('show_art', id=c
.art
.id))
137 except IntegrityError
:
138 # XXX Check this as early as possible, and clean up the filesystem!
139 # Right now this replaces the original file!
141 elixir
.session
.rollback()
142 duplicate_art
= Art
.get_by(hash=hash)
143 h
.flash("We already have that one.")
144 redirect(url('show_art', id=duplicate_art
.id))
149 # c.art = h.get_object_or_404(Art, id=id)
151 c
.your_score
= c
.art
.user_score(c
.user
)
152 return render("/art/show.mako")
155 # TODO: login required
157 # c.art = h.get_object_or_404(Art, id=id)
158 score
= request
.params
.get("score")
159 if score
and score
.isnumeric():
162 score
= Rating
.reverse_options
.get(score
)
164 c
.art
.rate(score
, c
.user
)
165 elixir
.session
.commit()
167 redirect(url('show_art', id=c
.art
.id))
170 def watchstream(self
, name
):
171 """Watchstream for a certain user."""
173 c
.watching_user
= User
.query
.filter(func
.lower(User
.name
) == name
) \
175 except NoResultFound
:
178 # This user has watches which are users which have art
179 # XXX use artist, not uploader
180 c
.artwork
= Art
.query
.join(Art
.uploader
,
181 User
.target_of_relationships
) \
182 .filter(UserRelationship
.user_id
== c
.watching_user
.id)
184 return render('/index.mako')