Got rid of the base class monkey-patching. That's frightening.
Added some accessors to Art to get lists of certain types of relationed
users.
Removed the user-list field from the upload page; for now, we assume the
uploader is also the artist.
log = logging.getLogger(__name__)
from floof.lib import file_storage as storage
-from floof.model.users import User
-from floof.model import Art, Rating, UserRelation
+from floof.model import Art, Rating, ArtUser
+from floof.model.art import ArtUserType
from floof.model.comments import Discussion
from floof.model.users import User, UserRelationship
if field.data == u'':
raise ValidationError('File is required')
- # Also make this into a general User List field validator
- """ PLEASE NOTE! I just realized that I need to have a __str__ method on User
- to get it to write the usernames back in the form when it redisplays them, since
- this validator turns them into user objects instead. This fact actually sounds dangerous
- to me in the future, since it means I proably shouldn't be changing the data input
- by the user right here in the validator, or the user will see the post-mangled data instead
- of what they actually typed. Hm.
-
- One solution to this could be to only look up the users after normal validation is over,
- and then manually add validation errors to the form if that fails. But I think that kind of
- sucks. Perhaps the ideology in Formish, where they keep Validation and Conversion as
- separate tasks, is a better way of doing it? That way there is less risk of changing the user's
- input -- you do that at the conversiot stage -- yet it is still encapsulated in the form workflow.
- Hm. But that means I'd have to query for the users in the validation step and throw them away,
- or something equally stupid. Guess there's no perfect solution here, but I thought it was
- worth discussing.
-
- Btw, this is meant to be used by a field with multi user autocompletion on it (like on stackoverflow tags),
- so the user should never actually submit anything invalid unless they disable javascript and force it.
- """
- def validate_by(self, field):
- if not field.data:
- raise ValidationError("Needs at least one creator")
- user_names = field.data.split()
- users = []
- # TODO: Could totally do a filter__in here instead of picking them out individually
- for user_name in user_names:
- user = User.get_by(name=user_name)
- if not user:
- raise ValidationError("Couldn't find user %s" % user_name)
- users.append(user)
- field.data = users
class ArtController(BaseController):
def __before__(self, id=None):
)
c.art.discussion = Discussion(count=0)
- for artist in c.form.by.data:
- UserRelation(user=artist, kind="by", creator=c.user, art=c.art)
+ # For the moment, cheerfully assume that people are uploading their own
+ # art
+ ArtUser(art=c.art, user=c.user, type=ArtUserType.BY)
try:
# Copyright (c) 2009 Scribblr
#
-# from elixir import Entity, Field, Integer, Unicode
from elixir import *
import elixir
from floof.lib.file_storage import get_path, save_file
from floof.lib.dbhelpers import find_or_create, update_or_create
-import floof.model.comments
+from floof.model.users import User
-# Note: Art is the most important class. To keep its size down, and to better organize the source code,
-# other modules will mix into it automatically by adding to its __bases__.
-
class Art(Entity):
title = Field(Unicode(120))
original_filename = Field(Unicode(120))
tags = OneToMany('Tag')
discussion = ManyToOne('Discussion')
- user_relations = OneToMany('UserRelation')
+ art_users = OneToMany('ArtUser')
@property
def file_path(self):
return get_path("art", self.hash)
+
+ # Associated users
+ # XXX ok these could stand to do the filtering sql-side
+ @property
+ def artists(self):
+ return (au.user for au in self.art_users if au.type == ArtUserType.BY)
+
+ @property
+ def recipients(self):
+ return (au.user for au in self.art_users if au.type == ArtUserType.FOR)
+
+ @property
+ def participants(self):
+ return (au.user for au in self.art_users if au.type == ArtUserType.OF)
+
+
+class ArtUserType(object):
+ BY = 1
+ FOR = 2
+ OF = 3
+
+class ArtUser(Entity):
+ art = ManyToOne('Art', required=True)
+ user = ManyToOne('User', required=True)
+ type = Field(Integer, required=True) # ArtUserType
+
+ # TODO: admin log ought to remember who confirmed the relation.
+ # (tag history will remember who proposed it)
+++ /dev/null
-from elixir import *
-from art import Art
-
-
-class UserRelation(Entity):
- user = ManyToOne("User")
- art = ManyToOne("Art")
- kind = Field(String) # by for of
- creator = ManyToOne("User")
- confirmed_by_related_user = Field(Boolean)
-
- # it is useful to record which authority figure on a given artwork
- # confirmed the validity of this relation.
- confirmed_by_authority = ManyToOne("User")
-
- def __init__(self, **kwargs):
- super(UserRelation, self).__init__(**kwargs)
- assert self.user and self.art and self.kind and self.creator
-
- if self.creator == self.user:
- self.confirmed_by_related_user = True
- # TODO: implement authorities
- # if self.creator in self.art.authorities
- # self.confirmed_by_authority = self.creator
-
- def __unicode__(self):
- return "%s: %s" % (self.kind, self.related_user)
-
-
-class RelationMixin(object):
- def add_relation(creator, kind, user):
- return UserRelation(art=self, creator=creator, kind=kind, user=user)
-
-Art.__bases__ += (RelationMixin,)
/*** Common bits and pieces ***/
h1 { margin: 0.5em 0 0.25em; font-size: 2em; border-bottom: 1px solid #404040; text-shadow: #a0a0a0 1px 1px 1px; }
+h2 { margin: 0.5em 0 0.25em; font-size: 1.5em; border-bottom: 1px dotted #606060; text-shadow: #a0a0a0 1px 1px 1px; }
a { color: #647cc4; font-weight: bold; text-decoration: none; pointer: cursor; }
a:visited { color: #48598e; }
<%inherit file="/base.mako" />
<h1>Add New Art</h1>
-<p>Now: Upload a file. Later: Supply a link? Not exclusive to uploading.</p>
-
-## Todo: write some macros to make outputting form fields easier.
-
${h.form(h.url('create_art'), multipart=True)}
-${normal_field(c.form.by)}
+## Todo: write some macros to make outputting form fields easier.
${normal_field(c.form.file)}
-
-##Artist: ${h.text('artist')}
-##${h.file('file')}
${h.submit(None, 'Upload!')}
${h.end_form()}
<h2>Relations</h2>
<ul>
-% for relation in c.art.user_relations:
-<li>${relation.kind}: ${relation.user}
+% for label, relations in (('Artist', c.art.artists), \
+ ('Recipient', c.art.recipients), \
+ ('Participant', c.art.participants)):
+% for user in relations:
+<li>${label}: ${user.name}
+% endfor
% endfor
</ul>