diff options
Diffstat (limited to 'docs/tutorials/wiki2')
21 files changed, 281 insertions, 315 deletions
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst index 98e6110f3..e40433497 100644 --- a/docs/tutorials/wiki2/authorization.rst +++ b/docs/tutorials/wiki2/authorization.rst @@ -104,10 +104,8 @@ Open ``tutorial/tutorial/__init__.py`` and add a ``root_factory`` parameter to our :term:`Configurator` constructor, that points to the class we created above: -.. TODO update the lines to include, linenos, lineno-start - .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 24-25 + :lines: 13-14 :emphasize-lines: 2 :language: python @@ -128,18 +126,18 @@ Open ``tutorial/tutorial/__init__.py`` and add the highlighted import statements: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 1-7 + :lines: 1-5 :linenos: - :emphasize-lines: 2-3,7 + :emphasize-lines: 2-5 :language: python Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 21-27 + :lines: 7-16 :linenos: - :lineno-start: 21 - :emphasize-lines: 1-3,6-7 + :lineno-start: 7 + :emphasize-lines: 4-6,9-10 :language: python Only the highlighted lines need to be added. @@ -152,47 +150,50 @@ ticket that may be included in the request. We are also enabling an Note that the :class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor accepts two arguments: ``secret`` and ``callback``. ``secret`` is a string representing an encryption key used by the "authentication ticket" -machinery represented by this policy: it is required. The ``callback`` is the +machinery represented by this policy; it is required. The ``callback`` is the ``groupfinder()`` function that we created before. + Add permission declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/tutorial/views.py`` and add a ``permission='edit'`` parameter -to the ``@view_config`` decorators for ``add_page()`` and ``edit_page()``: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 60-61 +Open ``tutorial/tutorial/views/default.py`` and add a ``permission='view'`` +parameter to the ``@view_config`` decorator for ``view_wiki()`` and +``view_page()`` as follows: + +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 27-29 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 75-76 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 33-35 :emphasize-lines: 1-2 :language: python Only the highlighted lines, along with their preceding commas, need to be edited and added. -The result is that only users who possess the ``edit`` permission at the time -of the request may invoke those two views. +This allows anyone to invoke these two views. -Add a ``permission='view'`` parameter to the ``@view_config`` decorator for -``view_wiki()`` and ``view_page()`` as follows: +Add a ``permission='edit'`` parameter to the ``@view_config`` decorators for +``add_page()`` and ``edit_page()``: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 30-31 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 57-59 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 36-37 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 72-74 :emphasize-lines: 1-2 :language: python Only the highlighted lines, along with their preceding commas, need to be edited and added. -This allows anyone to invoke these two views. +The result is that only users who possess the ``edit`` permission at the time +of the request may invoke those two views. We are done with the changes needed to control access. The changes that follow will add the login and logout feature. @@ -206,7 +207,7 @@ Go back to ``tutorial/tutorial/__init__.py`` and add these two routes as highlighted: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 30-33 + :lines: 20-23 :emphasize-lines: 2-3 :language: python @@ -214,7 +215,7 @@ highlighted: ``view_page`` route definition: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 33 + :lines: 23 :language: python This is because ``view_page``'s route definition uses a catch-all @@ -234,11 +235,11 @@ We'll also add a ``logout`` view callable to our application and provide a link to it. This view will clear the credentials of the logged in user and redirect back to the front page. -Add the following import statements to the head of -``tutorial/tutorial/views.py``: +Add the following import statements to ``tutorial/tutorial/views/default.py`` +after the import from ``pyramid.httpexceptions``: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 9-19 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 10-20 :emphasize-lines: 1-11 :language: python @@ -251,18 +252,18 @@ cookie. Now add the ``login`` and ``logout`` views at the end of the file: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 91-123 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 88-121 :language: python ``login()`` has two decorators: - a ``@view_config`` decorator which associates it with the ``login`` route - and makes it visible when we visit ``/login``, + and makes it visible when we visit ``/login``, and - a ``@forbidden_view_config`` decorator which turns it into a :term:`forbidden view`. ``login()`` will be invoked when a user tries to execute a view callable for which they lack authorization. For example, if - a user has not logged in and tries to add or edit a Wiki page, they will be + a user has not logged in and tries to add or edit a wiki page, they will be shown the login form before being allowed to continue. The order of these two :term:`view configuration` decorators is unimportant. @@ -270,36 +271,36 @@ The order of these two :term:`view configuration` decorators is unimportant. ``logout()`` is decorated with a ``@view_config`` decorator which associates it with the ``logout`` route. It will be invoked when we visit ``/logout``. -Add the ``login.pt`` Template -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Add the ``login.jinja2`` template +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create ``tutorial/tutorial/templates/login.pt`` with the following content: +Create ``tutorial/tutorial/templates/login.jinja2`` with the following content: -.. literalinclude:: src/authorization/tutorial/templates/login.pt +.. literalinclude:: src/authorization/tutorial/templates/login.jinja2 :language: html The above template is referenced in the login view that we just added in -``views.py``. +``views/default.py``. Return a ``logged_in`` flag to the renderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/tutorial/views.py`` again. Add a ``logged_in`` parameter to -the return value of ``view_page()``, ``edit_page()``, and ``add_page()`` as -follows: +Open ``tutorial/tutorial/views/default.py`` again. Add a ``logged_in`` +parameter to the return value of ``view_page()``, ``add_page()``, and +``edit_page()`` as follows: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 57-58 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 54-55 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 72-73 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 69-70 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 85-89 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 82-86 :emphasize-lines: 3-4 :language: python @@ -311,19 +312,19 @@ the user is not authenticated, or a userid if the user is authenticated. Add a "Logout" link when logged in ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/tutorial/templates/edit.pt`` and -``tutorial/tutorial/templates/view.pt`` and add the following code as +Open ``tutorial/tutorial/templates/edit.jinja2`` and +``tutorial/tutorial/templates/view.jinja2`` and add the following code as indicated by the highlighted lines. -.. literalinclude:: src/authorization/tutorial/templates/edit.pt - :lines: 34-38 - :emphasize-lines: 3-5 +.. literalinclude:: src/authorization/tutorial/templates/edit.jinja2 + :lines: 34-40 + :emphasize-lines: 3-7 :language: html -The attribute ``tal:condition="logged_in"`` will make the element be included -when ``logged_in`` is any user id. The link will invoke the logout view. The -above element will not be included if ``logged_in`` is ``None``, such as when -a user is not authenticated. +The attribute ``logged_in`` will make the element be included when +``logged_in`` is any user id. The link will invoke the logout view. The above +element will not be included if ``logged_in`` is ``None``, such as when a user +is not authenticated. Reviewing our changes --------------------- @@ -332,7 +333,7 @@ Our ``tutorial/tutorial/__init__.py`` will look like this when we're done: .. literalinclude:: src/authorization/tutorial/__init__.py :linenos: - :emphasize-lines: 2-3,7,21-23,25-27,31-32 + :emphasize-lines: 2-3,5,10-12,14-16,21-22 :language: python Only the highlighted lines need to be added or edited. @@ -346,31 +347,31 @@ Our ``tutorial/tutorial/models/mymodel.py`` will look like this when we're done: Only the highlighted lines need to be added or edited. -Our ``tutorial/tutorial/views.py`` will look like this when we're done: +Our ``tutorial/tutorial/views/default.py`` will look like this when we're done: -.. literalinclude:: src/authorization/tutorial/views.py +.. literalinclude:: src/authorization/tutorial/views/default.py :linenos: - :emphasize-lines: 9-11,14-19,25,31,37,58,61,73,76,88,91-117,119-123 + :emphasize-lines: 10-20,27-28,33-34,54-55,57-58,69-70,72-73,84-85,88-121 :language: python Only the highlighted lines need to be added or edited. -Our ``tutorial/tutorial/templates/edit.pt`` template will look like this when +Our ``tutorial/tutorial/templates/edit.jinja2`` template will look like this when we're done: -.. literalinclude:: src/authorization/tutorial/templates/edit.pt +.. literalinclude:: src/authorization/tutorial/templates/edit.jinja2 :linenos: - :emphasize-lines: 36-38 + :emphasize-lines: 36-40 :language: html Only the highlighted lines need to be added or edited. -Our ``tutorial/tutorial/templates/view.pt`` template will look like this when +Our ``tutorial/tutorial/templates/view.jinja2`` template will look like this when we're done: -.. literalinclude:: src/authorization/tutorial/templates/view.pt +.. literalinclude:: src/authorization/tutorial/templates/view.jinja2 :linenos: - :emphasize-lines: 36-38 + :emphasize-lines: 36-40 :language: html Only the highlighted lines need to be added or edited. @@ -405,5 +406,3 @@ following URLs, checking that the result is as expected: the login form with the ``editor`` credentials), we'll see a Logout link in the upper right hand corner. When we click it, we're logged out, and redirected back to the front page. - -.. TODO update the lines to include in src/authorization/tutorial/__init__.py diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini index a9d53b296..99c4ff0fe 100644 --- a/docs/tutorials/wiki2/src/authorization/development.ini +++ b/docs/tutorials/wiki2/src/authorization/development.ini @@ -27,7 +27,7 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite [server:main] use = egg:waitress#main -host = 0.0.0.0 +host = 127.0.0.1 port = 6543 ### @@ -68,4 +68,4 @@ level = NOTSET formatter = generic [formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/docs/tutorials/wiki2/src/authorization/production.ini b/docs/tutorials/wiki2/src/authorization/production.ini index 4684d2f7a..97acfbd7d 100644 --- a/docs/tutorials/wiki2/src/authorization/production.ini +++ b/docs/tutorials/wiki2/src/authorization/production.ini @@ -1,3 +1,8 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + [app:main] use = egg:tutorial @@ -16,7 +21,10 @@ use = egg:waitress#main host = 0.0.0.0 port = 6543 -# Begin logging configuration +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### [loggers] keys = root, tutorial, sqlalchemy @@ -51,6 +59,4 @@ level = NOTSET formatter = generic [formatter_generic] -format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s - -# End logging configuration +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py index 09bd63d33..d4e5a4072 100644 --- a/docs/tutorials/wiki2/src/authorization/setup.py +++ b/docs/tutorials/wiki2/src/authorization/setup.py @@ -10,7 +10,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'pyramid', - 'pyramid_chameleon', + 'pyramid_jinja2', 'pyramid_debugtoolbar', 'pyramid_tm', 'SQLAlchemy', diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py index 2ada42171..084fee19f 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py @@ -2,30 +2,20 @@ from pyramid.config import Configurator from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy -from sqlalchemy import engine_from_config - -from tutorial.security import groupfinder - -from .models import ( - DBSession, - Base, - ) - +from security.default import groupfinder def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - engine = engine_from_config(settings, 'sqlalchemy.') - DBSession.configure(bind=engine) - Base.metadata.bind = engine authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() config = Configurator(settings=settings, - root_factory='tutorial.models.RootFactory') + root_factory='tutorial.models.mymodel.RootFactory') config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) - config.include('pyramid_chameleon') + config.include('pyramid_jinja2') + config.include('.models.meta') config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('view_wiki', '/') config.add_route('login', '/login') diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py new file mode 100644 index 000000000..7b1c62867 --- /dev/null +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py @@ -0,0 +1,7 @@ +from sqlalchemy.orm import configure_mappers +# import all models classes here for sqlalchemy mappers +# to pick up +from .mymodel import Page # flake8: noqa + +# run configure mappers to ensure we avoid any race conditions +configure_mappers() diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/meta.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/meta.py new file mode 100644 index 000000000..b72b45f9f --- /dev/null +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/meta.py @@ -0,0 +1,46 @@ +from sqlalchemy import engine_from_config +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from sqlalchemy.schema import MetaData +import zope.sqlalchemy + +NAMING_CONVENTION = { + "ix": 'ix_%(column_0_label)s', + "uq": "uq_%(table_name)s_%(column_0_name)s", + "ck": "ck_%(table_name)s_%(constraint_name)s", + "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", + "pk": "pk_%(table_name)s" +} + +metadata = MetaData(naming_convention=NAMING_CONVENTION) +Base = declarative_base(metadata=metadata) + + +def includeme(config): + settings = config.get_settings() + dbmaker = get_dbmaker(get_engine(settings)) + + config.add_request_method( + lambda r: get_session(r.tm, dbmaker), + 'dbsession', + reify=True + ) + + config.include('pyramid_tm') + + +def get_session(transaction_manager, dbmaker): + dbsession = dbmaker() + zope.sqlalchemy.register(dbsession, + transaction_manager=transaction_manager) + return dbsession + + +def get_engine(settings, prefix='sqlalchemy.'): + return engine_from_config(settings, prefix) + + +def get_dbmaker(engine): + dbmaker = sessionmaker() + dbmaker.configure(bind=engine) + return dbmaker diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/mymodel.py index 4f7e1e024..03e2f90ca 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/models.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/mymodel.py @@ -1,3 +1,5 @@ +from .meta import Base + from pyramid.security import ( Allow, Everyone, @@ -9,29 +11,16 @@ from sqlalchemy import ( Text, ) -from sqlalchemy.ext.declarative import declarative_base - -from sqlalchemy.orm import ( - scoped_session, - sessionmaker, - ) - -from zope.sqlalchemy import ZopeTransactionExtension - -DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) -Base = declarative_base() - class Page(Base): """ The SQLAlchemy declarative model class for a Page object. """ __tablename__ = 'pages' id = Column(Integer, primary_key=True) name = Column(Text, unique=True) - data = Column(Text) - + data = Column(Integer) class RootFactory(object): __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'edit') ] def __init__(self, request): - pass + pass
\ No newline at end of file diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/scripts/initializedb.py b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/initializedb.py index 23a5f13f4..4aac4a848 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/scripts/initializedb.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/initializedb.py @@ -2,36 +2,41 @@ import os import sys import transaction -from sqlalchemy import engine_from_config - from pyramid.paster import ( get_appsettings, setup_logging, ) -from ..models import ( - DBSession, - Page, +from ..models.meta import ( Base, + get_session, + get_engine, + get_dbmaker, ) +from ..models.mymodel import Page def usage(argv): cmd = os.path.basename(argv[0]) - print('usage: %s <config_uri>\n' + print('usage: %s <config_uri> [var=value]\n' '(example: "%s development.ini")' % (cmd, cmd)) sys.exit(1) def main(argv=sys.argv): - if len(argv) != 2: + if len(argv) < 2: usage(argv) config_uri = argv[1] setup_logging(config_uri) settings = get_appsettings(config_uri) - engine = engine_from_config(settings, 'sqlalchemy.') - DBSession.configure(bind=engine) + + engine = get_engine(settings) + dbmaker = get_dbmaker(engine) + + dbsession = get_session(transaction.manager, dbmaker) + Base.metadata.create_all(engine) + with transaction.manager: model = Page(name='FrontPage', data='This is the front page') - DBSession.add(model) + dbsession.add(model) diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/security/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/security/__init__.py new file mode 100644 index 000000000..5bb534f79 --- /dev/null +++ b/docs/tutorials/wiki2/src/authorization/tutorial/security/__init__.py @@ -0,0 +1 @@ +# package diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/security.py b/docs/tutorials/wiki2/src/authorization/tutorial/security/default.py index d88c9c71f..d88c9c71f 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/security.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/security/default.py diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/theme.min.css b/docs/tutorials/wiki2/src/authorization/tutorial/static/theme.min.css index 2f924bcc5..0d25de5b6 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/static/theme.min.css +++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/theme.min.css @@ -1 +1 @@ -@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a{color:#fff}.starter-template .links ul li a:hover{text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}}
\ No newline at end of file +@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a,a{color:#f2b7bd;text-decoration:underline}.starter-template .links ul li a:hover,a:hover{color:#fff;text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}} diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.jinja2 index ed355434d..c4f3a2c93 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.jinja2 @@ -1,21 +1,20 @@ <!DOCTYPE html> -<html lang="${request.locale_name}"> +<html lang="{{request.locale_name}}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="pyramid web application"> <meta name="author" content="Pylons Project"> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}"> + <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}"> - <title>${page.name} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki)</title> + <title>Edit{% if page.name %} {{page.name}}{% endif %} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title> <!-- Bootstrap core CSS --> <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this scaffold --> - <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet"> + <link href="{{request.static_url('tutorial:static/theme.css')}}" rel="stylesheet"> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> @@ -23,29 +22,31 @@ <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]--> </head> + <body> <div class="starter-template"> <div class="container"> <div class="row"> <div class="col-md-2"> - <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework"> + <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework"> </div> <div class="col-md-10"> <div class="content"> - <p tal:condition="logged_in" class="pull-right"> - <a href="${request.application_url}/logout">Logout</a> + {% if logged_in %} + <p class="pull-right"> + <a href="{{ request.application_url }}/logout">Logout</a> </p> + {% endif %} <p> - Editing <strong><span tal:replace="page.name">Page Name Goes - Here</span></strong> + Editing <strong>{% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %}</strong> </p> <p>You can return to the - <a href="${request.application_url}">FrontPage</a>. + <a href="{{request.application_url}}">FrontPage</a>. </p> - <form action="${save_url}" method="post"> + <form action="{{ save_url }}" method="post"> <div class="form-group"> - <textarea class="form-control" name="body" tal:content="page.data" rows="10" cols="60"></textarea> + <textarea class="form-control" name="body" rows="10" cols="60">{{ page.data }}</textarea> </div> <div class="form-group"> <button type="submit" name="form.submitted" value="Save" class="btn btn-default">Save</button> diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 index c9b0cec21..ff624c65b 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 @@ -1,12 +1,12 @@ <!DOCTYPE html> -<html lang="${request.locale_name}"> +<html lang="{{request.locale_name}}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="pyramid web application"> <meta name="author" content="Pylons Project"> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}"> + <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}"> <title>Alchemy Scaffold for The Pyramid Web Framework</title> @@ -14,7 +14,7 @@ <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this scaffold --> - <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet"> + <link href="{{request.static_url('tutorial:static/theme.css')}}" rel="stylesheet"> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> @@ -29,19 +29,19 @@ <div class="container"> <div class="row"> <div class="col-md-2"> - <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework"> + <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework"> </div> <div class="col-md-10"> - <div class="content"> - <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1> - <p class="lead">Welcome to <span class="font-normal">${project}</span>, an application generated by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p> - </div> + {% block content %} + <p>No content</p> + {% endblock content %} </div> </div> <div class="row"> <div class="links"> <ul> - <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/latest/">Docs</a></li> + <li class="current-version">Generated by v1.7.dev0</li> + <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li> <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li> <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li> <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li> diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.jinja2 index 4a938e9bb..a80a2a165 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.jinja2 @@ -1,21 +1,20 @@ <!DOCTYPE html> -<html lang="${request.locale_name}"> +<html lang="{{request.locale_name}}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="pyramid web application"> <meta name="author" content="Pylons Project"> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}"> + <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}"> - <title>Login - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki)</title> + <title>Login - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title> <!-- Bootstrap core CSS --> <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this scaffold --> - <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet"> + <link href="{{request.static_url('tutorial:static/theme.css')}}" rel="stylesheet"> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> @@ -23,13 +22,14 @@ <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]--> </head> + <body> <div class="starter-template"> <div class="container"> <div class="row"> <div class="col-md-2"> - <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework"> + <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework"> </div> <div class="col-md-10"> <div class="content"> @@ -37,17 +37,17 @@ <strong> Login </strong><br> - <span tal:replace="message"></span> + {{ message }} </p> - <form action="${url}" method="post"> - <input type="hidden" name="came_from" value="${came_from}"> + <form action="{{ url }}" method="post"> + <input type="hidden" name="came_from" value="{{ came_from }}"> <div class="form-group"> <label for="login">Username</label> - <input type="text" name="login" value="${login}"> + <input type="text" name="login" value="{{ login }}"> </div> <div class="form-group"> <label for="password">Password</label> - <input type="password" name="password" value="${password}"> + <input type="password" name="password" value="{{ password }}"> </div> <div class="form-group"> <button type="submit" name="form.submitted" value="Log In" class="btn btn-default">Log In</button> diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.jinja2 new file mode 100644 index 000000000..bb622bf5a --- /dev/null +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.jinja2 @@ -0,0 +1,8 @@ +{% extends "layout.jinja2" %} + +{% block content %} +<div class="content"> + <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1> + <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, an application generated by<br>the <span class="font-normal">Pyramid Web Framework 1.7.dev0</span>.</p> +</div> +{% endblock content %} diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.jinja2 index 02cb8e73b..a7afc66fc 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt +++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.jinja2 @@ -1,21 +1,20 @@ <!DOCTYPE html> -<html lang="${request.locale_name}"> +<html lang="{{request.locale_name}}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="pyramid web application"> <meta name="author" content="Pylons Project"> - <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}"> + <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}"> - <title>${page.name} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki)</title> + <title>{{page.name}} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title> <!-- Bootstrap core CSS --> <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this scaffold --> - <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet"> + <link href="{{request.static_url('tutorial:static/theme.css')}}" rel="stylesheet"> <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> @@ -23,33 +22,33 @@ <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]--> </head> + <body> <div class="starter-template"> <div class="container"> <div class="row"> <div class="col-md-2"> - <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework"> + <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework"> </div> <div class="col-md-10"> <div class="content"> - <p tal:condition="logged_in" class="pull-right"> - <a href="${request.application_url}/logout">Logout</a> + {% if logged_in %} + <p class="pull-right"> + <a href="{{ request.application_url }}/logout">Logout</a> </p> - <div tal:replace="structure content"> - Page text goes here. - </div> + {% endif %} + <p>{{ content|safe }}</p> <p> - <a tal:attributes="href edit_url" href=""> + <a href="{{ edit_url }}"> Edit this page </a> </p> <p> - Viewing <strong><span tal:replace="page.name"> - Page Name Goes Here</span></strong> + Viewing <strong>{% if page.name %}{{page.name}}{% else %}Page Name Goes Here{% endif %}</strong> </p> <p>You can return to the - <a href="${request.application_url}">FrontPage</a>. + <a href="{{request.application_url}}">FrontPage</a>. </p> </div> </div> diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py index 9f01d2da5..b947e3bb1 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py @@ -3,144 +3,63 @@ import transaction from pyramid import testing -def _initTestingDB(): - from sqlalchemy import create_engine - from tutorial.models import ( - DBSession, - Page, - Base - ) - engine = create_engine('sqlite://') - Base.metadata.create_all(engine) - DBSession.configure(bind=engine) - with transaction.manager: - model = Page(name='FrontPage', data='This is the front page') - DBSession.add(model) - return DBSession - -def _registerRoutes(config): - config.add_route('view_page', '{pagename}') - config.add_route('edit_page', '{pagename}/edit_page') - config.add_route('add_page', 'add_page/{pagename}') - -class ViewWikiTests(unittest.TestCase): + +def dummy_request(dbsession): + return testing.DummyRequest(dbsession=dbsession) + + +class BaseTest(unittest.TestCase): def setUp(self): - self.config = testing.setUp() - self.session = _initTestingDB() + self.config = testing.setUp(settings={ + 'sqlalchemy.url': 'sqlite:///:memory:' + }) + self.config.include('.models.meta') + settings = self.config.get_settings() - def tearDown(self): - self.session.remove() - testing.tearDown() + from .models.meta import ( + get_session, + get_engine, + get_dbmaker, + ) - def _callFUT(self, request): - from tutorial.views import view_wiki - return view_wiki(request) + self.engine = get_engine(settings) + dbmaker = get_dbmaker(self.engine) - def test_it(self): - _registerRoutes(self.config) - request = testing.DummyRequest() - response = self._callFUT(request) - self.assertEqual(response.location, 'http://example.com/FrontPage') + self.session = get_session(transaction.manager, dbmaker) -class ViewPageTests(unittest.TestCase): - def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() + def init_database(self): + from .models.meta import Base + Base.metadata.create_all(self.engine) def tearDown(self): - self.session.remove() - testing.tearDown() - - def _callFUT(self, request): - from tutorial.views import view_page - return view_page(request) - - def test_it(self): - from tutorial.models import Page - request = testing.DummyRequest() - request.matchdict['pagename'] = 'IDoExist' - page = Page(name='IDoExist', data='Hello CruelWorld IDoExist') - self.session.add(page) - _registerRoutes(self.config) - info = self._callFUT(request) - self.assertEqual(info['page'], page) - self.assertEqual( - info['content'], - '<div class="document">\n' - '<p>Hello <a href="http://example.com/add_page/CruelWorld">' - 'CruelWorld</a> ' - '<a href="http://example.com/IDoExist">' - 'IDoExist</a>' - '</p>\n</div>\n') - self.assertEqual(info['edit_url'], - 'http://example.com/IDoExist/edit_page') - - -class AddPageTests(unittest.TestCase): - def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() + from .models.meta import Base - def tearDown(self): - self.session.remove() testing.tearDown() + transaction.abort() + Base.metadata.create_all(self.engine) + + +class TestMyViewSuccessCondition(BaseTest): - def _callFUT(self, request): - from tutorial.views import add_page - return add_page(request) - - def test_it_notsubmitted(self): - _registerRoutes(self.config) - request = testing.DummyRequest() - request.matchdict = {'pagename':'AnotherPage'} - info = self._callFUT(request) - self.assertEqual(info['page'].data,'') - self.assertEqual(info['save_url'], - 'http://example.com/add_page/AnotherPage') - - def test_it_submitted(self): - from tutorial.models import Page - _registerRoutes(self.config) - request = testing.DummyRequest({'form.submitted':True, - 'body':'Hello yo!'}) - request.matchdict = {'pagename':'AnotherPage'} - self._callFUT(request) - page = self.session.query(Page).filter_by(name='AnotherPage').one() - self.assertEqual(page.data, 'Hello yo!') - -class EditPageTests(unittest.TestCase): def setUp(self): - self.session = _initTestingDB() - self.config = testing.setUp() + super(TestMyViewSuccessCondition, self).setUp() + self.init_database() - def tearDown(self): - self.session.remove() - testing.tearDown() + from .models.mymodel import MyModel + + model = MyModel(name='one', value=55) + self.session.add(model) + + def test_passing_view(self): + from .views.default import my_view + info = my_view(dummy_request(self.session)) + self.assertEqual(info['one'].name, 'one') + self.assertEqual(info['project'], 'tutorial') + + +class TestMyViewFailureCondition(BaseTest): - def _callFUT(self, request): - from tutorial.views import edit_page - return edit_page(request) - - def test_it_notsubmitted(self): - from tutorial.models import Page - _registerRoutes(self.config) - request = testing.DummyRequest() - request.matchdict = {'pagename':'abc'} - page = Page(name='abc', data='hello') - self.session.add(page) - info = self._callFUT(request) - self.assertEqual(info['page'], page) - self.assertEqual(info['save_url'], - 'http://example.com/abc/edit_page') - - def test_it_submitted(self): - from tutorial.models import Page - _registerRoutes(self.config) - request = testing.DummyRequest({'form.submitted':True, - 'body':'Hello yo!'}) - request.matchdict = {'pagename':'abc'} - page = Page(name='abc', data='hello') - self.session.add(page) - response = self._callFUT(request) - self.assertEqual(response.location, 'http://example.com/abc') - self.assertEqual(page.data, 'Hello yo!') + def test_failing_view(self): + from .views.default import my_view + info = my_view(dummy_request(self.session)) + self.assertEqual(info.status_int, 500) diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/docs/tutorials/wiki2/src/authorization/tutorial/views/__init__.py diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py index e954d5a31..f35f041a4 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py @@ -1,3 +1,4 @@ +import cgi import re from docutils.core import publish_parts @@ -16,13 +17,9 @@ from pyramid.security import ( forget, ) -from .security import USERS - -from .models import ( - DBSession, - Page, - ) +from ..security.default import USERS +from ..models.mymodel import Page # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") @@ -30,26 +27,26 @@ wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") @view_config(route_name='view_wiki', permission='view') def view_wiki(request): - return HTTPFound(location = request.route_url('view_page', - pagename='FrontPage')) + return HTTPFound(location=request.route_url('view_page', + pagename='FrontPage')) -@view_config(route_name='view_page', renderer='templates/view.pt', +@view_config(route_name='view_page', renderer='templates/view.jinja2', permission='view') def view_page(request): pagename = request.matchdict['pagename'] - page = DBSession.query(Page).filter_by(name=pagename).first() + page = request.dbsession.query(Page).filter_by(name=pagename).first() if page is None: return HTTPNotFound('No such page') def check(match): word = match.group(1) - exists = DBSession.query(Page).filter_by(name=word).all() + exists = request.dbsession.query(Page).filter_by(name=word).all() if exists: view_url = request.route_url('view_page', pagename=word) - return '<a href="%s">%s</a>' % (view_url, word) + return '<a href="%s">%s</a>' % (view_url, cgi.escape(word)) else: add_url = request.route_url('add_page', pagename=word) - return '<a href="%s">%s</a>' % (add_url, word) + return '<a href="%s">%s</a>' % (add_url, cgi.escape(word)) content = publish_parts(page.data, writer_name='html')['html_body'] content = wikiwords.sub(check, content) @@ -57,14 +54,14 @@ def view_page(request): return dict(page=page, content=content, edit_url=edit_url, logged_in=request.authenticated_userid) -@view_config(route_name='add_page', renderer='templates/edit.pt', +@view_config(route_name='add_page', renderer='templates/edit.jinja2', permission='edit') def add_page(request): pagename = request.matchdict['pagename'] if 'form.submitted' in request.params: body = request.params['body'] page = Page(name=pagename, data=body) - DBSession.add(page) + request.dbsession.add(page) return HTTPFound(location = request.route_url('view_page', pagename=pagename)) save_url = request.route_url('add_page', pagename=pagename) @@ -72,24 +69,24 @@ def add_page(request): return dict(page=page, save_url=save_url, logged_in=request.authenticated_userid) -@view_config(route_name='edit_page', renderer='templates/edit.pt', +@view_config(route_name='edit_page', renderer='templates/edit.jinja2', permission='edit') def edit_page(request): pagename = request.matchdict['pagename'] - page = DBSession.query(Page).filter_by(name=pagename).one() + page = request.dbsession.query(Page).filter_by(name=pagename).one() if 'form.submitted' in request.params: page.data = request.params['body'] - DBSession.add(page) + request.dbsession.add(page) return HTTPFound(location = request.route_url('view_page', pagename=pagename)) return dict( page=page, - save_url=request.route_url('edit_page', pagename=pagename), + save_url = request.route_url('edit_page', pagename=pagename), logged_in=request.authenticated_userid ) -@view_config(route_name='login', renderer='templates/login.pt') -@forbidden_view_config(renderer='templates/login.pt') +@view_config(route_name='login', renderer='templates/login.jinja2') +@forbidden_view_config(renderer='templates/login.jinja2') def login(request): login_url = request.route_url('login') referrer = request.url @@ -121,4 +118,3 @@ def logout(request): headers = forget(request) return HTTPFound(location = request.route_url('view_wiki'), headers = headers) - diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/edit.jinja2 b/docs/tutorials/wiki2/src/views/tutorial/templates/edit.jinja2 index ad4cd17e1..b3aadfc2e 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/templates/edit.jinja2 +++ b/docs/tutorials/wiki2/src/views/tutorial/templates/edit.jinja2 @@ -8,7 +8,7 @@ <meta name="author" content="Pylons Project"> <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}"> - <title>{{page.name}} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title> + <title>Edit{% if page.name %} {{page.name}}{% endif %} - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title> <!-- Bootstrap core CSS --> <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> |
