Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move security control panel to z3c.form. #216

Closed
tisto opened this issue Jun 20, 2014 · 19 comments
Closed

Move security control panel to z3c.form. #216

tisto opened this issue Jun 20, 2014 · 19 comments

Comments

@tisto
Copy link
Sponsor Member

tisto commented Jun 20, 2014

This has been already done in the z3c.form branch of plone.app.contenttypes:

https://github.com/plone/plone.app.controlpanel/blob/plip10359-z3cform/plone/app/controlpanel/browser/security.py

@davisagli davisagli mentioned this issue Jun 20, 2014
90 tasks
@jcerjak jcerjak self-assigned this Jul 30, 2014
jcerjak added a commit to jcerjak/Products.CMFPlone that referenced this issue Aug 21, 2014
Also replaced portal_properties lookups with plone.app.registry
lookups and added a robot test.
jcerjak added a commit to jcerjak/plone.app.controlpanel that referenced this issue Aug 25, 2014
@jcerjak
Copy link
Member

jcerjak commented Dec 12, 2014

I did some additional work on this, but it's not ready to merge yet. I'll try to find some time to work on it before NYE.

@tisto
Copy link
Sponsor Member Author

tisto commented Dec 13, 2014

What exactly is missing? Could you maybe create a todo list? I'd like to help if possible.

@tisto
Copy link
Sponsor Member Author

tisto commented Dec 14, 2014

@jcerjak I took your pull requests, fixed all failing tests and created new pull requests:

#329
plone/plone.app.users#28
plone/plone.app.controlpanel#36

@tisto
Copy link
Sponsor Member Author

tisto commented Dec 14, 2014

FYI: I added a question regarding the (last) failing csrf protection test: https://github.com/plone/Products.CMFPlone/pull/329/files#diff-d1fcf3ddc12f39ad335b7ddf19472bbfR182

@jcerjak
Copy link
Member

jcerjak commented Dec 14, 2014

@tisto , thanks! Here is my to-do list from some time ago, not sure if everything is still relevant:

@tisto
Copy link
Sponsor Member Author

tisto commented Dec 15, 2014

@jcerjak I merged the pull requests yesterday. We can now work on the master branches. Would you mind going through your todo list and check if all those issues have been taken care of? I'd like to focus on the two last remaining control panels.

@jcerjak
Copy link
Member

jcerjak commented Dec 15, 2014

@tisto, thanks, I'll work on it this week.

@tisto
Copy link
Sponsor Member Author

tisto commented Jan 23, 2015

@jcerjak Any updates? We would like to close this issue if possible. If there is still work to do maybe you can give us an heads up so people at the sprint can work on that.

@jcerjak
Copy link
Member

jcerjak commented Jan 23, 2015

I've updated the list of things to fix, see: #216 (comment)

I'll start with the last two items on that list, I'd appreciate feedback on things that block other items.

@jcerjak
Copy link
Member

jcerjak commented Jan 26, 2015

I did some progress on this on the Alpine City Sprint, I hope to wrap it up today/tomorrow.

@jcerjak
Copy link
Member

jcerjak commented Jan 27, 2015

Pull request opened: #362

datakurre added a commit to plone/buildout.coredev that referenced this issue Feb 4, 2015
Branch: refs/heads/master
Date: 2015-01-25T12:29:31+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.robotframework@44dee80

Read "use_email_as_login" from registry instead of portal properties

Files changed:
M CHANGES.txt
M src/plone/app/robotframework/users.py

diff --git a/CHANGES.txt b/CHANGES.txt
index 373e43d..8de3ba7 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,7 +4,9 @@ Changelog
 0.9.9 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Read ``use_email_as_login`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
 
 
 0.9.8 (2014-11-11)
diff --git a/src/plone/app/robotframework/users.py b/src/plone/app/robotframework/users.py
index 22daf44..2603ea5 100644
--- a/src/plone/app/robotframework/users.py
+++ b/src/plone/app/robotframework/users.py
@@ -1,7 +1,10 @@
 # -*- coding: utf-8 -*-
 from Products.CMFCore.utils import getToolByName
-from zope.component.hooks import getSite
+from Products.CMFPlone.interfaces import ISecuritySchema
 from plone.app.robotframework.remote import RemoteLibrary
+from plone.registry.interfaces import IRegistry
+from zope.component import getUtility
+from zope.component.hooks import getSite
 
 
 class Users(RemoteLibrary):
@@ -26,10 +29,13 @@ def create_user(self, *args, **kwargs):
 
         portal = getSite()
         registration = getToolByName(portal, 'portal_registration')
-        portal_properties = getToolByName(portal, 'portal_properties')
 
-        use_email_as_username =\
-            portal_properties.site_properties.use_email_as_login
+        registry = getUtility(IRegistry)
+        settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
+        use_email_as_username = settings.use_email_as_login
 
         user_id = use_email_as_username and properties['email'] or username
         password = properties.pop('password', username)


Repository: plone.app.robotframework
Branch: refs/heads/master
Date: 2015-02-01T15:49:46+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.robotframework@a565754

restore Plone 4 compatibility

Files changed:
M src/plone/app/robotframework/users.py

diff --git a/src/plone/app/robotframework/users.py b/src/plone/app/robotframework/users.py
index 2603ea5..c92f296 100644
--- a/src/plone/app/robotframework/users.py
+++ b/src/plone/app/robotframework/users.py
@@ -1,11 +1,16 @@
 # -*- coding: utf-8 -*-
 from Products.CMFCore.utils import getToolByName
-from Products.CMFPlone.interfaces import ISecuritySchema
 from plone.app.robotframework.remote import RemoteLibrary
 from plone.registry.interfaces import IRegistry
 from zope.component import getUtility
 from zope.component.hooks import getSite
 
+HAS_SECURITY_SETTINGS = True
+try:
+    from Products.CMFPlone.interfaces import ISecuritySchema
+except ImportError:
+    HAS_SECURITY_SETTINGS = False
+
 
 class Users(RemoteLibrary):
 
@@ -30,12 +35,17 @@ def create_user(self, *args, **kwargs):
         portal = getSite()
         registration = getToolByName(portal, 'portal_registration')
 
-        registry = getUtility(IRegistry)
-        settings = registry.forInterface(
-            ISecuritySchema,
-            prefix='plone',
-        )
-        use_email_as_username = settings.use_email_as_login
+        if HAS_SECURITY_SETTINGS:  # Plone 5
+            registry = getUtility(IRegistry)
+            settings = registry.forInterface(
+                ISecuritySchema,
+                prefix='plone',
+            )
+            use_email_as_username = settings.use_email_as_login
+        else:  # Plone < 5
+            portal_properties = getToolByName(portal, 'portal_properties')
+            use_email_as_username = \
+                portal_properties.site_properties.use_email_as_login
 
         user_id = use_email_as_username and properties['email'] or username
         password = properties.pop('password', username)


Repository: plone.app.robotframework
Branch: refs/heads/master
Date: 2015-02-04T22:27:46+02:00
Author: Asko Soukka (datakurre) <asko.soukka@iki.fi>
Commit: plone/plone.app.robotframework@c5e344a

Merge pull request #35 from plone/plip10359-security-controlpanel

Plip 10359 - Security Control Panel migration

Files changed:
M CHANGES.txt
M src/plone/app/robotframework/users.py

diff --git a/CHANGES.txt b/CHANGES.txt
index 373e43d..8de3ba7 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,7 +4,9 @@ Changelog
 0.9.9 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Read ``use_email_as_login`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
 
 
 0.9.8 (2014-11-11)
diff --git a/src/plone/app/robotframework/users.py b/src/plone/app/robotframework/users.py
index 22daf44..c92f296 100644
--- a/src/plone/app/robotframework/users.py
+++ b/src/plone/app/robotframework/users.py
@@ -1,7 +1,15 @@
 # -*- coding: utf-8 -*-
 from Products.CMFCore.utils import getToolByName
-from zope.component.hooks import getSite
 from plone.app.robotframework.remote import RemoteLibrary
+from plone.registry.interfaces import IRegistry
+from zope.component import getUtility
+from zope.component.hooks import getSite
+
+HAS_SECURITY_SETTINGS = True
+try:
+    from Products.CMFPlone.interfaces import ISecuritySchema
+except ImportError:
+    HAS_SECURITY_SETTINGS = False
 
 
 class Users(RemoteLibrary):
@@ -26,10 +34,18 @@ def create_user(self, *args, **kwargs):
 
         portal = getSite()
         registration = getToolByName(portal, 'portal_registration')
-        portal_properties = getToolByName(portal, 'portal_properties')
 
-        use_email_as_username =\
-            portal_properties.site_properties.use_email_as_login
+        if HAS_SECURITY_SETTINGS:  # Plone 5
+            registry = getUtility(IRegistry)
+            settings = registry.forInterface(
+                ISecuritySchema,
+                prefix='plone',
+            )
+            use_email_as_username = settings.use_email_as_login
+        else:  # Plone < 5
+            portal_properties = getToolByName(portal, 'portal_properties')
+            use_email_as_username = \
+                portal_properties.site_properties.use_email_as_login
 
         user_id = use_email_as_username and properties['email'] or username
         password = properties.pop('password', username)
davisagli added a commit to plone/buildout.coredev that referenced this issue Feb 16, 2015
Branch: refs/heads/master
Date: 2015-02-15T17:31:58-08:00
Author: David Glick (davisagli) <david@glicksoftware.com>
Commit: plone/plone.app.robotframework@1b809c7

find mockup-based modals too

Files changed:
M CHANGES.txt
M src/plone/app/robotframework/keywords.robot

diff --git a/CHANGES.txt b/CHANGES.txt
index 8de3ba7..6cc6e84 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,10 @@ Changelog
 0.9.9 (unreleased)
 ------------------
 
