From 065bd5b754cc6e6ea5da17e11a939f7a5b34da75 Mon Sep 17 00:00:00 2001 From: Eevee Date: Sun, 15 Nov 2009 21:21:07 -0800 Subject: [PATCH] Added a watch/unwatch button to user pages. --- floof/config/routing.py | 10 ++-- floof/controllers/user_settings.py | 79 ++++++++++++++++++++++++++++ floof/controllers/users.py | 9 +++- floof/lib/base.py | 11 +++- floof/model/forms.py | 37 +++++++++++++ floof/templates/base.mako | 2 +- floof/templates/users/view.mako | 20 ++++++- floof/tests/functional/test_user_settings.py | 7 +++ 8 files changed, 168 insertions(+), 7 deletions(-) create mode 100644 floof/controllers/user_settings.py create mode 100644 floof/model/forms.py create mode 100644 floof/tests/functional/test_user_settings.py diff --git a/floof/config/routing.py b/floof/config/routing.py index 02e597f..44462f8 100644 --- a/floof/config/routing.py +++ b/floof/config/routing.py @@ -42,9 +42,13 @@ def make_map(): 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') + # Specific user stuff + with map.submapper(controller='users') as sub: + sub.connect( '/users', action='list') + sub.connect('user_page', '/users/{name}', action='view') + with map.submapper(controller='user_settings') as sub: + sub.connect( '/users/{name}/settings/relationships/toggle', + action='rel_toggle', **require_POST) # Comments with map.submapper(controller='comments') as sub: diff --git a/floof/controllers/user_settings.py b/floof/controllers/user_settings.py new file mode 100644 index 0000000..8d8adf0 --- /dev/null +++ b/floof/controllers/user_settings.py @@ -0,0 +1,79 @@ +import logging + +import elixir +from pylons import request, response, session, tmpl_context as c +from pylons.controllers.util import abort, redirect_to +from sqlalchemy import func +from sqlalchemy.orm.exc import NoResultFound + +import floof.lib.helpers as h +from floof.lib.base import BaseController, render +from floof.model.users import User, UserRelationship +from floof.model.forms import UserRelationshipToggleForm + +log = logging.getLogger(__name__) + +class UserSettingsController(BaseController): + + def rel_toggle(self, name): + """Adds or removes a single relationship with a single user. + + Expects to be called as a POST with `target_user_id`, + `type`, and `add_remove` as parameters. + """ + try: + user = User.query.filter(func.lower(User.name) == name).one() + except NoResultFound: + abort(404) + + schema = UserRelationshipToggleForm() + try: + form_result = schema.to_python(request.params) + except BaseException, e: + # The data for this form is generated entirely by the app. If + # there are errors, the user has been dicking around. + abort(400) + + # Grab any existing relationship row + rel = None + try: + rel = UserRelationship.query.filter_by( + user_id=user.id, + target_user_id=form_result['target_user'].id, + type=form_result['type'], + ).one() + except: + pass + + # XXX shouldn't include "watching"... + target_name = form_result['target_user'].name + if form_result['add_remove'] == u'add': + # Adding + if rel: + # Already exists! Nothing to do. + h.flash("You're already watching {name}..." + .format(name=target_name)) + else: + # Add it + UserRelationship( + user_id=user.id, + target_user_id=form_result['target_user'].id, + type=form_result['type'], + ) + h.flash("Now watching {name}." + .format(name=target_name)) + else: + # Removing + if rel: + # Toss it + rel.delete() + h.flash("No longer watching {name}. How cruel!." + .format(name=target_name)) + else: + # Already gone! Nothing to do. + h.flash("You're not watching {name}..." + .format(name=target_name)) + + elixir.session.commit() + + self.redirect_to_referrer() diff --git a/floof/controllers/users.py b/floof/controllers/users.py index 1e251f0..1a79c15 100644 --- a/floof/controllers/users.py +++ b/floof/controllers/users.py @@ -6,7 +6,7 @@ from sqlalchemy import func from sqlalchemy.orm.exc import NoResultFound from floof.lib.base import BaseController, render -from floof.model.users import User +from floof.model.users import User, UserRelationship log = logging.getLogger(__name__) @@ -29,4 +29,11 @@ class UsersController(BaseController): except NoResultFound: abort(404) + rels = UserRelationship.query.filter_by( + user_id=c.user.id, + target_user_id=c.this_user.id, + ).all() + + c.relationships = [_.type for _ in rels] + return render('/users/view.mako') diff --git a/floof/lib/base.py b/floof/lib/base.py index 169493c..b42d2be 100644 --- a/floof/lib/base.py +++ b/floof/lib/base.py @@ -3,8 +3,9 @@ Provides the BaseController class for subclassing. """ from pylons.controllers import WSGIController +from pylons.controllers.util import abort, redirect from pylons.templating import render_mako as render -from pylons import config, session, tmpl_context as c +from pylons import config, request, session, tmpl_context as c from routes import request_config from floof import model @@ -34,3 +35,11 @@ class BaseController(WSGIController): return WSGIController.__call__(self, environ, start_response) finally: model.Session.remove() + + + def redirect_to_referrer(self): + """Performs a redirect_to to wherever we came from. Used for stuff + like logging in. + """ + referrer = request.headers.get('REFERER', '/') + redirect(referrer, code=302) diff --git a/floof/model/forms.py b/floof/model/forms.py new file mode 100644 index 0000000..c316c38 --- /dev/null +++ b/floof/model/forms.py @@ -0,0 +1,37 @@ +"""FormEncode validators.""" + +import formencode + +from floof.model.users import User, UserRelationshipTypes + +class UniqueExistingRow(formencode.FancyValidator): + """Given a column object, converts a unique value from that column into the + corresponding row object. + """ + def __init__(self, table, column): + self.table = table + self.column = column + super(formencode.FancyValidator, self).__init__() + + def _to_python(self, value, state): + try: + row = self.table.query.filter(self.column == value).one() + except BaseException, e: + raise formencode.Invalid( + 'No unique row.', + value, state + ) + return row + +### user_settings + +class UserRelationshipToggleForm(formencode.Schema): + target_user = UniqueExistingRow(User, User.id) + type = formencode.compound.Pipe( + formencode.validators.Int(), + formencode.validators.OneOf( + [v for (k, v) in UserRelationshipTypes.__dict__.items() + if k[0] != '_'] + ), + ) + add_remove = formencode.validators.OneOf([u'add', u'remove']) diff --git a/floof/templates/base.mako b/floof/templates/base.mako index 0f3597c..60e8adb 100644 --- a/floof/templates/base.mako +++ b/floof/templates/base.mako @@ -17,7 +17,7 @@ ## | Your Page % endif -${h.form(h.url_for('search'), method='GET')} +${h.form(url('search'), method='GET')} ${h.text('query', c.query)} ${h.submit('button', 'Search')} diff --git a/floof/templates/users/view.mako b/floof/templates/users/view.mako index f9a9329..5b7e12d 100644 --- a/floof/templates/users/view.mako +++ b/floof/templates/users/view.mako @@ -3,7 +3,25 @@

This is the userpage for ${c.this_user.name}.

+<%! from floof.model.users import UserRelationshipTypes %> +% if c.this_user == c.user: +## Nothing +<% pass %>\ +% else: +${h.form(url(controller='user_settings', action='rel_toggle', name=c.user.name.lower()), method='POST')} +

+ + + % if UserRelationshipTypes.IS_WATCHING in c.relationships: + + + % else: + + + % endif +% endif + % for gallery in c.this_user.primary_page.galleries:

${gallery.string}

${macros.thumbs(gallery.search.results)} -% endfor \ No newline at end of file +% endfor diff --git a/floof/tests/functional/test_user_settings.py b/floof/tests/functional/test_user_settings.py new file mode 100644 index 0000000..b28f8be --- /dev/null +++ b/floof/tests/functional/test_user_settings.py @@ -0,0 +1,7 @@ +from floof.tests import * + +class TestUserSettingsController(TestController): + + def test_index(self): + response = self.app.get(url(controller='user_settings', action='index')) + # Test response... -- 2.7.4