duplicate submissions.
Made an absolute mess of routes, but I think I've fixed them all now.
Removed all url.current() calls because they don't seem to work, though
I'm not sure if that's because I added explicit=True or not. I'm wary
of them anyhow after reading
http://pylonsbook.com/en/1.0/urls-routing-and-dispatch.html#route-memory
map.connect('/error/{action}', controller='error')
map.connect('/error/{action}/{id}', controller='error')
- map.connect('/', controller='main', action='index')
-
- # User stuff
- map.connect('/account/login', controller='account', action='login')
- map.connect('/account/login_begin', controller='account', action='login_begin', **require_POST)
- map.connect('/account/login_finish', controller='account', action='login_finish')
- map.connect('/account/logout', controller='account', action='logout', **require_POST)
- map.connect('/account/register', controller='account', action='register')
- map.connect('/account/register_finish', controller='account', action='register_finish', **require_POST)
-
+ map.connect('home', '/', controller='main', action='index')
+
+ # Account stuff
+ with map.submapper(controller="account") as sub:
+ sub.connect('login', '/account/login', action='login')
+ sub.connect('login_begin', '/account/login_begin', action='login_begin', **require_POST)
+ sub.connect('login_finish', '/account/login_finish', action='login_finish')
+ sub.connect('logout', '/account/logout', action='logout', **require_POST)
+ sub.connect('register', '/account/register', action='register')
+ sub.connect('register_finish', '/account/register_finish', action='register_finish', **require_POST)
+
+ # with map.submapper()
map.connect('/users', controller='users', action='list')
map.connect('user_page', '/users/{name}', controller='users', action='view')
- # Art stuff
- art = map.resource('art','art', controller="art", member={'rate':'PUT'})
- # wow, it even works if you name the plural and singular the same thing.
- # Resources documented here: http://routes.groovie.org/manual.html#restful-services
- # It seems the first parameter (singular) is only ever used in route names, e.g. url('kitten', id=5).
- # The second parameter, plural, is used everywhere else by default: in the url, controller name,
- # and the route name for the collection. e.g. url('kittens') -> '/kittens' -> kittens.index().
- # Since our controllers have singular names, we'll have to override this every time with the 'controller' parameter.
- # Even singular routes use the plural in urls. url('kitten', id=5) -> '/kittens/5'.
- # And it appears that if the singular and plural are the same, either will match, so no harm done.
- # It does mean, however, that if you have a None id accidentally, url('art', id=None) you'll get the same thing
- # as url('art'). I mean, you might have wanted a singular but you got a plural route instead.
-
+
+ with map.submapper(controller="art") as sub:
+ sub.connect('new_art', '/art/new', action="new")
+ sub.connect('create_art', '/art/create', action="create")
+ sub.connect('rate_art', '/art/{id}/rate', action="rate")
+ sub.connect('show_art', '/art/{id}', action="show")
+
+ with map.submapper(controller='tag') as sub:
+ sub.connect('delete_tag', '/art/{art_id}/tag/{id}')
+ sub.connect('create_tag', '/art/{art_id}/tag')
+
map.resource('tag','tags', controller="tag",
parent_resource=dict(member_name='art', collection_name='art'))
# Yeah, parent resources are specified kinda dumb-ly. Would be better if you could pass in the
from openid.store.filestore import FileOpenIDStore
from sqlalchemy.orm.exc import NoResultFound
-from pylons import request, response, session, tmpl_context as c, url
-from pylons.controllers.util import abort, redirect_to
+from pylons import request, response, session, tmpl_context as c, url, h
+from pylons.controllers.util import abort, redirect
from routes import url_for, request_config
from floof.lib.base import BaseController, render
return_url = url_for(host=host, controller='account', action='login_finish')
new_url = auth_request.redirectURL(return_to=return_url,
realm=protocol + '://' + host)
- redirect_to(new_url)
+ redirect(new_url)
def login_finish(self):
"""Step two of logging in; the OpenID provider redirects back here."""
session['register:nickname'] = sreg_res['nickname']
session.save()
- redirect_to(url.current(action='register'))
+ redirect(url('register'))
# Remember who's logged in, and we're good to go
session['user_id'] = user.id
session.save()
# XXX send me where I came from
- redirect_to('/')
+ redirect('/')
def logout(self):
"""Log user out."""
# XXX success message
# XXX send me where I came from
- redirect_to('/')
+ redirect('/')
def register(self):
"""Logging in with an unrecognized identity URL redirects here."""
# XXX how do we do success messages in some useful way?
# XXX send me where I came from
- redirect_to('/')
+ redirect('/')
import elixir
from floof.model.art import Art, Rating
+from sqlalchemy.exceptions import IntegrityError
+
+
class ArtController(BaseController):
def __before__(self, id=None):
super(ArtController, self).__before__()
# TODO: login required
def create(self):
- Art(uploaded_by=c.user, **request.params)
- elixir.session.commit()
- redirect_to(controller="main", action="index")
+ c.art = Art(uploader=c.user, **request.params)
+
+ try:
+ elixir.session.commit()
+ redirect(url('show_art', id=c.art.id))
+ except IntegrityError:
+ # hurr, there must be a better way to do this but I am lazy right now
+ hash = c.art.hash
+ elixir.session.rollback()
+ duplicate_art = Art.get_by(hash=hash)
+ h.flash("We already have that one.")
+ redirect(url('show_art', id=duplicate_art.id))
+
def show(self, id):
# c.art = h.get_object_or_404(Art, id=id)
c.art.rate(score, c.user)
elixir.session.commit()
- redirect(url('art', id=c.art.id))
+ redirect(url('show_art', id=c.art.id))
# TODO: login required
def display(self, id):
c.search = h.get_object_or_404(SavedSearch, id=id)
- c.gallery = GalleryWidget(search=c.search, displayer=c.user)
+ c.gallery = GalleryWidget(search=c.search, page=c.user.primary_page)
elixir.session.commit()
redirect(url(controller="users", action="view", name=c.user.name))
tag = h.get_object_or_404(Tag, id=id)
elixir.session.delete(tag)
elixir.session.commit()
- redirect(url('art', id=art_id))
+ redirect(url('show_art', id=art_id))
# TODO: login required
def create(self, art_id):
c.art = h.get_object_or_404(Art, id=art_id)
c.art.add_tags(request.params["tags"], c.user)
elixir.session.commit()
- redirect(url('art', id=c.art.id))
+ redirect(url('show_art', id=c.art.id))
class Art(Entity):
title = Field(Unicode(120))
original_filename = Field(Unicode(120))
- hash = Field(String)
+ hash = Field(String, unique=True, required=True)
- uploader = ManyToOne('User')
+ uploader = ManyToOne('User', required=True)
tags = OneToMany('Tag')
# def __init__(self, **kwargs):
def set_file(self, file):
self.hash = save_file("art", file)
+ self.original_filename = file.filename
file = property(get_path, set_file)
class GalleryWidget(Entity):
+ page = ManyToOne('UserPage')
search = ManyToOne(SavedSearch)
- displayer = ManyToOne('User') # determines whose page should it should show up on
- # Could be no-ones, if it's just a template.
+
+ # NOTE: no longer needed now that we have pages, I guess.
+ # displayer = ManyToOne('User') # determines whose page should it should show up on
+ # # Could be no-ones, if it's just a template.
# Needs some fields for position on your page
@string.setter
def string(self, value):
# TODO: should we delete the possibly orphaned saved search?
- if not self.displayer:
- # TODO: may have to refactor this into an init if the key ordering is inconvenienc
- raise "Oh no! This gallery needs a displayer to set on the saved search."
-
- self.search = SavedSearch(author=self.displayer, string=value)
-
+ # if not self.displayer:
+ # # TODO: may have to refactor this into an init if the key ordering is inconvenienc
+ # raise "Oh no! This gallery needs a displayer to set on the saved search."
-# class UserPage(Entity):
-# owner = ManyToOne('User')
-# visible = Field(Boolean)
\ No newline at end of file
+ self.search = SavedSearch(author=getattr(self,"author",None), string=value)
+
\ No newline at end of file
# from elixir import Entity, Field, Unicode, belongs_to, has_many
from elixir import *
+from search import GalleryWidget
class User(Entity):
name = Field(Unicode(20))
uploads = OneToMany('Art')
has_many('identity_urls', of_kind='IdentityURL')
searches = OneToMany('SavedSearch')
- galleries = OneToMany('GalleryWidget')
+ # galleries = OneToMany('GalleryWidget')
+ pages = OneToMany('UserPage', inverse="owner")
+ primary_page = OneToOne('UserPage', inverse="owner")
+
def __unicode__(self):
return self.name
+ def __init__(self, **kwargs):
+ super(User, self).__init__(**kwargs)
+
+
+
+ # TODO: have this clone a standard starter page
+ self.primary_page = UserPage(owner=self, title="default", visible=True)
+
+ # a starter gallery, just for fun
+ gallery = GalleryWidget(owner=self, string="awesome")
+ self.primary_page.galleries.append(gallery)
+
+
class IdentityURL(Entity):
url = Field(Unicode(255))
belongs_to('user', of_kind='User')
+
+
+class UserPage(Entity):
+ """A user can have multiple pages, though by default they only have one visible.
+ This is so that they can keep some nice themed pages lying around for special occasions.
+ Page templates that provide familiar interfaces will also be UserPage records. Users will
+ see a panel full of them, and they can choose to clone those template pages to their own page list.
+ If more than one is set to visible, there would be tabs.
+
+ """
+
+ owner = ManyToOne('User', inverse="pages")
+ title = Field(String)
+
+ visible = Field(Boolean)
+ galleries = OneToMany('GalleryWidget')
\ No newline at end of file
<p>Registering from <strong>${c.identity_url}</strong>.</p>
-${h.form(url.current(action='register_finish'), method='POST')}
+${h.form(url('register_finish'), method='POST')}
<dl class="form">
<dt>Username</dt>
<dd>${h.text('username', value=c.username)}</dd>
<h1>Add New Art</h1>
<p>Now: Upload a file. Later: Supply a link? Not exclusive to uploading.</p>
-${h.form(h.url_for(controller='art', action='upload'), multipart=True)}
+${h.form(h.url('create_art'), multipart=True)}
${h.file('file')}
${h.submit(None, 'Upload!')}
${h.end_form()}
</div>
+
+<% messages = h.flash.pop_messages() %>
+% if messages:
+<ul id="flash-messages">
+ % for message in messages:
+ <li>${message}</li>
+ % endfor
+</ul>
+% endif
+
+
<div id="body">
${next.body()}
</div>
<ul class="artwork-grid">
% for item in art:
<li>
- <a href="${h.url("art", id=item.id)}">
+ <a href="${h.url("show_art", id=item.id)}">
<img width="180" src="${item.get_path()}">
</a>
</li>
<p>This is the userpage for ${c.this_user.name}.</p>
-% for gallery in c.this_user.galleries:
+% for gallery in c.this_user.primary_page.galleries:
<h2>${gallery.string}</h2>
${macros.thumbs(gallery.search.results)}
% endfor
\ No newline at end of file