+- Also detect mockup-based modals in the "Click Overlay Link" and
+  "Click Overlay Button" keywords.
+  [davisagli]
+
 - Read ``use_email_as_login`` setting from the registry instead of portal
   properties (see plone/Products.CMFPlone#216).
   [jcerjak]
diff --git a/src/plone/app/robotframework/keywords.robot b/src/plone/app/robotframework/keywords.robot
index 4e83420..efbd616 100644
--- a/src/plone/app/robotframework/keywords.robot
+++ b/src/plone/app/robotframework/keywords.robot
@@ -103,15 +103,15 @@ Log out
 Click Overlay Link
     [Arguments]  ${element}
     Click Link  ${element}
-    Wait until keyword succeeds  10  1  Page Should Contain Element  css=.pb-ajax > div
-    Element Should Be Visible  css=.pb-ajax > div
+    Wait until keyword succeeds  10  1  Page Should Contain Element  css=.pb-ajax > div,.plone-modal
+    Element Should Be Visible  css=.pb-ajax > div,.plone-modal
 
 Click Overlay Button
     [Arguments]  ${element}
     Click Button  ${element}
-    Wait until page contains element  css=.pb-ajax > div
-    Page Should Contain Element  css=.pb-ajax > div
-    Element Should Be Visible  css=.pb-ajax > div
+    Wait until page contains element  css=.pb-ajax > div,.plone-modal
+    Page Should Contain Element  css=.pb-ajax > div,.plone-modal
+    Element Should Be Visible  css=.pb-ajax > div,.plone-modal
 
 Should be above
     [Arguments]  ${locator1}  ${locator2}
@tisto
Copy link
Sponsor Member Author

tisto commented Feb 27, 2015

Hey @jcerjak, I plan to work on this today. I just merged master into all repos. Though, I see quite a few test failures in CMFPlone now. Do you have time for a quick chat on IRC?

tisto added a commit to plone/buildout.coredev that referenced this issue Feb 27, 2015
Branch: refs/heads/master
Date: 2015-01-25T20:15:31+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.search@15427c4

read "allow_anon_views_about" from registry instead of properties

Files changed:
M CHANGES.rst
M plone/app/search/search.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 8a05d5c..a1ea647 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,9 @@ Changelog
 1.2.3 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Read ``allow_anon_views_about`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
 
 
 1.2.2 (2014-10-23)
diff --git a/plone/app/search/search.pt b/plone/app/search/search.pt
index 2549364..9ae4233 100644
--- a/plone/app/search/search.pt
+++ b/plone/app/search/search.pt
@@ -147,7 +147,7 @@
                                       <div class="search-type-options">
                                         <tal:div
                                            tal:define="typeLists python:context.createMultiColumnList(types_list, numCols=2, sort_on='self');"
-                                           
+
                                            tal:repeat="sublist typeLists">
                                           <tal:items repeat="type sublist">
                                             <div>
@@ -240,7 +240,7 @@
 
                     </dl>
 
-                    
+
                 </div>
 
 
@@ -275,8 +275,8 @@
                                                    toLocalizedTime nocall: context/@@plone/toLocalizedTime;
                                                    site_properties context/portal_properties/site_properties;
                                                    use_view_action site_properties/typesUseViewActionInListings|python:();
-                                                   allowAnonymousViewAbout site_properties/allowAnonymousViewAbout;
-                                                   show_about python:not isAnon or allowAnonymousViewAbout;">
+                                                   allow_anon_views_about python:context.portal_registry['plone.allow_anon_views_about'];
+                                                   show_about python:not isAnon or allow_anon_views_about;">
                           <ol class="searchResults">
                               <tal:results repeat="item batch">
                                     <li>


Repository: plone.app.search
Branch: refs/heads/master
Date: 2015-02-27T07:47:52+01:00
Author: Timo Stollenwerk () <contact@timostollenwerk.net>
Commit: plone/plone.app.search@c233aec

Merge branch 'master' into plip10359-security-controlpanel

Files changed:
M README.rst

diff --git a/README.rst b/README.rst
index 6868b6f..a42c0fb 100644
--- a/README.rst
+++ b/README.rst
@@ -8,4 +8,6 @@ plone.app.search also updates main search field (usually located at the top righ
 plone.app.search has the aim to give intuitively clear and understandable interface for searching in Plone. But there might be some new things that are not so obvious. Let's see how the search results works now.
 
 Notes
-=====
\ No newline at end of file
+=====
+
+This package is merged into Products.CMFPlone in Plone 5.


Repository: plone.app.search
Branch: refs/heads/master
Date: 2015-02-27T08:35:10+01:00
Author: Timo Stollenwerk (tisto) <tisto@plone.org>
Commit: plone/plone.app.search@9c7459b

Merge pull request #14 from plone/plip10359-security-controlpanel

Plip 10359 - Security Control Panel migration

Files changed:
M CHANGES.rst
M plone/app/search/search.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 8a05d5c..a1ea647 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,9 @@ Changelog
 1.2.3 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Read ``allow_anon_views_about`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
 
 
 1.2.2 (2014-10-23)
diff --git a/plone/app/search/search.pt b/plone/app/search/search.pt
index 2549364..9ae4233 100644
--- a/plone/app/search/search.pt
+++ b/plone/app/search/search.pt
@@ -147,7 +147,7 @@
                                       <div class="search-type-options">
                                         <tal:div
                                            tal:define="typeLists python:context.createMultiColumnList(types_list, numCols=2, sort_on='self');"
-                                           
+
                                            tal:repeat="sublist typeLists">
                                           <tal:items repeat="type sublist">
                                             <div>
@@ -240,7 +240,7 @@
 
                     </dl>
 
-                    
+
                 </div>
 
 
@@ -275,8 +275,8 @@
                                                    toLocalizedTime nocall: context/@@plone/toLocalizedTime;
                                                    site_properties context/portal_properties/site_properties;
                                                    use_view_action site_properties/typesUseViewActionInListings|python:();
-                                                   allowAnonymousViewAbout site_properties/allowAnonymousViewAbout;
-                                                   show_about python:not isAnon or allowAnonymousViewAbout;">
+                                                   allow_anon_views_about python:context.portal_registry['plone.allow_anon_views_about'];
+                                                   show_about python:not isAnon or allow_anon_views_about;">
                           <ol class="searchResults">
                               <tal:results repeat="item batch">
                                     <li>
@tisto
Copy link
Sponsor Member Author

tisto commented Feb 27, 2015

I created a Jenkins job, see console output for test failures: http://jenkins.plone.org/job/PLIP-10359/3/console

tisto added a commit to plone/buildout.coredev that referenced this issue Feb 27, 2015
Branch: refs/heads/master
Date: 2015-01-25T20:33:16+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.portlets@3a154ee

Read "use_email_as_login" from registry instead of properties

Files changed:
M CHANGES.rst
M plone/app/portlets/portlets/login.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 3a4ad10..93bcdd1 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,10 @@ Changelog
 3.0.3 (unreleased)
 ------------------
 
+- Read ``use_email_as_login`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
+
 - Use plone_layout for getIcon.
   [pbauer]
 
diff --git a/plone/app/portlets/portlets/login.pt b/plone/app/portlets/portlets/login.pt
index d210276..606737f 100644
--- a/plone/app/portlets/portlets/login.pt
+++ b/plone/app/portlets/portlets/login.pt
@@ -30,7 +30,7 @@
             </div>
 
             <div class="field"
-                 tal:define="use_email_as_login context/portal_properties/site_properties/use_email_as_login|nothing;">
+                 tal:define="use_email_as_login python:context.portal_registry['plone.use_email_as_login'];">
 
               <tal:loginname condition="not:use_email_as_login">
                 <label for=""


Repository: plone.app.portlets
Branch: refs/heads/master
Date: 2015-02-27T07:48:27+01:00
Author: Timo Stollenwerk () <contact@timostollenwerk.net>
Commit: plone/plone.app.portlets@ac46445

Merge branch 'master' into plip10359-security-controlpanel

Conflicts:
	CHANGES.rst

Files changed:
M CHANGES.rst
M plone/app/portlets/browser/templates/manage-contextual.pt
M plone/app/portlets/browser/templates/topbar-manage-portlets.pt
M plone/app/portlets/portlets/recent.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 93bcdd1..f206468 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,6 +8,9 @@ Changelog
   properties (see plone/Products.CMFPlone#216).
   [jcerjak]
 
+- Fix missing definitions of ``plone_view``. Fixes the recent portlet.
+  [thet]
+
 - Use plone_layout for getIcon.
   [pbauer]
 
diff --git a/plone/app/portlets/browser/templates/manage-contextual.pt b/plone/app/portlets/browser/templates/manage-contextual.pt
index 1db5528..d01927c 100644
--- a/plone/app/portlets/browser/templates/manage-contextual.pt
+++ b/plone/app/portlets/browser/templates/manage-contextual.pt
@@ -13,7 +13,7 @@
 </head>
 
 <body>
-<metal:main fill-slot="main" tal:define="ploneview context/@@plone">
+<metal:main fill-slot="main" tal:define="plone_view context/@@plone">
 
   <h1 class="documentFirstHeading"
       i18n:translate="title_manage_contextual_portlets">
@@ -40,7 +40,7 @@
     </tal:block>
 
       <div class="portalMessage info"
-          tal:condition="ploneview/isDefaultPageInFolder|nothing">
+          tal:condition="plone_view/isDefaultPageInFolder|nothing">
         <strong i18n:translate="">
             Info
         </strong>
diff --git a/plone/app/portlets/browser/templates/topbar-manage-portlets.pt b/plone/app/portlets/browser/templates/topbar-manage-portlets.pt
index f501d48..f8199e4 100644
--- a/plone/app/portlets/browser/templates/topbar-manage-portlets.pt
+++ b/plone/app/portlets/browser/templates/topbar-manage-portlets.pt
@@ -6,9 +6,9 @@
       i18n:domain="plone">
 <body>
 
-  <div metal:fill-slot="main">
+  <div metal:fill-slot="main" tal:define="plone_view context/@@plone">
     <div class="portalMessage info"
-        tal:condition="ploneview/isDefaultPageInFolder|nothing">
+        tal:condition="plone_view/isDefaultPageInFolder|nothing">
       <strong>
           Info
       </strong>
diff --git a/plone/app/portlets/portlets/recent.pt b/plone/app/portlets/portlets/recent.pt
index f5c0a26..a5ab758 100644
--- a/plone/app/portlets/portlets/recent.pt
+++ b/plone/app/portlets/portlets/recent.pt
@@ -15,6 +15,7 @@
         tal:condition="view/recent_items">
       <ul>
         <tal:items tal:define="plone_layout context/@@plone_layout;
+                           plone_view context/@@plone;
                            getIcon nocall:plone_layout/getIcon;
                            normalizeString nocall:plone_view/normalizeString;
                            toLocalizedTime nocall:plone_view/toLocalizedTime;"


Repository: plone.app.portlets
Branch: refs/heads/master
Date: 2015-02-27T09:05:39+01:00
Author: Timo Stollenwerk (tisto) <tisto@plone.org>
Commit: plone/plone.app.portlets@0842bd5

Merge pull request #46 from plone/plip10359-security-controlpanel

Plip 10359 - Security Control Panel migration

Files changed:
M CHANGES.rst
M plone/app/portlets/portlets/login.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 186b99b..f206468 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,10 @@ Changelog
 3.0.3 (unreleased)
 ------------------
 
+- Read ``use_email_as_login`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
+
 - Fix missing definitions of ``plone_view``. Fixes the recent portlet.
   [thet]
 
diff --git a/plone/app/portlets/portlets/login.pt b/plone/app/portlets/portlets/login.pt
index d210276..606737f 100644
--- a/plone/app/portlets/portlets/login.pt
+++ b/plone/app/portlets/portlets/login.pt
@@ -30,7 +30,7 @@
             </div>
 
             <div class="field"
-                 tal:define="use_email_as_login context/portal_properties/site_properties/use_email_as_login|nothing;">
+                 tal:define="use_email_as_login python:context.portal_registry['plone.use_email_as_login'];">
 
               <tal:loginname condition="not:use_email_as_login">
                 <label for=""
tisto added a commit to plone/buildout.coredev that referenced this issue Feb 27, 2015
Branch: refs/heads/master
Date: 2015-01-24T16:02:38+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/Products.PasswordResetTool@3b81f12

update browser.txt to reflect changes in CMFPlone

validate_email was replaced by enable_user_pwd_choice

Files changed:
M Products/PasswordResetTool/tests/browser.txt

diff --git a/Products/PasswordResetTool/tests/browser.txt b/Products/PasswordResetTool/tests/browser.txt
index b9a573e..5876c79 100644
--- a/Products/PasswordResetTool/tests/browser.txt
+++ b/Products/PasswordResetTool/tests/browser.txt
@@ -25,9 +25,9 @@ distinct password policies regarding member registration.
   B. A password is generated for the users (and an e-mail with login
      credentials is sent automatically).
 
-This policy can enabled or disabled in the ``validate_email`` property
-on the Plone Site object.  By default ``validate_email`` is enabled
-and the second policy applies.
+This policy can be enabled or disabled with the ``enable_user_pwd_choice``
+setting in the security control panel.  By default ``enable_user_pwd_choice`` is
+disabled and the second policy applies.
 
 Another aspect we have to take into account is the fact that Plone by
 default only allows Administrators to register (other) members, but allowing


Repository: Products.PasswordResetTool
Branch: refs/heads/master
Date: 2015-01-25T17:09:01+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/Products.PasswordResetTool@5a9bacc

Read use_email_as_login from registry instead of portal properties

Files changed:
M CHANGES.txt
M Products/PasswordResetTool/PasswordResetTool.py
M Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt

diff --git a/CHANGES.txt b/CHANGES.txt
index 4a3883f..3a66e3f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,10 @@ Changelog
 2.1.2 (unreleased)
 ------------------
 
+- Read ``use_email_as_login`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
+
 - Amend browser.txt test to the new p.a.registry-based control panels
   (Plone 5 only).
   [timo]
diff --git a/Products/PasswordResetTool/PasswordResetTool.py b/Products/PasswordResetTool/PasswordResetTool.py
index dd03c3e..20d95aa 100644
--- a/Products/PasswordResetTool/PasswordResetTool.py
+++ b/Products/PasswordResetTool/PasswordResetTool.py
@@ -19,7 +19,9 @@
 from App.special_dtml import DTMLFile
 from AccessControl import ClassSecurityInfo
 from AccessControl import ModuleSecurityInfo
+from plone.registry.interfaces import IRegistry
 from Products.CMFCore.permissions import ManagePortal
+from Products.CMFPlone.interfaces import ISecuritySchema
 try:
     from Products.CMFPlone.RegistrationTool import get_member_by_login_name
 except ImportError:
@@ -33,6 +35,7 @@
 import time
 import socket
 from DateTime import DateTime
+from zope.component import getUtility
 from zope.interface import implements
 
 module_security = ModuleSecurityInfo('Products.PasswordResetTool.PasswordResetTool')
@@ -346,8 +349,10 @@ def expirationDate(self):
     def getValidUser(self, userid):
         """Returns the member with 'userid' if available and None otherwise."""
         if get_member_by_login_name:
-            props = getToolByName(self, 'portal_properties').site_properties
-            if props.getProperty('use_email_as_login', False):
+            registry = getUtility(IRegistry)
+            settings = registry.forInterface(ISecuritySchema, prefix='plone')
+
+            if settings.use_email_as_login:
                 return get_member_by_login_name(
                     self, userid, raise_exceptions=False)
         membertool = getToolByName(self, 'portal_membership')
diff --git a/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt b/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
index 53d325a..53be415 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
+++ b/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
@@ -32,7 +32,7 @@
                     <div class="field"
                          tal:define="error errors/userid | nothing;
                                      site_properties context/portal_properties/site_properties;
-                                     use_email_as_login site_properties/use_email_as_login|nothing;"
+                                     use_email_as_login python:context.portal_registry['plone.use_email_as_login'];"
                          tal:attributes="class python:test(error, 'field error', 'field')"
                          tal:condition="here/portal_password_reset/checkUser | nothing">
 


Repository: Products.PasswordResetTool
Branch: refs/heads/master
Date: 2015-01-25T20:39:07+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/Products.PasswordResetTool@d1b381b

fix "use_email_as_login" in other templates as well

Files changed:
M Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
M Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt

diff --git a/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt b/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
index 03daaad..d23c1f1 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
+++ b/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
@@ -14,7 +14,7 @@
 
 <metal:main fill-slot="main"
      tal:define="global props context/@@plone_tools/properties;
-                 use_email_as_login props/site_properties/use_email_as_login|nothing;">
+                 use_email_as_login python:context.portal_registry['plone.use_email_as_login'];">
 
     <h1 class="documentFirstHeading"
         i18n:translate="heading_lost_password">Lost Password</h1>
diff --git a/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt b/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
index 755ed7e..417cf2f 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
+++ b/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
@@ -6,7 +6,7 @@
 
 <metal:main fill-slot="main"
      tal:define="site_properties context/portal_properties/site_properties;
-                 use_email_as_login site_properties/use_email_as_login|nothing;">
+                 use_email_as_login python:context.portal_registry['plone.use_email_as_login'];">
 
     <h1 class="documentFirstHeading" i18n:translate="heading_pwreset_invalid">Error setting password</h1>
 


Repository: Products.PasswordResetTool
Branch: refs/heads/master
Date: 2015-02-27T07:50:34+01:00
Author: Timo Stollenwerk () <contact@timostollenwerk.net>
Commit: plone/Products.PasswordResetTool@a529ec2

Merge branch 'master' into plip10359-security-controlpanel

Files changed:
M CHANGES.txt
M Products/PasswordResetTool/skins/PasswordReset/mail_password_template.pt
M Products/PasswordResetTool/tests/browser.txt

diff --git a/CHANGES.txt b/CHANGES.txt
index 3a66e3f..95ac758 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -11,6 +11,8 @@ Changelog
 - Amend browser.txt test to the new p.a.registry-based control panels
   (Plone 5 only).
   [timo]
+- Added userid information in reset mail (useful when the administrator resets a user password)
+  [sgeulette]
 
 
 2.1.1 (2014-10-22)
diff --git a/Products/PasswordResetTool/skins/PasswordReset/mail_password_template.pt b/Products/PasswordResetTool/skins/PasswordReset/mail_password_template.pt
index 792967e..d5a57a1 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/mail_password_template.pt
+++ b/Products/PasswordResetTool/skins/PasswordReset/mail_password_template.pt
@@ -3,6 +3,7 @@
                   member python:options['member'];
                   portal_state context/@@plone_portal_state;
                   view context/@@passwordreset_view;
+                  isAnon context/@@plone_portal_state/anonymous;
                   reset python:options['reset']"
 >From: <span tal:replace="structure view/encoded_mail_sender" />
 To: <span tal:replace="python:member.getProperty('email')" />
@@ -10,6 +11,15 @@ Subject: <span tal:replace="view/mail_password_subject" />
 Precedence: bulk
 
 <div i18n:domain="passwordresettool"
+     i18n:translate="mailtemplate_reset_information"
+     tal:omit-tag=""
+     tal:condition="not:isAnon">
+The site administrator asks you to reset your password for '<span i18n:name="userid"
+          tal:omit-tag=""
+          tal:content="member/id" />' userid. Your old password doesn't work anymore.
+</div>
+
+<div i18n:domain="passwordresettool"
      i18n:translate="mailtemplate_text_linkreset"
      tal:omit-tag=""
      tal:define="fullname python: test(member.fullname,
@@ -32,7 +42,8 @@ The following link will take you to a page where you can reset your password for
 
 <div i18n:domain="passwordresettool"
      i18n:translate="mailtemplate_tracking_information"
-     tal:omit-tag="">
+     tal:omit-tag=""
+     tal:condition="isAnon">
 If you didn't expect to receive this email, please ignore it. Your password has not been changed.
 Request made from IP address <span tal:define="host request/HTTP_X_FORWARDED_FOR|request/REMOTE_ADDR"
           tal:content="host"
diff --git a/Products/PasswordResetTool/tests/browser.txt b/Products/PasswordResetTool/tests/browser.txt
index 5876c79..bc44317 100644
--- a/Products/PasswordResetTool/tests/browser.txt
+++ b/Products/PasswordResetTool/tests/browser.txt
@@ -72,6 +72,7 @@ What we do here:
   - Log in
   - Log out again
   - Forget our password (this is where PasswordResetTool comes in)
+  - Check if this is a soft reset (old password already works until changed)
   - Read the e-mail that contains the URL we visit to reset our password
   - Reset our password
   - Log in with our new password
@@ -154,6 +155,24 @@ password`` in the login form:
   >>> form.getControl(name='userid').value = 'jsmith'
   >>> form.submit()
 
+We check if the old password always works.
+
+  >>> browser.open('http://nohost/plone/login')
+  >>> browser.getControl(name='__ac_name').value = 'jsmith'
+  >>> browser.getControl(name='__ac_password').value = 'secret'
+  >>> browser.getControl(name='submit').click()
+
+We should be logged in now:
+
+  >>> "You are now logged in" in browser.contents
+  True
+
+Log out again:
+
+  >>> browser.getLink('Log out').click()
+  >>> "You are now logged out" in browser.contents
+  True
+
 As part of our test setup, we replaced the original MailHost with our
 own version.  Our version doesn't mail messages, it just collects them
 in a list called ``messages``:
@@ -170,13 +189,17 @@ then we extract the address that lets us reset our password:
   >>> msg = quopri.decodestring(msg)
   >>> "To: jsmith@example.com" in msg
   True
+  >>> "The site administrator asks you to reset your password for 'jsmith' userid" in msg
+  False
   >>> please_visit_text = "The following link will take you to a page where you can reset your password for Plone site site:"
   >>> please_visit_text in msg
   True
   >>> url_index = msg.index(please_visit_text) + len(please_visit_text)
   >>> address = msg[url_index:].strip().split()[0]
- >>> address # doctest: +ELLIPSIS
+  >>> address # doctest: +ELLIPSIS
   'http://nohost/plone/passwordreset/...'
+  >>> "If you didn't expect to receive this email" in msg
+  True
 
 Now that we have the address, we will reset our password:
 
@@ -221,6 +244,9 @@ Log out again:
   - Register a member (with send email checked???)
   - Log out
   - Log in as the new member
+  - A manager resets a user password
+  - Check if this is a hard reset (old password is changed)
+  - Check the received mail
 
 First, we want to login as the portal owner:
 
@@ -261,6 +287,56 @@ We want to logout and login as the new member:
 
   >>> browser.getLink('Log out').click()
 
+Again, we want to login as the portal owner:
+
+  >>> browser.open('http://nohost/plone/login')
+  >>> browser.getControl(name='__ac_name').value = SITE_OWNER_NAME
+  >>> browser.getControl(name='__ac_password').value = SITE_OWNER_PASSWORD
+  >>> browser.getControl(name='submit').click()
+  >>> "You are now logged in" in browser.contents
+  True
+
+We navigate to the Users Overview page and reset a password user:
+
+  >>> browser.getLink('Site Setup').click()
+  >>> browser.getLink('Users and Groups').click()
+  >>> resets = browser.getControl(name='users.resetpassword:records')
+  >>> reset = resets.getControl(value='wsmith')
+  >>> reset.selected = True  
+  >>> browser.getControl(name="form.button.Modify").click()
+  >>> "Changes applied." in browser.contents
+  True
+  >>> browser.getLink('Log out').click()
+  >>> "You are now logged out" in browser.contents
+  True
+
+We check if the old password is well changed.
+
+  >>> browser.open('http://nohost/plone/login')
+  >>> browser.getControl(name='__ac_name').value = 'wsmith'
+  >>> browser.getControl(name='__ac_password').value = 'supersecret'
+  >>> browser.getControl(name='submit').click()
+
+We should not be logged in:
+
+  >>> "Login failed" in browser.contents
+  True
+
+We should have received an e-mail at this point:
+
+  >>> mailhost = layer['portal'].MailHost
+  >>> len(mailhost.messages)
+  2
+  >>> import quopri
+  >>> msg = quopri.decodestring(str(mailhost.messages[-1]))
+  >>> "The site administrator asks you to reset your password for 'wsmith' userid" in msg
+  True
+  >>> please_visit_text = "The following link will take you to a page where you can reset your password for Plone site site:"
+  >>> please_visit_text in msg
+  True
+  >>> "If you didn't expect to receive this email" in msg
+  False
+
 
 1B. User joins with e-mail validation enabled and forgets password
 ------------------------------------------------------------------
@@ -311,7 +387,7 @@ We should have received an e-mail at this point:
 
   >>> mailhost = layer['portal'].MailHost
   >>> len(mailhost.messages)
-  2
+  3
   >>> msg = str(mailhost.messages[-1])
 
 Now that we have the message, we want to look at its contents, and
@@ -397,7 +473,7 @@ We should have received an e-mail at this point:
 
   >>> mailhost = layer['portal'].MailHost
   >>> len(mailhost.messages)
-  3
+  4
   >>> msg = str(mailhost.messages[-1])
 
 Now that we have the message, we want to look at its contents, and


Repository: Products.PasswordResetTool
Branch: refs/heads/master
Date: 2015-02-27T10:00:03+01:00
Author: Timo Stollenwerk (tisto) <tisto@plone.org>
Commit: plone/Products.PasswordResetTool@7019f76

Merge pull request #8 from plone/plip10359-security-controlpanel

Plip10359 security controlpanel

Files changed:
M CHANGES.txt
M Products/PasswordResetTool/PasswordResetTool.py
M Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
M Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
M Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
M Products/PasswordResetTool/tests/browser.txt

diff --git a/CHANGES.txt b/CHANGES.txt
index 4f951e3..95ac758 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,10 @@ Changelog
 2.1.2 (unreleased)
 ------------------
 
+- Read ``use_email_as_login`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
+
 - Amend browser.txt test to the new p.a.registry-based control panels
   (Plone 5 only).
   [timo]
diff --git a/Products/PasswordResetTool/PasswordResetTool.py b/Products/PasswordResetTool/PasswordResetTool.py
index dd03c3e..20d95aa 100644
--- a/Products/PasswordResetTool/PasswordResetTool.py
+++ b/Products/PasswordResetTool/PasswordResetTool.py
@@ -19,7 +19,9 @@
 from App.special_dtml import DTMLFile
 from AccessControl import ClassSecurityInfo
 from AccessControl import ModuleSecurityInfo
+from plone.registry.interfaces import IRegistry
 from Products.CMFCore.permissions import ManagePortal
+from Products.CMFPlone.interfaces import ISecuritySchema
 try:
     from Products.CMFPlone.RegistrationTool import get_member_by_login_name
 except ImportError:
@@ -33,6 +35,7 @@
 import time
 import socket
 from DateTime import DateTime
+from zope.component import getUtility
 from zope.interface import implements
 
 module_security = ModuleSecurityInfo('Products.PasswordResetTool.PasswordResetTool')
@@ -346,8 +349,10 @@ def expirationDate(self):
     def getValidUser(self, userid):
         """Returns the member with 'userid' if available and None otherwise."""
         if get_member_by_login_name:
-            props = getToolByName(self, 'portal_properties').site_properties
-            if props.getProperty('use_email_as_login', False):
+            registry = getUtility(IRegistry)
+            settings = registry.forInterface(ISecuritySchema, prefix='plone')
+
+            if settings.use_email_as_login:
                 return get_member_by_login_name(
                     self, userid, raise_exceptions=False)
         membertool = getToolByName(self, 'portal_membership')
diff --git a/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt b/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
index 03daaad..d23c1f1 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
+++ b/Products/PasswordResetTool/skins/PasswordReset/mail_password_form.pt
@@ -14,7 +14,7 @@
 
 <metal:main fill-slot="main"
      tal:define="global props context/@@plone_tools/properties;
-                 use_email_as_login props/site_properties/use_email_as_login|nothing;">
+                 use_email_as_login python:context.portal_registry['plone.use_email_as_login'];">
 
     <h1 class="documentFirstHeading"
         i18n:translate="heading_lost_password">Lost Password</h1>
diff --git a/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt b/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
index 53d325a..53be415 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
+++ b/Products/PasswordResetTool/skins/PasswordReset/pwreset_form.cpt
@@ -32,7 +32,7 @@
                     <div class="field"
                          tal:define="error errors/userid | nothing;
                                      site_properties context/portal_properties/site_properties;
-                                     use_email_as_login site_properties/use_email_as_login|nothing;"
+                                     use_email_as_login python:context.portal_registry['plone.use_email_as_login'];"
                          tal:attributes="class python:test(error, 'field error', 'field')"
                          tal:condition="here/portal_password_reset/checkUser | nothing">
 
diff --git a/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt b/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
index 755ed7e..417cf2f 100644
--- a/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
+++ b/Products/PasswordResetTool/skins/PasswordReset/pwreset_invalid.pt
@@ -6,7 +6,7 @@
 
 <metal:main fill-slot="main"
      tal:define="site_properties context/portal_properties/site_properties;
-                 use_email_as_login site_properties/use_email_as_login|nothing;">
+                 use_email_as_login python:context.portal_registry['plone.use_email_as_login'];">
 
     <h1 class="documentFirstHeading" i18n:translate="heading_pwreset_invalid">Error setting password</h1>
 
diff --git a/Products/PasswordResetTool/tests/browser.txt b/Products/PasswordResetTool/tests/browser.txt
index d4dc5b1..bc44317 100644
--- a/Products/PasswordResetTool/tests/browser.txt
+++ b/Products/PasswordResetTool/tests/browser.txt
@@ -25,9 +25,9 @@ distinct password policies regarding member registration.
   B. A password is generated for the users (and an e-mail with login
      credentials is sent automatically).
 
-This policy can enabled or disabled in the ``validate_email`` property
-on the Plone Site object.  By default ``validate_email`` is enabled
-and the second policy applies.
+This policy can be enabled or disabled with the ``enable_user_pwd_choice``
+setting in the security control panel.  By default ``enable_user_pwd_choice`` is
+disabled and the second policy applies.
 
 Another aspect we have to take into account is the fact that Plone by
 default only allows Administrators to register (other) members, but allowing
tisto added a commit to plone/buildout.coredev that referenced this issue Feb 27, 2015
Branch: refs/heads/master
Date: 2015-01-25T13:32:53+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.layout@ec8d8bb

Read "allow_anon_views_about" from registry instead of properties

Files changed:
M CHANGES.rst
M plone/app/layout/links/viewlets.py
M plone/app/layout/viewlets/content.py
M plone/app/layout/viewlets/tests/test_content.py

diff --git a/CHANGES.rst b/CHANGES.rst
index ee37d4c..2e0a425 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,10 @@ Changelog
 2.5.4 (unreleased)
 ------------------
 
+- Read ``allow_anon_views_about`` settings from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
+
 - Added support for site logos stored in the portal registry via the site
   control panel for the logo viewlet with a fallback to the ``OFS.Image``
   based ``logo.png`` file. Removed support of long-gone
diff --git a/plone/app/layout/links/viewlets.py b/plone/app/layout/links/viewlets.py
index 555616a..3ec1283 100644
--- a/plone/app/layout/links/viewlets.py
+++ b/plone/app/layout/links/viewlets.py
@@ -13,6 +13,7 @@
 from zope.schema.interfaces import IVocabularyFactory
 from zope.component import getUtility
 from plone.registry.interfaces import IRegistry
+from Products.CMFPlone.interfaces import ISecuritySchema
 from Products.CMFPlone.interfaces.syndication import IFeedSettings
 from Products.CMFPlone.interfaces.syndication import ISiteSyndicationSettings
 
@@ -62,12 +63,13 @@ def update(self):
                                      name='plone_tools')
 
     def show(self):
