Skip to content

Commit

Permalink
Merge pull request #2385 from stevepiercy/feature/alchemy-scaffold-up…
Browse files Browse the repository at this point in the history
…date

redirect to edit page when user attempts to add page that already exists
  • Loading branch information
mmerickel committed Feb 29, 2016
2 parents 20eac53 + ae5cccc commit 0c185a3
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 63 deletions.
61 changes: 32 additions & 29 deletions docs/tutorials/wiki2/authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,34 +132,34 @@ Open the file ``tutorial/views/default.py`` and fix the following imports:

Change the two highlighted lines.

In the same file, now edit the ``add_page`` view function:
In the same file, now edit the ``edit_page`` view function:

.. literalinclude:: src/authentication/tutorial/views/default.py
:lines: 62-76
:lines: 45-60
:lineno-match:
:emphasize-lines: 3-5,10
:emphasize-lines: 5-7
:language: python

Only the highlighted lines need to be changed.

If the user either is not logged in or is not in the ``basic`` or ``editor``
roles, then we raise ``HTTPForbidden``, which will return a "403 Forbidden"
response to the user. However, we will hook this later to redirect to the login
page. Also, now that we have ``request.user``, we no longer have to hard-code
the creator as the ``editor`` user, so we can finally drop that hack.
If the user either is not logged in or the user is not the page's creator
*and* not an ``editor``, then we raise ``HTTPForbidden``.

Now edit the ``edit_page`` view function:
In the same file, now edit the ``add_page`` view function:

.. literalinclude:: src/authentication/tutorial/views/default.py
:lines: 45-60
:lines: 62-76
:lineno-match:
:emphasize-lines: 5-7
:emphasize-lines: 3-5,13
:language: python

Only the highlighted lines need to be changed.

If the user either is not logged in or the user is not the page's creator
*and* not an ``editor``, then we raise ``HTTPForbidden``.
If the user either is not logged in or is not in the ``basic`` or ``editor``
roles, then we raise ``HTTPForbidden``, which will return a "403 Forbidden"
response to the user. However, we will hook this later to redirect to the login
page. Also, now that we have ``request.user``, we no longer have to hard-code
the creator as the ``editor`` user, so we can finally drop that hack.

These simple checks should protect our views.

Expand Down Expand Up @@ -285,25 +285,28 @@ following URLs, checking that the result is as expected:
while the user is not authenticated, else it is a "Logout" link when the user
is authenticated.

- http://localhost:6543/FrontPage/edit_page invokes the edit view for the
``FrontPage`` object. It is executable by only the ``editor`` user. If a
different user (or the anonymous user) invokes it, then a login form will be
displayed. Supplying the credentials with the username ``editor`` and
- http://localhost:6543/FrontPage/edit_page invokes the ``edit_page`` view for
the ``FrontPage`` page object. It is executable by only the ``editor`` user.
If a different user (or the anonymous user) invokes it, then a login form
will be displayed. Supplying the credentials with the username ``editor`` and
password ``editor`` will display the edit page form.

- http://localhost:6543/add_page/SomePageName invokes the add view for a page.
It is executable by either the ``editor`` or ``basic`` user. If a different
user (or the anonymous user) invokes it, then a login form will be displayed.
Supplying the credentials with either the username ``editor`` and password
``editor``, or username ``basic`` and password ``basic``, will display the
edit page form.
- http://localhost:6543/add_page/SomePageName invokes the ``add_page`` view for
a page. If the page already exists, then it redirects the user to the
``edit_page`` view for the page object. It is executable by either the
``editor`` or ``basic`` user. If a different user (or the anonymous user)
invokes it, then a login form will be displayed. Supplying the credentials
with either the username ``editor`` and password ``editor``, or username
``basic`` and password ``basic``, will display the edit page form.

- http://localhost:6543/SomePageName/edit_page is editable by the ``basic``
user if the page was created by that user in the previous step. If, instead,
the page was created by the ``editor`` user, then the login page should be
shown for the ``basic`` user.
- http://localhost:6543/SomePageName/edit_page invokes the ``edit_page`` view
for an existing page, or generates an error if the page does not exist. It is
editable by the ``basic`` user if the page was created by that user in the
previous step. If, instead, the page was created by the ``editor`` user, then
the login page should be shown for the ``basic`` user.

