利用者属性の登録

次に、OpenIDで認証した人がニックネームと時差を登録できるようにする。

モデル

  • model/__init__.py
import boto
import jsonpickle

class UserProperty(object):
    def __init__(self,
                 openid = None,
                 nickname = None,
                 time_diff = 0):
        self.openid = openid
        self.nickname = nickname
        self.time_diff = time_diff
        
class UserPropertySDB(object):
    def __init__(self):
        sdb = boto.connect_sdb()
        self.domain = sdb.create_domain('UserProperty')

    def get_item(self, key):
        item = self.domain.get_item(key)
        if item:
            item = jsonpickle.decode(item['userproperty'])
        return item

    def put_item(self, up):
        item = self.domain.get_item(up.openid)
        if item is None:
            item = self.domain.new_item(up.openid)

        item['userproperty'] = jsonpickle.encode(up)
        item.save()
  • モデルUserPropertyについては直球勝負。
  • 美しくないが、__init__.py中にSimpleDBとのやりとりも含めた。(UserPropertySDB)
    • Domain(RDBでいうテーブルみたいな概念)名はUserProperty
    • キーにOpenIDを使う
    • UserPropertyはjsonpickleでシリアライズして格納→スキーマフリーとしてSimpleDBを使ってみる。
    • 保存時には既存キーなら上書き。そうでなければ新規キー追加。

フォーム準備

lib/helpers.py

from routes import url_for

from formbuild.helpers import field
from formbuild import start_with_layout as form_start, end_with_layout as form_end
from webhelpers.html.tags import *
  • フォーム作成に必要なモジュールを取り込んでおく。

clock.py

import logging

from pylons import request, response, session, tmpl_context as c
from pylons.controllers.util import abort, redirect_to

from myclock.lib.base import BaseController, render
import datetime

from authkit.authorize.pylons_adaptors import authorize
from authkit.permissions import RemoteUser
from routes.util import url_for

from myclock.lib import helpers as h

log = logging.getLogger(__name__)

from myclock.model import UserProperty, UserPropertySDB
import formencode
from pylons.decorators.rest import restrict
from pylons.decorators import validate

class TimeDiffForm(formencode.Schema):
    allow_extra_fields = True
    filter_extra_fields = True
    nickname = formencode.validators.String(not_empty = True)
    time_diff = formencode.validators.Int(not_empty = True)

class ClockController(BaseController):
    def __init__(self):
        BaseController.__init__(self)
        self.ups = UserPropertySDB()

    @authorize(RemoteUser())
    def now(self):
        item = self.ups.get_item(request.environ['REMOTE_USER'])

        if item:
            name = item.nickname
            time_diff = item.time_diff
        else:
            name = request.environ['REMOTE_USER']
            time_diff = 0

        time = datetime.datetime.now()

        time = str(time + datetime.timedelta(0, 0, 0, 0, 0, time_diff))
        c.content = "Welcome, %s. Current time is %s (diff is %s)" % (name, time, str(time_diff))

        return render('/derived/clock/now.html')


    @authorize(RemoteUser())
    def customize(self):
        return render('/derived/clock/customize.html')

    @restrict('POST')
    @validate(schema = TimeDiffForm(), form = 'time_diff')
    @authorize(RemoteUser())
    def save(self):
        up = UserProperty(request.environ['REMOTE_USER'],
                          self.form_result['nickname'],
                          int(self.form_result['time_diff']))

        self.ups.put_item(up)
        redirect_to('now')

    def signout(self):
        redirect_to('now')
  • TimeDiffForm...フォーム内容チェックのためのデコレータ。
    • nicknameとtime_diffの型チェックおよび必須チェック
  • ClockController
    • __init__で、SimpleDBとの接続を確立→sqlalchemyみたいにSession()に取り込むのが理想。
    • now()ではSimpleDBから属性を取り込み、表示。データがない場合はOpenIDとゼロがそれぞれ入る。
    • customize()は登録フォーム表示
    • save()はフォームのサブミット先。

templates/derived/clock/now.html

<%inherit file="/base/index.html"/>
${c.content}
<br/>
You can <a href="${h.url_for(action = 'customize')}">customize</a>.
<br/>
<a href="${h.url_for(action = 'signout')}">Signout</a>
  • 時差計算をした時刻を表示するように改造。
  • 属性変更画面へのリンクを追加。

templates/derived/clock/customize.html

<%inherit file="/base/index.html"/>

<%namespace file = "fields.html" name = "fields" import = "*"/>


    ${h.form_start(h.url_for(action = 'save'), method = 'post')}
    ${fields.body()}
    ${h.field(field = h.submit(value = "Save", name = "submit"))}
    ${h.form_end()}
  • 属性登録画面。フォームの項目は次のファイル。

templates/derived/clock/fields.html

${h.field(
  "Nickame",
  h.text(name = 'nickname'),
  required = False,
)}

${h.field(
  "Time Diff",
  h.text(name = 'time_diff'),
  required = False,
)}

表示

OpenID認証すると、こんな感じの画面になる。

customizeを選択して、フォーム表示。

フォームの中身が反映されるの図。

Gitコミット先

目次に戻る