-        properties = self.tools.properties()
-        site_properties = getattr(properties, 'site_properties')
         anonymous = self.portal_state.anonymous()
-        allowAnonymousViewAbout = site_properties.getProperty(
-            'allowAnonymousViewAbout', True)
-        return not anonymous or allowAnonymousViewAbout
+        registry = getUtility(IRegistry)
+        settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
+        return not anonymous or settings.allow_anon_views_about
 
     def render(self):
         if self.show():
diff --git a/plone/app/layout/viewlets/content.py b/plone/app/layout/viewlets/content.py
index 15adcbd..7ac2abf 100644
--- a/plone/app/layout/viewlets/content.py
+++ b/plone/app/layout/viewlets/content.py
@@ -6,14 +6,17 @@
 from AccessControl import getSecurityManager
 from Acquisition import aq_inner
 from DateTime import DateTime
+from plone.registry.interfaces import IRegistry
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 from Products.CMFCore.utils import _checkPermission
 from Products.CMFCore.utils import getToolByName
 from Products.CMFCore.WorkflowCore import WorkflowException
 from Products.CMFEditions.Permissions import AccessPreviousVersions
 from Products.CMFPlone import PloneMessageFactory as _
+from Products.CMFPlone.interfaces import ISecuritySchema
 from Products.CMFPlone.utils import base_hasattr
 from Products.CMFPlone.utils import log