- After logging in (as a result of hitting an edit or add page and submitting
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.
the upper right hand corner. When we click it, we're logged out, redirected
back to the front page, and a "Login" link is shown in the upper right hand
corner.
51 changes: 27 additions & 24 deletions docs/tutorials/wiki2/authorization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Open the file ``tutorial/routes.py`` and edit the following lines:

.. literalinclude:: src/authorization/tutorial/routes.py
:linenos:
:emphasize-lines: 1-7,14-50
:emphasize-lines: 1-11,17-
:language: python

The highlighted lines need to be edited or added.
Expand All @@ -120,34 +120,34 @@ the principals of either ``role:editor`` or ``role:basic`` to have the
``create`` permission:

.. literalinclude:: src/authorization/tutorial/routes.py
:lines: 20-32
:lines: 30-38
:lineno-match:
:emphasize-lines: 11,12
:emphasize-lines: 5-9
:language: python

The ``NewPage`` is loaded as the :term:`context` of the ``add_page`` route by
declaring a ``factory`` on the route:

.. literalinclude:: src/authorization/tutorial/routes.py
:lines: 15-16
:lines: 18-19
:lineno-match:
:emphasize-lines: 2
:emphasize-lines: 1-2
:language: python

The ``PageResource`` class defines the :term:`ACL` for a ``Page``. It uses an
actual ``Page`` object to determine *who* can do *what* to the page.

.. literalinclude:: src/authorization/tutorial/routes.py
:lines: 34-50
:lines: 47-
:lineno-match:
:emphasize-lines: 14-16
:emphasize-lines: 5-10
:language: python

The ``PageResource`` is loaded as the :term:`context` of the ``view_page`` and
``edit_page`` routes by declaring a ``factory`` on the routes:

.. literalinclude:: src/authorization/tutorial/routes.py
:lines: 14-18
:lines: 17-21
:lineno-match:
:emphasize-lines: 1,4-5
:language: python
Expand Down Expand Up @@ -236,25 +236,28 @@ following URLs, checking that the result is as expected:
while the user is not authenticated, else it is a "Logout" link when the user
is authenticated.

- http://localhost:6543/FrontPage/edit_page invokes the edit view for the
``FrontPage`` object. It is executable by only the ``editor`` user. If a
different user (or the anonymous user) invokes it, then a login form will be
displayed. Supplying the credentials with the username ``editor`` and
- http://localhost:6543/FrontPage/edit_page invokes the ``edit_page`` view for
the ``FrontPage`` page object. It is executable by only the ``editor`` user.
If a different user (or the anonymous user) invokes it, then a login form
will be displayed. Supplying the credentials with the username ``editor`` and
password ``editor`` will display the edit page form.

- http://localhost:6543/add_page/SomePageName invokes the add view for a page.
It is executable by either the ``editor`` or ``basic`` user. If a different
user (or the anonymous user) invokes it, then a login form will be displayed.
Supplying the credentials with either the username ``editor`` and password
``editor``, or username ``basic`` and password ``basic``, will display the
edit page form.
- http://localhost:6543/add_page/SomePageName invokes the ``add_page`` view for
a page. If the page already exists, then it redirects the user to the
``edit_page`` view for the page object. It is executable by either the
``editor`` or ``basic`` user. If a different user (or the anonymous user)
invokes it, then a login form will be displayed. Supplying the credentials
with either the username ``editor`` and password ``editor``, or username
``basic`` and password ``basic``, will display the edit page form.

- http://localhost:6543/SomePageName/edit_page is editable by the ``basic``
user if the page was created by that user in the previous step. If, instead,
the page was created by the ``editor`` user, then the login page should be
shown for the ``basic`` user.
- http://localhost:6543/SomePageName/edit_page invokes the ``edit_page`` view
for an existing page, or generates an error if the page does not exist. It is
editable by the ``basic`` user if the page was created by that user in the
previous step. If, instead, the page was created by the ``editor`` user, then
the login page should be shown for the ``basic`` user.

- After logging in (as a result of hitting an edit or add page and submitting
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.
the upper right hand corner. When we click it, we're logged out, redirected
back to the front page, and a "Login" link is shown in the upper right hand
corner.
23 changes: 16 additions & 7 deletions docs/tutorials/wiki2/definingviews.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ edit it to look like the following:
.. literalinclude:: src/views/tutorial/views/default.py
:linenos:
:language: python
:emphasize-lines: 1-9,12-70
:emphasize-lines: 1-9,12-

The highlighted lines need to be added or edited.

Expand Down Expand Up @@ -277,7 +277,7 @@ The ``add_page`` view function
Here is the code for the ``add_page`` view function and its decorator:

.. literalinclude:: src/views/tutorial/views/default.py
:lines: 58-70
:lines: 58-
:lineno-match:
:linenos:
:language: python
Expand All @@ -294,6 +294,10 @@ page we'd like to add. If our add view is invoked via, for example,
``http://localhost:6543/add_page/SomeName``, the value for ``'pagename'`` in
the ``matchdict`` will be ``'SomeName'``.

Next a check is performed to determine whether the ``Page`` already exists in
the database. If it already exists, then the client is redirected to the
``edit_page`` view, else we continue to the next check.

If the view execution *is* a result of a form submission (i.e., the expression
``'form.submitted' in request.params`` is ``True``), we grab the page body from
the form data, create a Page object with this page body and the name taken from
Expand Down Expand Up @@ -452,13 +456,18 @@ each of the following URLs, checking that the result is as expected:
- http://localhost:6543/ invokes the ``view_wiki`` view. This always
redirects to the ``view_page`` view of the ``FrontPage`` page object.

- http://localhost:6543/FrontPage invokes the ``view_page`` view of the front
page object.
- http://localhost:6543/FrontPage invokes the ``view_page`` view of the
``FrontPage`` page object.

- http://localhost:6543/FrontPage/edit_page invokes the ``edit_page`` view for
the ``FrontPage`` page object.

- http://localhost:6543/FrontPage/edit_page invokes the edit view for the
front page object.
- http://localhost:6543/add_page/SomePageName invokes the ``add_page`` view for
a page. If the page already exists, then it redirects the user to the
``edit_page`` view for the page object.

- http://localhost:6543/add_page/SomePageName invokes the add view for a page.
- http://localhost:6543/SomePageName/edit_page invokes the ``edit_page`` view
for an existing page, or generates an error if the page does not exist.

- To generate an error, visit http://localhost:6543/foobars/edit_page which
will generate a ``NoResultFound: No row was found for one()`` error. You'll
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ def add_page(request):
if user is None or user.role not in ('editor', 'basic'):
raise HTTPForbidden
pagename = request.matchdict['pagename']
if request.dbsession.query(Page).filter_by(name=pagename).count() > 0:
next_url = request.route_url('edit_page', pagename=pagename)
return HTTPFound(location=next_url)
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(name=pagename, data=body)
Expand Down
8 changes: 7 additions & 1 deletion docs/tutorials/wiki2/src/authorization/tutorial/routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from pyramid.httpexceptions import HTTPNotFound
from pyramid.httpexceptions import (
HTTPNotFound,
HTTPFound,
)
from pyramid.security import (
Allow,
Everyone,
Expand All @@ -19,6 +22,9 @@ def includeme(config):

def new_page_factory(request):
pagename = request.matchdict['pagename']
if request.dbsession.query(Page).filter_by(name=pagename).count() > 0:
next_url = request.route_url('edit_page', pagename=pagename)
raise HTTPFound(location=next_url)
return NewPage(pagename)

class NewPage(object):
Expand Down
8 changes: 7 additions & 1 deletion docs/tutorials/wiki2/src/tests/tutorial/routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from pyramid.httpexceptions import HTTPNotFound
from pyramid.httpexceptions import (
HTTPNotFound,
HTTPFound,
)
from pyramid.security import (
Allow,
Everyone,
Expand All @@ -19,6 +22,9 @@ def includeme(config):

def new_page_factory(request):
pagename = request.matchdict['pagename']
if request.dbsession.query(Page).filter_by(name=pagename).count() > 0:
next_url = request.route_url('edit_page', pagename=pagename)
raise HTTPFound(location=next_url)
return NewPage(pagename)

class NewPage(object):
Expand Down
12 changes: 12 additions & 0 deletions docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,18 @@ def _callFUT(self, request):
from tutorial.views.default import add_page
return add_page(request)

def test_it_pageexists(self):
from ..models import Page
from ..routes import NewPage
request = testing.DummyRequest({'form.submitted': True,
'body': 'Hello yo!'},
dbsession=self.session)
request.user = self.makeUser('foo', 'editor')
request.context = NewPage('AnotherPage')
self._callFUT(request)
pagecount = self.session.query(Page).filter_by(name='AnotherPage').count()
self.assertGreater(pagecount, 0)

def test_it_notsubmitted(self):
from ..routes import NewPage
request = dummy_request(self.session)
Expand Down
3 changes: 3 additions & 0 deletions docs/tutorials/wiki2/src/views/tutorial/views/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ def edit_page(request):
@view_config(route_name='add_page', renderer='../templates/edit.jinja2')
def add_page(request):
pagename = request.matchdict['pagename']
if request.dbsession.query(Page).filter_by(name=pagename).count() > 0:
next_url = request.route_url('edit_page', pagename=pagename)
return HTTPFound(location=next_url)
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(name=pagename, data=body)
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/wiki2/tests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ The expected result should look like the following:
.....................
----------------------------------------------------------------------
Ran 21 tests in 5.117s
Ran 22 tests in 5.320s
OK
Expand Down

0 comments on commit 0c185a3

Please sign in to comment.