diff --git a/docs/tutorials/wiki2/authentication.rst b/docs/tutorials/wiki2/authentication.rst index 72c11f311f..5447db8617 100644 --- a/docs/tutorials/wiki2/authentication.rst +++ b/docs/tutorials/wiki2/authentication.rst @@ -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. @@ -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. diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst index 1be961f61b..962e2859cd 100644 --- a/docs/tutorials/wiki2/authorization.rst +++ b/docs/tutorials/wiki2/authorization.rst @@ -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. @@ -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 @@ -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. diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst index e48980dc83..b0cbe7dc47 100644 --- a/docs/tutorials/wiki2/definingviews.rst +++ b/docs/tutorials/wiki2/definingviews.rst @@ -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. @@ -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 @@ -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 @@ -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 diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py b/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py index ffe967f6e8..1b071434cf 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py @@ -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) diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/routes.py b/docs/tutorials/wiki2/src/authorization/tutorial/routes.py index c7c3a21206..f0a8b7f963 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/routes.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/routes.py @@ -1,4 +1,7 @@ -from pyramid.httpexceptions import HTTPNotFound +from pyramid.httpexceptions import ( + HTTPNotFound, + HTTPFound, +) from pyramid.security import ( Allow, Everyone, @@ -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): diff --git a/docs/tutorials/wiki2/src/tests/tutorial/routes.py b/docs/tutorials/wiki2/src/tests/tutorial/routes.py index c7c3a21206..f0a8b7f963 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/routes.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/routes.py @@ -1,4 +1,7 @@ -from pyramid.httpexceptions import HTTPNotFound +from pyramid.httpexceptions import ( + HTTPNotFound, + HTTPFound, +) from pyramid.security import ( Allow, Everyone, @@ -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): diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py index 5253183dff..2c945ab337 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_views.py @@ -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) diff --git a/docs/tutorials/wiki2/src/views/tutorial/views/default.py b/docs/tutorials/wiki2/src/views/tutorial/views/default.py index c1d402f6a4..bb6300b75f 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/views/default.py +++ b/docs/tutorials/wiki2/src/views/tutorial/views/default.py @@ -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) diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst index dabb73956f..54aea28c69 100644 --- a/docs/tutorials/wiki2/tests.rst +++ b/docs/tutorials/wiki2/tests.rst @@ -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