+from zope.component import getUtility
 
 from plone.app.layout.globals.interfaces import IViewView
 from plone.app.layout.viewlets import ViewletBase
@@ -64,11 +67,12 @@ def update(self):
         self.has_pam = HAS_PAM
 
     def show(self):
-        properties = getToolByName(self.context, 'portal_properties')
-        site_properties = getattr(properties, 'site_properties')
-        allowAnonymousViewAbout = site_properties.getProperty(
-            'allowAnonymousViewAbout', True)
-        return not self.anonymous or allowAnonymousViewAbout
+        registry = getUtility(IRegistry)
+        settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
+        return not self.anonymous or settings.allow_anon_views_about
 
     def show_history(self):
         has_access_preview_versions_permission = _checkPermission(
diff --git a/plone/app/layout/viewlets/tests/test_content.py b/plone/app/layout/viewlets/tests/test_content.py
index 2e32def..d474d08 100644
--- a/plone/app/layout/viewlets/tests/test_content.py
+++ b/plone/app/layout/viewlets/tests/test_content.py
@@ -8,6 +8,8 @@
 from plone.app.layout.viewlets.content import ContentRelatedItems
 from plone.locking.tests import addMember
 from plone.locking.interfaces import ILockable
+from plone.registry.interfaces import IRegistry
+from Products.CMFPlone.interfaces import ISecuritySchema
 
 from DateTime import DateTime
 from Products.CMFCore.utils import getToolByName
@@ -35,6 +37,44 @@ def afterSetUp(self):
         portal = getSite()
         addMember(portal, 'Alan', roles=('Member', 'Manager'))
         addMember(portal, 'Ano', roles=())
+        self.folder.invokeFactory('Document', 'doc1', title='Document 1')
+
+        registry = getUtility(IRegistry)
+        self.security_settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
+
+    def _get_viewlet(self):
+        context = self.folder['doc1']
+        request = self.app.REQUEST
+        viewlet = DocumentBylineViewlet(context, request, None, None)
+        viewlet.update()
+        return viewlet
+
+    def test_show_anonymous_not_allowed(self):
+        self.security_settings.allow_anon_views_about = False
+        self.logout()
+        viewlet = self._get_viewlet()
+        self.assertFalse(viewlet.show())
+
+    def test_show_anonymous_allowed(self):
+        self.security_settings.allow_anon_views_about = True
+        self.logout()
+        viewlet = self._get_viewlet()
+        self.assertTrue(viewlet.show())
+
+    def test_show_logged_in_anonymous_not_allowed(self):
+        self.security_settings.allow_anon_views_about = False
+        self.login('Alan')
+        viewlet = self._get_viewlet()
+        self.assertTrue(viewlet.show())
+
+    def test_show_logged_in_anonymous_allowed(self):
+        self.security_settings.allow_anon_views_about = True
+        self.login('Alan')
+        viewlet = self._get_viewlet()
+        self.assertTrue(viewlet.show())
 
     def test_anonymous_locked_icon(self):
         request = self.app.REQUEST


Repository: plone.app.layout
Branch: refs/heads/master
Date: 2015-01-25T13:52:55+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.layout@49137b1

restructure DocumentBylineViewlet tests

Files changed:
M plone/app/layout/viewlets/tests/test_content.py

diff --git a/plone/app/layout/viewlets/tests/test_content.py b/plone/app/layout/viewlets/tests/test_content.py
index d474d08..c459ded 100644
--- a/plone/app/layout/viewlets/tests/test_content.py
+++ b/plone/app/layout/viewlets/tests/test_content.py
@@ -34,10 +34,8 @@ class TestDocumentBylineViewletView(ViewletsTestCase):
     Test the document by line viewlet
     """
     def afterSetUp(self):
-        portal = getSite()
-        addMember(portal, 'Alan', roles=('Member', 'Manager'))
-        addMember(portal, 'Ano', roles=())
         self.folder.invokeFactory('Document', 'doc1', title='Document 1')
+        self.context = self.folder['doc1']
 
         registry = getUtility(IRegistry)
         self.security_settings = registry.forInterface(
@@ -46,9 +44,8 @@ def afterSetUp(self):
         )
 
     def _get_viewlet(self):
-        context = self.folder['doc1']
         request = self.app.REQUEST
-        viewlet = DocumentBylineViewlet(context, request, None, None)
+        viewlet = DocumentBylineViewlet(self.context, request, None, None)
         viewlet.update()
         return viewlet
 
@@ -66,57 +63,45 @@ def test_show_anonymous_allowed(self):
 
     def test_show_logged_in_anonymous_not_allowed(self):
         self.security_settings.allow_anon_views_about = False
-        self.login('Alan')
         viewlet = self._get_viewlet()
         self.assertTrue(viewlet.show())
 
     def test_show_logged_in_anonymous_allowed(self):
         self.security_settings.allow_anon_views_about = True
-        self.login('Alan')
         viewlet = self._get_viewlet()
         self.assertTrue(viewlet.show())
 
-    def test_anonymous_locked_icon(self):
-        request = self.app.REQUEST
-        self.setRoles(['Manager', 'Member'])
-        self.portal.invokeFactory('Document', 'd1')
-        context = getattr(self.portal, 'd1')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
-        ILockable(context).lock()
-        self.login('Ano')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
+    def test_anonymous_locked_icon_not_locked(self):
+        self.logout()
+        viewlet = self._get_viewlet()
         self.assertEqual(viewlet.locked_icon(), "")
 
-    def test_locked_icon(self):
-        request = self.app.REQUEST
-        self.setRoles(['Manager', 'Member'])
-        self.portal.invokeFactory('Document', 'd1')
-        context = getattr(self.portal, 'd1')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
+    def test_anonymous_locked_icon_is_locked(self):
+        self.logout()
+        ILockable(self.context).lock()
+        viewlet = self._get_viewlet()
         self.assertEqual(viewlet.locked_icon(), "")
-        ILockable(context).lock()
+
+    def test_logged_in_locked_icon_not_locked(self):
+        viewlet = self._get_viewlet()
+        self.assertEqual(viewlet.locked_icon(), "")
+
+    def test_logged_in_locked_icon_is_locked(self):
+        viewlet = self._get_viewlet()
+        ILockable(self.context).lock()
         lockIconUrl = '<img src="http://nohost/plone/lock_icon.png" alt="" \
 title="Locked" height="16" width="16" />'
         self.assertEqual(viewlet.locked_icon(), lockIconUrl)
 
     def test_pub_date(self):
-        request = self.app.REQUEST
-        self.login('Alan')
-        self.portal.invokeFactory('Document', 'd1')
-        context = getattr(self.portal, 'd1')
-
         # configure our portal to enable publication date on pages globally on
         # the site
-        properties = getToolByName(context, 'portal_properties')
+        properties = getToolByName(self.portal, 'portal_properties')
         site_properties = getattr(properties, 'site_properties')
         site_properties.displayPublicationDateInByline = True
 
-        self.login('Ano')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
+        self.logout()
+        viewlet = self._get_viewlet()
 
         # publication date should be None as there is not Effective date set
         # for our document yet
@@ -124,7 +109,7 @@ def test_pub_date(self):
 
         # now set effective date for our document
         effective = DateTime()
-        context.setEffectiveDate(effective)
+        self.context.setEffectiveDate(effective)
         self.assertEqual(viewlet.pub_date(), DateTime(effective.ISO8601()))
 
         # now switch off publication date globally on the site and see if


Repository: plone.app.layout
Branch: refs/heads/master
Date: 2015-01-25T16:56:29+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.layout@24d7cb6

remove unused imports, reorganize imports in test_content

Files changed:
M plone/app/layout/viewlets/tests/test_content.py

diff --git a/plone/app/layout/viewlets/tests/test_content.py b/plone/app/layout/viewlets/tests/test_content.py
index c459ded..d7f4476 100644
--- a/plone/app/layout/viewlets/tests/test_content.py
+++ b/plone/app/layout/viewlets/tests/test_content.py
@@ -1,18 +1,15 @@
-from z3c.relationfield import RelationValue
-from zope.component import getUtility
-from zope.component.hooks import getSite
-from zope.interface import Interface
-from zope.intid.interfaces import IIntIds
+from DateTime import DateTime
 from plone.app.layout.viewlets.tests.base import ViewletsTestCase
 from plone.app.layout.viewlets.content import DocumentBylineViewlet
 from plone.app.layout.viewlets.content import ContentRelatedItems
-from plone.locking.tests import addMember
 from plone.locking.interfaces import ILockable
 from plone.registry.interfaces import IRegistry
-from Products.CMFPlone.interfaces import ISecuritySchema
-
-from DateTime import DateTime
 from Products.CMFCore.utils import getToolByName
+from Products.CMFPlone.interfaces import ISecuritySchema
+from z3c.relationfield import RelationValue
+from zope.component import getUtility
+from zope.interface import Interface
+from zope.intid.interfaces import IIntIds
 
 try:
     import pkg_resources


Repository: plone.app.layout
Branch: refs/heads/master
Date: 2015-02-27T07:49:09+01:00
Author: Timo Stollenwerk () <contact@timostollenwerk.net>
Commit: plone/plone.app.layout@8d8c3cc

Merge branch 'master' into plip10359-security-controlpanel

Conflicts:
	CHANGES.rst

Files changed:
A plone/app/layout/globals/tests/test_pattern_settings.py
M CHANGES.rst
M plone/app/layout/globals/patterns_settings.py
M plone/app/layout/links/viewlets.py
M plone/app/layout/viewlets/common.py
M plone/app/layout/viewlets/searchbox.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 2e0a425..9c87a70 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,6 +8,12 @@ Changelog
   properties (see plone/Products.CMFPlone#216).
   [jcerjak]
 
+- use livesearch pattern
+  [vangheem]
+
+- use configuration registry pattern options
+  [vangheem]
+
 - Added support for site logos stored in the portal registry via the site
   control panel for the logo viewlet with a fallback to the ``OFS.Image``
   based ``logo.png`` file. Removed support of long-gone
diff --git a/plone/app/layout/globals/patterns_settings.py b/plone/app/layout/globals/patterns_settings.py
index f72115d..669bbd1 100644
--- a/plone/app/layout/globals/patterns_settings.py
+++ b/plone/app/layout/globals/patterns_settings.py
@@ -2,12 +2,12 @@
 
 from zope.interface import implements
 from zope.component import getAdapters
-from zope.component.hooks import getSite
 from zope.publisher.browser import BrowserView
 from .interfaces import IPatternsSettingsRenderer
 from Products.CMFPlone.interfaces import IPatternsSettings
-
-import json
+from plone.registry.interfaces import IRegistry
+from zope.component import getUtility
+from zope.component import getMultiAdapter
 
 
 class PatternsSettings(BrowserView):
@@ -17,20 +17,28 @@ class PatternsSettings(BrowserView):
     implements(IPatternsSettingsRenderer)
 
     def __call__(self):
-        modal_options = {
-            'actionOptions': {
-                'displayInModal': False,
-            }
-        }
-        base_url = getSite().absolute_url()
+        portal_state = getMultiAdapter(
+            (self.context, self.request), name=u'plone_portal_state')
+        # do not use getSite because it's possible it could be different
+        # than the actual portal url
+        base_url = portal_state.portal_url()
         result = {
-            'data-pat-modal': json.dumps(modal_options),
             'data-base-url': self.context.absolute_url(),
             'data-portal-url': base_url,
             'data-i18ncatalogurl': base_url + '/plonejsi18n'
         }
+
+        # first, check for any adapters that need pattern data defined
         adapters = getAdapters((self.context, self.request, None), IPatternsSettings)
         [result.update(x[1]()) for x in adapters]
-        return result
 
+        # Resources Registered UI patterns can override adapters
+        registry = getUtility(IRegistry)
+        try:
+            pattern_options = registry['plone.patternoptions']
+        except (AttributeError, KeyError):
+            pattern_options = {}
+        for key, value in pattern_options.items():
+            result['data-pat-' + key] = value
 
+        return result
diff --git a/plone/app/layout/globals/tests/test_pattern_settings.py b/plone/app/layout/globals/tests/test_pattern_settings.py
new file mode 100644
index 0000000..a17cc1a
--- /dev/null
+++ b/plone/app/layout/globals/tests/test_pattern_settings.py
@@ -0,0 +1,33 @@
+from plone.app.layout.globals.tests.base import GlobalsTestCase
+from plone.app.layout.globals.patterns_settings import PatternsSettings
+from plone.registry.interfaces import IRegistry
+from zope.component import getUtility
+
+
+class TestPatternSettings(GlobalsTestCase):
+    """Ensure that the basic redirector setup is successful.
+    """
+
+    def testShouldReturnCorrectType(self):
+        settings = PatternsSettings(self.folder, self.app.REQUEST)
+        result = settings()
+        self.assertEquals(type(result), dict)
+        for key, value in result.items():
+            self.assertTrue(isinstance(key, basestring))
+            self.assertTrue(isinstance(value, basestring))
+
+    def testUrls(self):
+        settings = PatternsSettings(self.folder, self.app.REQUEST)
+        result = settings()
+        self.assertEquals(result['data-base-url'], self.folder.absolute_url())
+        self.assertEquals(result['data-portal-url'], self.portal.absolute_url())
+
+    def testPatternOptions(self):
+        registry = getUtility(IRegistry)
+        registry['plone.patternoptions'] = {
+            'foo': u'{"foo": "bar"}'
+        }
+
+        settings = PatternsSettings(self.folder, self.app.REQUEST)
+        result = settings()
+        self.assertEquals(result['data-pat-foo'], u'{"foo": "bar"}')
\ No newline at end of file
diff --git a/plone/app/layout/links/viewlets.py b/plone/app/layout/links/viewlets.py
index 3ec1283..48d1534 100644
--- a/plone/app/layout/links/viewlets.py
+++ b/plone/app/layout/links/viewlets.py
@@ -112,12 +112,13 @@ def update(self):
                     settings = registry.forInterface(ISiteSyndicationSettings)
                 except KeyError:
                     return
-                for uid in settings.site_rss_items:
-                    obj = uuidToObject(uid)
-                    if obj is not None:
-                        self.rsslinks.extend(self.getRssLinks(obj))
-                self.rsslinks.extend(self.getRssLinks(
-                    self.portal_state.portal()))
+                if settings.site_rss_items:
+                    for uid in settings.site_rss_items:
+                        obj = uuidToObject(uid)
+                        if obj is not None:
+                            self.rsslinks.extend(self.getRssLinks(obj))
+                    self.rsslinks.extend(self.getRssLinks(
+                        self.portal_state.portal()))
         else:
             if util.context_enabled():
                 self.rsslinks.extend(self.getRssLinks(self.context))
diff --git a/plone/app/layout/viewlets/common.py b/plone/app/layout/viewlets/common.py
index 0f65305..4a05b72 100644
--- a/plone/app/layout/viewlets/common.py
+++ b/plone/app/layout/viewlets/common.py
@@ -17,6 +17,7 @@
 
 from Products.CMFCore.utils import getToolByName
 from Products.CMFPlone.interfaces import ISiteSchema
+from Products.CMFPlone.interfaces import ISearchSchema
 from Products.CMFPlone.utils import safe_unicode
 from Products.CMFPlone.interfaces import IPloneSiteRoot
 from Products.Five.browser import BrowserView
@@ -175,13 +176,9 @@ def update(self):
         context_state = getMultiAdapter((self.context, self.request),
                                         name=u'plone_context_state')
 
-        props = getToolByName(self.context, 'portal_properties')
-        livesearch = props.site_properties.getProperty(
-            'enable_livesearch', False)
-        if livesearch:
-            self.search_input_id = "searchGadget"
-        else:
-            self.search_input_id = "nolivesearchGadget"  # don't use "" here!
+        registry = getUtility(IRegistry)
+        search_settings = registry.forInterface(ISearchSchema, prefix='plone')
+        self.livesearch = search_settings.enable_livesearch
 
         folder = context_state.folder()
         self.folder_path = '/'.join(folder.getPhysicalPath())
diff --git a/plone/app/layout/viewlets/searchbox.pt b/plone/app/layout/viewlets/searchbox.pt
index 879a6d7..bde537c 100644
--- a/plone/app/layout/viewlets/searchbox.pt
+++ b/plone/app/layout/viewlets/searchbox.pt
@@ -1,30 +1,30 @@
 <div id="portal-searchbox"
      i18n:domain="plone"
-     tal:define="navigation_root_url view/navigation_root_url;
-                 search_input_id view/search_input_id;">
+     tal:define="navigation_root_url view/navigation_root_url;">
 
     <form id="searchGadget_form"
           action="@@search"
           role="search"
           tal:attributes="action string:${navigation_root_url}/@@search;
-                          id string:${search_input_id}_form;">
+                          data-pat-livesearch string:ajaxUrl:${navigation_root_url}/@@ajax-search;
+                          class python: view.livesearch and 'pat-livesearch' or ''">
 
         <div class="LSBox">
         <label class="hiddenStructure"
-               tal:attributes="for search_input_id"
+               for="searchGadget"
                i18n:translate="text_search">Search Site</label>
 
         <input name="SearchableText"
                type="text"
                size="18"
                value=""
+               id="searchGadget"
                title="Search Site"
                placeholder="Search Site"
                accesskey="4"
                i18n:attributes="title title_search_site;
                                 placeholder title_search_site"
-               tal:attributes="value request/form/SearchableText|nothing;
-                               id search_input_id"
+               tal:attributes="value request/form/SearchableText|nothing;"
                class="searchField" />
 
         <input class="searchButton"
@@ -46,8 +46,6 @@
                 only in current section
             </label>
         </div>
-
-        <div class="LSResult" id="LSResult"><div class="LSShadow" id="LSShadow"></div></div>
         </div>
     </form>
 


Repository: plone.app.layout
Branch: refs/heads/master
Date: 2015-02-27T10:10:33+01:00
Author: Timo Stollenwerk (tisto) <tisto@plone.org>
Commit: plone/plone.app.layout@1cdded0

Merge pull request #39 from plone/plip10359-security-controlpanel

Plip10359 security controlpanel

Files changed:
M CHANGES.rst
M plone/app/layout/links/viewlets.py
M plone/app/layout/viewlets/content.py
M plone/app/layout/viewlets/tests/test_content.py

diff --git a/CHANGES.rst b/CHANGES.rst
index 7051605..9c87a70 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,10 @@ Changelog
 2.5.4 (unreleased)
 ------------------
 
+- Read ``allow_anon_views_about`` settings from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
+
 - use livesearch pattern
   [vangheem]
 
diff --git a/plone/app/layout/links/viewlets.py b/plone/app/layout/links/viewlets.py
index 238c61d..48d1534 100644
--- a/plone/app/layout/links/viewlets.py
+++ b/plone/app/layout/links/viewlets.py
@@ -13,6 +13,7 @@
 from zope.schema.interfaces import IVocabularyFactory
 from zope.component import getUtility
 from plone.registry.interfaces import IRegistry
+from Products.CMFPlone.interfaces import ISecuritySchema
 from Products.CMFPlone.interfaces.syndication import IFeedSettings
 from Products.CMFPlone.interfaces.syndication import ISiteSyndicationSettings
 
@@ -62,12 +63,13 @@ def update(self):
                                      name='plone_tools')
 
     def show(self):
-        properties = self.tools.properties()
-        site_properties = getattr(properties, 'site_properties')
         anonymous = self.portal_state.anonymous()
-        allowAnonymousViewAbout = site_properties.getProperty(
-            'allowAnonymousViewAbout', True)
-        return not anonymous or allowAnonymousViewAbout
+        registry = getUtility(IRegistry)
+        settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
+        return not anonymous or settings.allow_anon_views_about
 
     def render(self):
         if self.show():
diff --git a/plone/app/layout/viewlets/content.py b/plone/app/layout/viewlets/content.py
index 15adcbd..7ac2abf 100644
--- a/plone/app/layout/viewlets/content.py
+++ b/plone/app/layout/viewlets/content.py
@@ -6,14 +6,17 @@
 from AccessControl import getSecurityManager
 from Acquisition import aq_inner
 from DateTime import DateTime
+from plone.registry.interfaces import IRegistry
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 from Products.CMFCore.utils import _checkPermission
 from Products.CMFCore.utils import getToolByName
 from Products.CMFCore.WorkflowCore import WorkflowException
 from Products.CMFEditions.Permissions import AccessPreviousVersions
 from Products.CMFPlone import PloneMessageFactory as _
+from Products.CMFPlone.interfaces import ISecuritySchema
 from Products.CMFPlone.utils import base_hasattr
 from Products.CMFPlone.utils import log
+from zope.component import getUtility
 
 from plone.app.layout.globals.interfaces import IViewView
 from plone.app.layout.viewlets import ViewletBase
@@ -64,11 +67,12 @@ def update(self):
         self.has_pam = HAS_PAM
 
     def show(self):
-        properties = getToolByName(self.context, 'portal_properties')
-        site_properties = getattr(properties, 'site_properties')
-        allowAnonymousViewAbout = site_properties.getProperty(
-            'allowAnonymousViewAbout', True)
-        return not self.anonymous or allowAnonymousViewAbout
+        registry = getUtility(IRegistry)
+        settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
+        return not self.anonymous or settings.allow_anon_views_about
 
     def show_history(self):
         has_access_preview_versions_permission = _checkPermission(
diff --git a/plone/app/layout/viewlets/tests/test_content.py b/plone/app/layout/viewlets/tests/test_content.py
index 2e32def..d7f4476 100644
--- a/plone/app/layout/viewlets/tests/test_content.py
+++ b/plone/app/layout/viewlets/tests/test_content.py
@@ -1,16 +1,15 @@
-from z3c.relationfield import RelationValue
-from zope.component import getUtility
-from zope.component.hooks import getSite
-from zope.interface import Interface
-from zope.intid.interfaces import IIntIds
+from DateTime import DateTime
 from plone.app.layout.viewlets.tests.base import ViewletsTestCase
 from plone.app.layout.viewlets.content import DocumentBylineViewlet
 from plone.app.layout.viewlets.content import ContentRelatedItems
-from plone.locking.tests import addMember
 from plone.locking.interfaces import ILockable
-
-from DateTime import DateTime
+from plone.registry.interfaces import IRegistry
 from Products.CMFCore.utils import getToolByName
+from Products.CMFPlone.interfaces import ISecuritySchema
+from z3c.relationfield import RelationValue
+from zope.component import getUtility
+from zope.interface import Interface
+from zope.intid.interfaces import IIntIds
 
 try:
     import pkg_resources
@@ -32,51 +31,74 @@ class TestDocumentBylineViewletView(ViewletsTestCase):
     Test the document by line viewlet
     """
     def afterSetUp(self):
-        portal = getSite()
-        addMember(portal, 'Alan', roles=('Member', 'Manager'))
-        addMember(portal, 'Ano', roles=())
+        self.folder.invokeFactory('Document', 'doc1', title='Document 1')
+        self.context = self.folder['doc1']
+
+        registry = getUtility(IRegistry)
+        self.security_settings = registry.forInterface(
+            ISecuritySchema,
+            prefix='plone',
+        )
 
-    def test_anonymous_locked_icon(self):
+    def _get_viewlet(self):
         request = self.app.REQUEST
-        self.setRoles(['Manager', 'Member'])
-        self.portal.invokeFactory('Document', 'd1')
-        context = getattr(self.portal, 'd1')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
-        ILockable(context).lock()
-        self.login('Ano')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
+        viewlet = DocumentBylineViewlet(self.context, request, None, None)
         viewlet.update()
+        return viewlet
+
+    def test_show_anonymous_not_allowed(self):
+        self.security_settings.allow_anon_views_about = False
+        self.logout()
+        viewlet = self._get_viewlet()
+        self.assertFalse(viewlet.show())
+
+    def test_show_anonymous_allowed(self):
+        self.security_settings.allow_anon_views_about = True
+        self.logout()
+        viewlet = self._get_viewlet()
+        self.assertTrue(viewlet.show())
+
+    def test_show_logged_in_anonymous_not_allowed(self):
+        self.security_settings.allow_anon_views_about = False
+        viewlet = self._get_viewlet()
+        self.assertTrue(viewlet.show())
+
+    def test_show_logged_in_anonymous_allowed(self):
+        self.security_settings.allow_anon_views_about = True
+        viewlet = self._get_viewlet()
+        self.assertTrue(viewlet.show())
+
+    def test_anonymous_locked_icon_not_locked(self):
+        self.logout()
+        viewlet = self._get_viewlet()
         self.assertEqual(viewlet.locked_icon(), "")
 
-    def test_locked_icon(self):
-        request = self.app.REQUEST
-        self.setRoles(['Manager', 'Member'])
-        self.portal.invokeFactory('Document', 'd1')
-        context = getattr(self.portal, 'd1')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
+    def test_anonymous_locked_icon_is_locked(self):
+        self.logout()
+        ILockable(self.context).lock()
+        viewlet = self._get_viewlet()
         self.assertEqual(viewlet.locked_icon(), "")
-        ILockable(context).lock()
+
+    def test_logged_in_locked_icon_not_locked(self):
+        viewlet = self._get_viewlet()
+        self.assertEqual(viewlet.locked_icon(), "")
+
+    def test_logged_in_locked_icon_is_locked(self):
+        viewlet = self._get_viewlet()
+        ILockable(self.context).lock()
         lockIconUrl = '<img src="http://nohost/plone/lock_icon.png" alt="" \
 title="Locked" height="16" width="16" />'
         self.assertEqual(viewlet.locked_icon(), lockIconUrl)
 
     def test_pub_date(self):
-        request = self.app.REQUEST
-        self.login('Alan')
-        self.portal.invokeFactory('Document', 'd1')
-        context = getattr(self.portal, 'd1')
-
         # configure our portal to enable publication date on pages globally on
         # the site
-        properties = getToolByName(context, 'portal_properties')
+        properties = getToolByName(self.portal, 'portal_properties')
         site_properties = getattr(properties, 'site_properties')
         site_properties.displayPublicationDateInByline = True
 
-        self.login('Ano')
-        viewlet = DocumentBylineViewlet(context, request, None, None)
-        viewlet.update()
+        self.logout()
+        viewlet = self._get_viewlet()
 
         # publication date should be None as there is not Effective date set
         # for our document yet
@@ -84,7 +106,7 @@ def test_pub_date(self):
 
         # now set effective date for our document
         effective = DateTime()
-        context.setEffectiveDate(effective)
+        self.context.setEffectiveDate(effective)
         self.assertEqual(viewlet.pub_date(), DateTime(effective.ISO8601()))
 
         # now switch off publication date globally on the site and see if
@tisto
Copy link
Sponsor Member Author

tisto commented Feb 27, 2015

@jcerjak is it possible that all tests pass now?

http://jenkins.plone.org/view/PLIPs/job/PLIP-10359/8/console

After I set up the Jenkins job on the new machine all tests seem to pass. Will check on my local machine...

@jcerjak
Copy link
Member

jcerjak commented Feb 28, 2015

@tisto, if it sounds too good to be true, it probably is :)

I did:

  • git pull
  • bin/buildout -c plips/plip10359-security-controlpanel.cfg
  • bin/test

and I get a bunch of errors. Am I missing something?

@tisto
Copy link
Sponsor Member Author

tisto commented Feb 28, 2015

There must be something wrong with the Jenkins job. I get errors when I run the tests locally. BTW: running "bin/test" without any params will not work in buildout.coredev. You always have to run "bin/alltests" and "bin/alltests-at".

@tisto
Copy link
Sponsor Member Author

tisto commented Feb 28, 2015

Ok, this is a configuration problem. I will investigate it further...

@jcerjak
Copy link
Member

jcerjak commented Mar 2, 2015

Ok, thanks!

tisto added a commit to plone/buildout.coredev that referenced this issue Mar 2, 2015
Branch: refs/heads/master
Date: 2015-01-26T19:50:04+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.collection@67e3724

Read "allow_anon_views_about" from registry instead of properties

Files changed:
M CHANGES.rst
M plone/app/collection/browser/templates/standard_view.pt

diff --git a/CHANGES.rst b/CHANGES.rst
index 169f9c9..9adfd4e 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,7 +4,9 @@ Changelog
 1.1.3 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Read ``allow_anon_views_about`` setting from the registry instead of portal
+  properties (see plone/Products.CMFPlone#216).
+  [jcerjak]
 
 
 1.1.2 (2014-10-23)
diff --git a/plone/app/collection/browser/templates/standard_view.pt b/plone/app/collection/browser/templates/standard_view.pt
index 052ebf8..408e4d2 100644
--- a/plone/app/collection/browser/templates/standard_view.pt
+++ b/plone/app/collection/browser/templates/standard_view.pt
@@ -33,7 +33,7 @@
                              isAnon context/@@plone_portal_state/anonymous;
                              normalizeString nocall: context/plone_utils/normalizeString;
                              toLocalizedTime nocall: context/@@plone/toLocalizedTime;
-                             show_about python:not isAnon or site_properties.allowAnonymousViewAbout;
+                             show_about python:not isAnon or context.portal_registry['plone.allow_anon_views_about'];
                              navigation_root_url context/@@plone_portal_state/navigation_root_url;
                              pas_member context/@@pas_member;">
         <tal:listing condition="batch">


Repository: plone.app.collection
Branch: refs/heads/master
Date: 2015-02-27T07:50:17+01:00
Author: Timo Stollenwerk () <contact@timostollenwerk.net>
Commit: plone/plone.app.collection@321bd07

Merge branch 'master' into plip10359-security-controlpanel

Conflicts:
	CHANGES.rst

Files changed:
A plone/app/collection/marshaller.py
M CHANGES.rst
M plone/app/collection/collection.py
M plone/app/collection/configure.zcml
M plone/app/collection/tests/test_collection.py
M setup.py

diff --git a/CHANGES.rst b/CHANGES.rst
index 9adfd4e..d42b982 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -8,6 +8,9 @@ Changelog
   properties (see plone/Products.CMFPlone#216).
   [jcerjak]
 
+- Support for import and export of collections using FTP, DAV and GenericSetup
+  [matthewwilkes]
+
 
 1.1.2 (2014-10-23)
 ------------------
diff --git a/plone/app/collection/collection.py b/plone/app/collection/collection.py
index eac3bce..5504a4e 100644
--- a/plone/app/collection/collection.py
+++ b/plone/app/collection/collection.py
@@ -2,7 +2,7 @@
 from OFS.ObjectManager import ObjectManager
 from plone.app.collection.field import QueryField
 from plone.app.contentlisting.interfaces import IContentListing
-from plone.app.widgets.at import QueryStringWidget
+from Products.Archetypes.Widget import QueryStringWidget
 from Products.ATContentTypes.content import document, schemata
 from Products.Archetypes import atapi
 from Products.Archetypes.atapi import (BooleanField,
@@ -20,7 +20,7 @@
 from plone.app.collection import PloneMessageFactory as _
 from plone.app.collection.config import ATCT_TOOLNAME, PROJECTNAME
 from plone.app.collection.interfaces import ICollection
-
+from plone.app.collection.marshaller import CollectionRFC822Marshaller
 
 CollectionSchema = document.ATDocumentSchema.copy() + atapi.Schema((
 
@@ -86,6 +86,9 @@
         ),
 ))
 
+# Use the extended marshaller that understands queries
+CollectionSchema.registerLayer("marshall", CollectionRFC822Marshaller())
+
 CollectionSchema.moveField('query', after='description')
 if 'presentation' in CollectionSchema:
     CollectionSchema['presentation'].widget.visible = False
diff --git a/plone/app/collection/configure.zcml b/plone/app/collection/configure.zcml
index 33ce9dc..d2bda5d 100644
--- a/plone/app/collection/configure.zcml
+++ b/plone/app/collection/configure.zcml
@@ -14,7 +14,7 @@
     name="default"
     title="plone.app.collection"
     directory="profiles/default"
-    description="Adds support for new style collections to Plone"
+    description="Archetypes-based collections"
     provides="Products.GenericSetup.interfaces.EXTENSION"
     />
 
diff --git a/plone/app/collection/marshaller.py b/plone/app/collection/marshaller.py
new file mode 100644
index 0000000..acab0ad
--- /dev/null
+++ b/plone/app/collection/marshaller.py
@@ -0,0 +1,68 @@
+from types import ListType, TupleType
+
+from zope.contenttype import guess_content_type
+
+from AccessControl import ClassSecurityInfo
+from App.class_init import InitializeClass
+from Products.Archetypes.interfaces.base import IBaseUnit
+from Products.Archetypes.utils import mapply
+from Products.Archetypes.Marshall import RFC822Marshaller, parseRFC822, formatRFC822Headers
+
+
+class CollectionRFC822Marshaller(RFC822Marshaller):
+
+    security = ClassSecurityInfo()
+    security.declareObjectPrivate()
+    security.setDefaultAccess('deny')
+
+    def demarshall(self, instance, data, **kwargs):
+        # We don't want to pass file forward.
+        if 'file' in kwargs:
+            if not data:
+                # TODO Yuck! Shouldn't read the whole file, never.
+                # OTOH, if you care about large files, you should be
+                # using the PrimaryFieldMarshaller or something
+                # similar.
+                data = kwargs['file'].read()
+            del kwargs['file']
+        headers, body = parseRFC822(data)
+        
+        query = {}
+        for k, v in headers.items():
+            if not k.startswith("query"):
+                continue
+            else:
+                index = int(k[5])
+                sub_key = k.split("_")[1]
+                query_part = query.get(index, {})
+                query_part[sub_key] = v
+                query[index] = query_part
+                del headers[k]
+        query = [facet[1] for facet in sorted(query.items())]
+        
+        header = formatRFC822Headers(headers.items())
+        data = '%s\n\n%s' % (header, body)
+        
+        try:
+            return RFC822Marshaller.demarshall(self, instance, data, **kwargs)
+        finally:
+            instance.query = query
+
+    def marshall(self, instance, **kwargs):
+        content_type, length, data = RFC822Marshaller.marshall(self, instance, **kwargs)
+        headers, body = parseRFC822(data)
+        
+        headers = headers.items()
+        for i, query in enumerate(instance.query):
+            for key, value in query.items():
+                if isinstance(value, list):
+                    value = "\n".join(value)
+                header_key = 'query%d_%s' % (i, key)
+                headers.append((header_key, value))
+        
+        header = formatRFC822Headers(headers)
+        data = '%s\n\n%s' % (header, body)
+        length = len(data)
+        return (content_type, length, data)
+
+InitializeClass(CollectionRFC822Marshaller)
\ No newline at end of file
diff --git a/plone/app/collection/tests/test_collection.py b/plone/app/collection/tests/test_collection.py
index f1611e7..9599d3e 100644
--- a/plone/app/collection/tests/test_collection.py
+++ b/plone/app/collection/tests/test_collection.py
@@ -7,6 +7,7 @@
 from plone.app.testing import setRoles
 from plone.testing.z2 import Browser
 from transaction import commit
+from Products.Archetypes.Marshall import parseRFC822
 
 import unittest2 as unittest
 
@@ -235,3 +236,94 @@ def test_selectedViewFields(self):
     def test_syndication_enabled_by_default(self):
         syn = getToolByName(self.portal, 'portal_syndication')
         self.assertTrue(syn.isSyndicationAllowed(self.collection))
+
+
+class TestMarshalling(unittest.TestCase):
+
+    layer = PLONEAPPCOLLECTION_INTEGRATION_TESTING
+
+    def test_simple_query_included_in_marshall_results(self):
+        portal = self.layer['portal']
+        login(portal, 'admin')
+        query = [{
+            'i': 'portal_type',
+            'o': 'plone.app.querystring.operation.string.is',
+            'v': 'News Item',
+        }]
+        portal.invokeFactory("Collection",
+                             "collection",
+                             query=query,
+                             title="New Collection")
+        collection = portal['collection']
+        rfc822 = collection.manage_FTPget()
+        data = parseRFC822(rfc822)
+        self.assertIn('query0_i', data[0])
+        self.assertIn('query0_o', data[0])
+        self.assertIn('query0_v', data[0])
+        
+        self.assertEqual(data[0]['query0_i'], query[0]['i'])
+        self.assertEqual(data[0]['query0_o'], query[0]['o'])
+        self.assertEqual(data[0]['query0_v'], query[0]['v'])
+    
+    def test_multiple_query_items_included_in_marshall_results(self):
+        portal = self.layer['portal']
+        login(portal, 'admin')
+        query = [{
+            'i': 'portal_type',
+            'o': 'plone.app.querystring.operation.string.is',
+            'v': 'News Item',
+        },{ 'i': 'Title',
+            'o': 'plone.app.querystring.operation.string.is',
+            'v': 'Test News Item',
+        }]
+        
+        portal.invokeFactory("Collection",
+                             "collection",
+                             query=query,
+                             title="New Collection")
+        collection = portal['collection']
+        rfc822 = collection.manage_FTPget()
+        data = parseRFC822(rfc822)
+        
+        self.assertIn('query0_i', data[0])
+        self.assertIn('query0_o', data[0])
+        self.assertIn('query0_v', data[0])
+        self.assertIn('query1_i', data[0])
+        self.assertIn('query1_o', data[0])
+        self.assertIn('query1_v', data[0])
+        
+        self.assertEqual(data[0]['query0_i'], query[0]['i'])
+        self.assertEqual(data[0]['query0_o'], query[0]['o'])
+        self.assertEqual(data[0]['query0_v'], query[0]['v'])
+        self.assertEqual(data[0]['query1_i'], query[1]['i'])
+        self.assertEqual(data[0]['query1_o'], query[1]['o'])
+        self.assertEqual(data[0]['query1_v'], query[1]['v'])
+    
+    def test_query_gets_set_on_PUT(self):
+        portal = self.layer['portal']
+        login(portal, 'admin')
+        query = [{
+            'i': 'portal_type',
+            'o': 'plone.app.querystring.operation.string.is',
+            'v': 'News Item',
+        }]
+        
+        expected_query = [{
+            'i': 'portal_type',
+            'o': 'plone.app.querystring.operation.string.is',
+            'v': 'LOREM IPSUM DOLOR',
+        }]
+        
+        portal.invokeFactory("Collection",
+                             "collection",
+                             query=query,
+                             title="New Collection")
+        collection = portal['collection']
+        rfc822 = collection.manage_FTPget()
+        # Modify the response to put in a sentinal, to check it's been updated
+        rfc822 = rfc822.replace(query[0]['v'], expected_query[0]['v'])
+        
+        portal.REQUEST.set("BODY", rfc822)
+        collection.PUT(portal.REQUEST, None)
+        self.assertEqual(collection.query, expected_query)
+    
diff --git a/setup.py b/setup.py
index c4d4d8d..9a982fb 100644
--- a/setup.py
+++ b/setup.py
@@ -31,7 +31,7 @@
           'plone.app.widgets',
           'plone.portlet.collection',
           'plone.portlets',
-          'Products.Archetypes',
+          'Products.Archetypes>=1.10.4.dev0',
           'Products.CMFCore',
           'Products.CMFPlone',
           'Products.CMFQuickInstallerTool',


Repository: plone.app.collection
Branch: refs/heads/master
Date: 2015-02-27T14:39:17+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.collection@2da6fa1

restore plone 4 compatibility for 'show about' setting

Files changed:
M CHANGES.rst
M plone/app/collection/browser/templates/standard_view.pt
M plone/app/collection/tests/test_collection.py

diff --git a/CHANGES.rst b/CHANGES.rst
index d42b982..10ee51a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,8 +4,8 @@ Changelog
 1.1.3 (unreleased)
 ------------------
 
-- Read ``allow_anon_views_about`` setting from the registry instead of portal
-  properties (see plone/Products.CMFPlone#216).
+- Read ``allow_anon_views_about`` setting from the registry, with fallback to
+  portal properties (see plone/Products.CMFPlone#216)
   [jcerjak]
 
 - Support for import and export of collections using FTP, DAV and GenericSetup
diff --git a/plone/app/collection/browser/templates/standard_view.pt b/plone/app/collection/browser/templates/standard_view.pt
index 408e4d2..2d036bc 100644
--- a/plone/app/collection/browser/templates/standard_view.pt
+++ b/plone/app/collection/browser/templates/standard_view.pt
@@ -29,11 +29,14 @@
         <tal:results define="b_start python:request.get('b_start', 0);
                              batch python:context.results(b_start=b_start);
                              site_properties context/portal_properties/site_properties;
+                             portal_registry context/portal_registry|nothing;
                              use_view_action site_properties/typesUseViewActionInListings|python:();
                              isAnon context/@@plone_portal_state/anonymous;
                              normalizeString nocall: context/plone_utils/normalizeString;
                              toLocalizedTime nocall: context/@@plone/toLocalizedTime;
-                             show_about python:not isAnon or context.portal_registry['plone.allow_anon_views_about'];
+                             show_about_bbb site_properties/allowAnonymousViewAbout|nothing;
+                             show_about_registry python:portal_registry and portal_registry.get('plone.allow_anon_views_about');
+                             show_about python:not isAnon or show_about_registry or show_about_bbb;
                              navigation_root_url context/@@plone_portal_state/navigation_root_url;
                              pas_member context/@@pas_member;">
         <tal:listing condition="batch">
diff --git a/plone/app/collection/tests/test_collection.py b/plone/app/collection/tests/test_collection.py
index 9599d3e..b2640ff 100644
--- a/plone/app/collection/tests/test_collection.py
+++ b/plone/app/collection/tests/test_collection.py
@@ -42,6 +42,14 @@ def setUp(self):
             pass
         self.collection = self.portal['col']
 
+    def _set_up_collection(self):
+        self.portal.invokeFactory(
+            'Document',
+            'doc1',
+            title='Collection Test Page'
+        )
+        self.collection.setQuery(query)
+
     def test_addCollection(self):
         self.portal.invokeFactory("Collection",
                                   "col1",
@@ -114,6 +122,160 @@ def test_viewingCollection(self):
         browser.open(self.collection.absolute_url())
         self.assertTrue("Collection Test Page" in browser.contents)
 
+    def test_show_about_no_registry_has_property_noshow(self):
+        """Test the case where we fetch show about information from portal
+        properties (Plone < 5) and show about is False.
+        """
+        # disable show about in site properties
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', False, 'boolean')
+        except:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=False)
+        self.portal.portal_registry = None
+
+        self._set_up_collection()
+
+        # logout and check if author information is hidden
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertFalse("author" in result)
+        self.assertFalse("test-user" in result)
+
+    def test_show_about_no_registry_has_property_show(self):
+        """Test the case where we fetch show about information from portal
+        properties (Plone < 5) and show about is True.
+        """
+        # enable show about in site properties
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', True, 'boolean')
+        except:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=True)
+        self.portal.portal_registry = None
+
+        self._set_up_collection()
+
+        # logout and check if author information is shown
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
+    def test_show_about_has_property_and_registry_noshow(self):
+        """Test the case where we fetch show about information from portal
+        properties, but registry is also present (Plone < 5, with
+        plone.app.registry installed) and show about is False.
+        """
+        # disable show about in site properties, create an empty registry
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', False, 'boolean')
+        except:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=False)
+        self.portal.portal_registry = {}  # mock the registry
+
+        self._set_up_collection()
+
+        # logout and check if author information is hidden
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertFalse("author" in result)
+        self.assertFalse("test-user" in result)
+
+    def test_show_about_has_property_and_registry_show(self):
+        """Test the case where we fetch show about information from portal
+        properties, but registry is also present (Plone < 5, with
+        plone.app.registry installed) and show about is True.
+        """
+        # enable show about in site properties, create an empty registry
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', True, 'boolean')
+        except:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=True)
+        self.portal.portal_registry = {}  # mock the registry
+
+        self._set_up_collection()
+
+        # logout and check if author information is shown
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
+    def test_show_about_has_registry_no_property_noshow(self):
+        """Test the case where we fetch show about information from the
+        registry (Plone >= 5) and show about is False.
+        """
+        # disable show about in the registry, delete 'allowAnonymousViewAbout'
+        # property
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_delProperties(
+                ['allowAnonymousViewAbout'])
+        except:
+            pass
+        self.portal.portal_registry = {'plone.allow_anon_views_about': False}
+
+        self._set_up_collection()
+
+        # logout and check if author information is hidden
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertFalse("author" in result)
+        self.assertFalse("test-user" in result)
+
+    def test_show_about_has_registry_no_property_show(self):
+        """Test the case where we fetch show about information from the
+        registry (Plone >= 5) and show about is True.
+        """
+        # enable show about in the registry, delete 'allowAnonymousViewAbout'
+        # property
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_delProperties(
+                ['allowAnonymousViewAbout'])
+        except:
+            pass
+        self.portal.portal_registry = {'plone.allow_anon_views_about': True}
+
+        self._set_up_collection()
+
+        # logout and check if author information is shown
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
+    def test_show_about_logged_in(self):
+        """Test the case where we show about information if a user is logged in
+        even though show about is set to False
+        """
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', False, 'boolean')
+        except:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=False)
+        self.portal.portal_registry = {'plone.allow_anon_views_about': False}
+
+        self._set_up_collection()
+
+        # check if author information is shown
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
     def test_collection_templates(self):
         data = getData('image.png')
         # add an image that will be listed by the collection
@@ -260,11 +422,11 @@ def test_simple_query_included_in_marshall_results(self):
         self.assertIn('query0_i', data[0])
         self.assertIn('query0_o', data[0])
         self.assertIn('query0_v', data[0])
-        
+
         self.assertEqual(data[0]['query0_i'], query[0]['i'])
         self.assertEqual(data[0]['query0_o'], query[0]['o'])
         self.assertEqual(data[0]['query0_v'], query[0]['v'])
-    
+
     def test_multiple_query_items_included_in_marshall_results(self):
         portal = self.layer['portal']
         login(portal, 'admin')
@@ -276,7 +438,7 @@ def test_multiple_query_items_included_in_marshall_results(self):
             'o': 'plone.app.querystring.operation.string.is',
             'v': 'Test News Item',
         }]
-        
+
         portal.invokeFactory("Collection",
                              "collection",
                              query=query,
@@ -284,21 +446,21 @@ def test_multiple_query_items_included_in_marshall_results(self):
         collection = portal['collection']
         rfc822 = collection.manage_FTPget()
         data = parseRFC822(rfc822)
-        
+
         self.assertIn('query0_i', data[0])
         self.assertIn('query0_o', data[0])
         self.assertIn('query0_v', data[0])
         self.assertIn('query1_i', data[0])
         self.assertIn('query1_o', data[0])
         self.assertIn('query1_v', data[0])
-        
+
         self.assertEqual(data[0]['query0_i'], query[0]['i'])
         self.assertEqual(data[0]['query0_o'], query[0]['o'])
         self.assertEqual(data[0]['query0_v'], query[0]['v'])
         self.assertEqual(data[0]['query1_i'], query[1]['i'])
         self.assertEqual(data[0]['query1_o'], query[1]['o'])
         self.assertEqual(data[0]['query1_v'], query[1]['v'])
-    
+
     def test_query_gets_set_on_PUT(self):
         portal = self.layer['portal']
         login(portal, 'admin')
@@ -307,13 +469,13 @@ def test_query_gets_set_on_PUT(self):
             'o': 'plone.app.querystring.operation.string.is',
             'v': 'News Item',
         }]
-        
+
         expected_query = [{
             'i': 'portal_type',
             'o': 'plone.app.querystring.operation.string.is',
             'v': 'LOREM IPSUM DOLOR',
         }]
-        
+
         portal.invokeFactory("Collection",
                              "collection",
                              query=query,
@@ -322,8 +484,7 @@ def test_query_gets_set_on_PUT(self):
         rfc822 = collection.manage_FTPget()
         # Modify the response to put in a sentinal, to check it's been updated
         rfc822 = rfc822.replace(query[0]['v'], expected_query[0]['v'])
-        
+
         portal.REQUEST.set("BODY", rfc822)
         collection.PUT(portal.REQUEST, None)
         self.assertEqual(collection.query, expected_query)
-    


Repository: plone.app.collection
Branch: refs/heads/master
Date: 2015-02-27T18:30:41+01:00
Author: Jure Cerjak (jcerjak) <jcerjak@termitnjak.si>
Commit: plone/plone.app.collection@8dc58e5

don't do bare excepts

Files changed:
M plone/app/collection/tests/test_collection.py

diff --git a/plone/app/collection/tests/test_collection.py b/plone/app/collection/tests/test_collection.py
index b2640ff..0804004 100644
--- a/plone/app/collection/tests/test_collection.py
+++ b/plone/app/collection/tests/test_collection.py
@@ -1,3 +1,4 @@
+from Products.Archetypes.Marshall import parseRFC822
 from Products.CMFCore.utils import getToolByName
 from plone.app.collection.testing import PLONEAPPCOLLECTION_INTEGRATION_TESTING
 from plone.app.testing import TEST_USER_ID
@@ -7,7 +8,7 @@
 from plone.app.testing import setRoles
 from plone.testing.z2 import Browser
 from transaction import commit
-from Products.Archetypes.Marshall import parseRFC822
+from zExceptions import BadRequest
 
 import unittest2 as unittest
 
@@ -131,7 +132,7 @@ def test_show_about_no_registry_has_property_noshow(self):
         try:
             properties.site_properties.manage_addProperty(
                 'allowAnonymousViewAbout', False, 'boolean')
-        except:
+        except BadRequest:
             properties.site_properties.manage_changeProperties(
                 allowAnonymousViewAbout=False)
         self.portal.portal_registry = None
@@ -153,7 +154,7 @@ def test_show_about_no_registry_has_property_show(self):
         try:
             properties.site_properties.manage_addProperty(
                 'allowAnonymousViewAbout', True, 'boolean')
-        except:
+        except BadRequest:
             properties.site_properties.manage_changeProperties(
                 allowAnonymousViewAbout=True)
         self.portal.portal_registry = None
@@ -176,7 +177,7 @@ def test_show_about_has_property_and_registry_noshow(self):
         try:
             properties.site_properties.manage_addProperty(
                 'allowAnonymousViewAbout', False, 'boolean')
-        except:
+        except BadRequest:
             properties.site_properties.manage_changeProperties(
                 allowAnonymousViewAbout=False)
         self.portal.portal_registry = {}  # mock the registry
@@ -199,7 +200,7 @@ def test_show_about_has_property_and_registry_show(self):
         try:
             properties.site_properties.manage_addProperty(
                 'allowAnonymousViewAbout', True, 'boolean')
-        except:
+        except BadRequest:
             properties.site_properties.manage_changeProperties(
                 allowAnonymousViewAbout=True)
         self.portal.portal_registry = {}  # mock the registry
@@ -222,7 +223,7 @@ def test_show_about_has_registry_no_property_noshow(self):
         try:
             properties.site_properties.manage_delProperties(
                 ['allowAnonymousViewAbout'])
-        except:
+        except BadRequest:
             pass
         self.portal.portal_registry = {'plone.allow_anon_views_about': False}
 
@@ -244,7 +245,7 @@ def test_show_about_has_registry_no_property_show(self):
         try:
             properties.site_properties.manage_delProperties(
                 ['allowAnonymousViewAbout'])
-        except:
+        except BadRequest:
             pass
         self.portal.portal_registry = {'plone.allow_anon_views_about': True}
 
@@ -264,7 +265,7 @@ def test_show_about_logged_in(self):
         try:
             properties.site_properties.manage_addProperty(
                 'allowAnonymousViewAbout', False, 'boolean')
-        except:
+        except BadRequest:
             properties.site_properties.manage_changeProperties(
                 allowAnonymousViewAbout=False)
         self.portal.portal_registry = {'plone.allow_anon_views_about': False}


Repository: plone.app.collection
Branch: refs/heads/master
Date: 2015-03-02T18:07:09+01:00
Author: Timo Stollenwerk (tisto) <tisto@plone.org>
Commit: plone/plone.app.collection@f50678f

Merge pull request #22 from plone/plip10359-security-controlpanel

Plip 10359 - Security Control Panel migration

Files changed:
M CHANGES.rst
M plone/app/collection/browser/templates/standard_view.pt
M plone/app/collection/tests/test_collection.py

diff --git a/CHANGES.rst b/CHANGES.rst
index 734edfa..10ee51a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,10 @@ Changelog
 1.1.3 (unreleased)
 ------------------
 
+- Read ``allow_anon_views_about`` setting from the registry, with fallback to
+  portal properties (see plone/Products.CMFPlone#216)
+  [jcerjak]
+
 - Support for import and export of collections using FTP, DAV and GenericSetup
   [matthewwilkes]
 
diff --git a/plone/app/collection/browser/templates/standard_view.pt b/plone/app/collection/browser/templates/standard_view.pt
index 052ebf8..2d036bc 100644
--- a/plone/app/collection/browser/templates/standard_view.pt
+++ b/plone/app/collection/browser/templates/standard_view.pt
@@ -29,11 +29,14 @@
         <tal:results define="b_start python:request.get('b_start', 0);
                              batch python:context.results(b_start=b_start);
                              site_properties context/portal_properties/site_properties;
+                             portal_registry context/portal_registry|nothing;
                              use_view_action site_properties/typesUseViewActionInListings|python:();
                              isAnon context/@@plone_portal_state/anonymous;
                              normalizeString nocall: context/plone_utils/normalizeString;
                              toLocalizedTime nocall: context/@@plone/toLocalizedTime;
-                             show_about python:not isAnon or site_properties.allowAnonymousViewAbout;
+                             show_about_bbb site_properties/allowAnonymousViewAbout|nothing;
+                             show_about_registry python:portal_registry and portal_registry.get('plone.allow_anon_views_about');
+                             show_about python:not isAnon or show_about_registry or show_about_bbb;
                              navigation_root_url context/@@plone_portal_state/navigation_root_url;
                              pas_member context/@@pas_member;">
         <tal:listing condition="batch">
diff --git a/plone/app/collection/tests/test_collection.py b/plone/app/collection/tests/test_collection.py
index 9599d3e..0804004 100644
--- a/plone/app/collection/tests/test_collection.py
+++ b/plone/app/collection/tests/test_collection.py
@@ -1,3 +1,4 @@
+from Products.Archetypes.Marshall import parseRFC822
 from Products.CMFCore.utils import getToolByName
 from plone.app.collection.testing import PLONEAPPCOLLECTION_INTEGRATION_TESTING
 from plone.app.testing import TEST_USER_ID
@@ -7,7 +8,7 @@
 from plone.app.testing import setRoles
 from plone.testing.z2 import Browser
 from transaction import commit
-from Products.Archetypes.Marshall import parseRFC822
+from zExceptions import BadRequest
 
 import unittest2 as unittest
 
@@ -42,6 +43,14 @@ def setUp(self):
             pass
         self.collection = self.portal['col']
 
+    def _set_up_collection(self):
+        self.portal.invokeFactory(
+            'Document',
+            'doc1',
+            title='Collection Test Page'
+        )
+        self.collection.setQuery(query)
+
     def test_addCollection(self):
         self.portal.invokeFactory("Collection",
                                   "col1",
@@ -114,6 +123,160 @@ def test_viewingCollection(self):
         browser.open(self.collection.absolute_url())
         self.assertTrue("Collection Test Page" in browser.contents)
 
+    def test_show_about_no_registry_has_property_noshow(self):
+        """Test the case where we fetch show about information from portal
+        properties (Plone < 5) and show about is False.
+        """
+        # disable show about in site properties
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', False, 'boolean')
+        except BadRequest:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=False)
+        self.portal.portal_registry = None
+
+        self._set_up_collection()
+
+        # logout and check if author information is hidden
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertFalse("author" in result)
+        self.assertFalse("test-user" in result)
+
+    def test_show_about_no_registry_has_property_show(self):
+        """Test the case where we fetch show about information from portal
+        properties (Plone < 5) and show about is True.
+        """
+        # enable show about in site properties
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', True, 'boolean')
+        except BadRequest:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=True)
+        self.portal.portal_registry = None
+
+        self._set_up_collection()
+
+        # logout and check if author information is shown
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
+    def test_show_about_has_property_and_registry_noshow(self):
+        """Test the case where we fetch show about information from portal
+        properties, but registry is also present (Plone < 5, with
+        plone.app.registry installed) and show about is False.
+        """
+        # disable show about in site properties, create an empty registry
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', False, 'boolean')
+        except BadRequest:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=False)
+        self.portal.portal_registry = {}  # mock the registry
+
+        self._set_up_collection()
+
+        # logout and check if author information is hidden
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertFalse("author" in result)
+        self.assertFalse("test-user" in result)
+
+    def test_show_about_has_property_and_registry_show(self):
+        """Test the case where we fetch show about information from portal
+        properties, but registry is also present (Plone < 5, with
+        plone.app.registry installed) and show about is True.
+        """
+        # enable show about in site properties, create an empty registry
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', True, 'boolean')
+        except BadRequest:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=True)
+        self.portal.portal_registry = {}  # mock the registry
+
+        self._set_up_collection()
+
+        # logout and check if author information is shown
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
+    def test_show_about_has_registry_no_property_noshow(self):
+        """Test the case where we fetch show about information from the
+        registry (Plone >= 5) and show about is False.
+        """
+        # disable show about in the registry, delete 'allowAnonymousViewAbout'
+        # property
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_delProperties(
+                ['allowAnonymousViewAbout'])
+        except BadRequest:
+            pass
+        self.portal.portal_registry = {'plone.allow_anon_views_about': False}
+
+        self._set_up_collection()
+
+        # logout and check if author information is hidden
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertFalse("author" in result)
+        self.assertFalse("test-user" in result)
+
+    def test_show_about_has_registry_no_property_show(self):
+        """Test the case where we fetch show about information from the
+        registry (Plone >= 5) and show about is True.
+        """
+        # enable show about in the registry, delete 'allowAnonymousViewAbout'
+        # property
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_delProperties(
+                ['allowAnonymousViewAbout'])
+        except BadRequest:
+            pass
+        self.portal.portal_registry = {'plone.allow_anon_views_about': True}
+
+        self._set_up_collection()
+
+        # logout and check if author information is shown
+        logout()
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
+    def test_show_about_logged_in(self):
+        """Test the case where we show about information if a user is logged in
+        even though show about is set to False
+        """
+        properties = getToolByName(self.portal, 'portal_properties')
+        try:
+            properties.site_properties.manage_addProperty(
+                'allowAnonymousViewAbout', False, 'boolean')
+        except BadRequest:
+            properties.site_properties.manage_changeProperties(
+                allowAnonymousViewAbout=False)
+        self.portal.portal_registry = {'plone.allow_anon_views_about': False}
+
+        self._set_up_collection()
+
+        # check if author information is shown
+        result = self.collection.restrictedTraverse('standard_view')()
+        self.assertTrue("author" in result)
+        self.assertTrue("test-user" in result)
+
     def test_collection_templates(self):
         data = getData('image.png')
         # add an image that will be listed by the collection
@@ -260,11 +423,11 @@ def test_simple_query_included_in_marshall_results(self):
         self.assertIn('query0_i', data[0])
         self.assertIn('query0_o', data[0])
         self.assertIn('query0_v', data[0])
-        
+
         self.assertEqual(data[0]['query0_i'], query[0]['i'])
         self.assertEqual(data[0]['query0_o'], query[0]['o'])
         self.assertEqual(data[0]['query0_v'], query[0]['v'])
-    
+
     def test_multiple_query_items_included_in_marshall_results(self):
         portal = self.layer['portal']
         login(portal, 'admin')
@@ -276,7 +439,7 @@ def test_multiple_query_items_included_in_marshall_results(self):
             'o': 'plone.app.querystring.operation.string.is',
             'v': 'Test News Item',
         }]
-        
+
         portal.invokeFactory("Collection",
                              "collection",
                              query=query,
@@ -284,21 +447,21 @@ def test_multiple_query_items_included_in_marshall_results(self):
         collection = portal['collection']
         rfc822 = collection.manage_FTPget()
         data = parseRFC822(rfc822)
-        
+
         self.assertIn('query0_i', data[0])
         self.assertIn('query0_o', data[0])
         self.assertIn('query0_v', data[0])
         self.assertIn('query1_i', data[0])
         self.assertIn('query1_o', data[0])
         self.assertIn('query1_v', data[0])
-        
+
         self.assertEqual(data[0]['query0_i'], query[0]['i'])
         self.assertEqual(data[0]['query0_o'], query[0]['o'])
         self.assertEqual(data[0]['query0_v'], query[0]['v'])
         self.assertEqual(data[0]['query1_i'], query[1]['i'])
         self.assertEqual(data[0]['query1_o'], query[1]['o'])
         self.assertEqual(data[0]['query1_v'], query[1]['v'])
-    
+
     def test_query_gets_set_on_PUT(self):
         portal = self.layer['portal']
         login(portal, 'admin')
@@ -307,13 +470,13 @@ def test_query_gets_set_on_PUT(self):
             'o': 'plone.app.querystring.operation.string.is',
             'v': 'News Item',
         }]
-        
+
         expected_query = [{
             'i': 'portal_type',
             'o': 'plone.app.querystring.operation.string.is',
             'v': 'LOREM IPSUM DOLOR',
         }]
-        
+
         portal.invokeFactory("Collection",
                              "collection",
                              query=query,
@@ -322,8 +485,7 @@ def test_query_gets_set_on_PUT(self):
         rfc822 = collection.manage_FTPget()
         # Modify the response to put in a sentinal, to check it's been updated
         rfc822 = rfc822.replace(query[0]['v'], expected_query[0]['v'])
-        
+
         portal.REQUEST.set("BODY", rfc822)
         collection.PUT(portal.REQUEST, None)
         self.assertEqual(collection.query, expected_query)
-
@tisto
Copy link
Sponsor Member Author

tisto commented Mar 2, 2015

All pull requests merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants