Allow Anonymous users to add Dexterity objects - plone

I have a Dexterity-based container that holds inside a Dexterity-based item. I need to let Anonymous users to add objects of this type inside the container.
I already created a rolemap.xml file with the following:
<?xml version="1.0"?>
<rolemap>
<permissions>
<permission name="my.package: Add My Type" acquire="True">
<role name="Anonymous"/>
</permission>
</permissions>
</rolemap>
I declared the permission on configure.zcml:
<permission
id="my.package.AddMyType"
title="my.package: Add My Type"
/>
and finally I added a custom add view like this one:
class MyAddView(dexterity.AddForm):
grok.name('MyType')
grok.require('my.package.AddMyType')
the form is already showing up for anonymous users but, when I press the save button I'm redirected to the login form.
also, logged in users are also able to see the form and this is supposed not to be happening.
what else I have to do?

thanks to David Glick, who guided me, I ended up with a very simple solution involving the add method of the AddForm class:
class MyAddView(dexterity.AddForm):
grok.name('MyType')
grok.require('my.package.AddMyType')
def update(self):
# check here if the user is anonymous and raise exception if not
super(AddView, self).update()
def add(self, object):
container = aq_inner(self.context)
addContentToContainer(container, object, checkConstraints=False)
self.immediate_view = container.absolute_url()
to understand it better, you may want to take a look at the original code in plone.dexterity.
one important thing you may also note is that you probably need to fix your workflow permissions to remove Owner role from some of them, or you could end with content editable by anonymous users also.

Related

Plone: default display for new created content

I have a browser view my_custom_display, that can be selected for folders using the menu: Display -> my_custom_display.
The problem appears after I select the custom display and I'm trying to create new objects inside the folder with this custom display.
By default all new items seems to have my_custom_display and my solution is to manually fix it with /selectViewTemplate?templateId=folder_listing.
What is the better solution for this situations? (Set a display only for the item itself not any new child inside it.)
(It's annoying because my browser view generates errors if used in wrong place. Yes, I can improve it, but...)
Update:
In /portal_types/Folder/manage_propertiesForm I added my_custom_display in Available view methods. I need it only for specific folders.
Solved by forcing layout setting on folder creation:
<subscriber
for="Products.ATContentTypes.interfaces.IATFolder
Products.Archetypes.event.ObjectInitializedEvent"
handler="my.package.globalhandlers.set_folder_listing_by_default" />
added in configure.cfg.
Then:
def set_folder_listing_by_default(folder, event):
""" Set folder_listing as default Display for new created folders.
"""
folder.setLayout('folder_listing')
Seems not nice, but it solved my issue. :)

Plone - How can I setDefaultPage in an event subscriber?

I have a folderish dexterity content type and I have an event subscriber. When the content type is created, I create a Collection, which shows the children in the container according to several parameters. After the collection is created, I try to set the default page of the container to the collection.
def myContainerAdded(my_container, event):
#get container
#set advanced query for collection
#create collection with api.create
my_container.setDefaultPage(new_collection.id)
The subscriber in configure.zcml
<subscriber
for="my.product.my_container.IMyContainer
zope.lifecycleevent.interfaces.IObjectAddedEvent"
handler=".events.myContainerAdded" />
Unfortunately, the default page is not being fully set. It just shows the container page, but the Collection is selected under the 'Display' drop down.
If I click "Change content item as default view" and select the collection, it does change the default page to the collection.
Earlier, I was using a "setuphandler" to setup a folder structure (as opposed to an add event), and setDefaultPage was working. Am I forgetting a step since I'm attempting this through an event?
I am using plone.4.3.
Edit: I also tried:
my_container.default_page = new_collection.id
Edit:
I found something interesting. I temporarily commented out the code related to the collection in the event subscriber. I manually added the collection to the container object and then set the default page of the container to the collection. The container's default page was the collection.
Maybe something isn't getting indexed right?
In fact everything went well, it's just that after creating a Dexterity-based content-type, one will land on the default-view's URL, meaning '/view' is appended to the item's URL, which is an alias to the default-view-method and here resolves to the 'folder_listing'-template.
To overcome this quickly, you can add a redirect to the object's URL in the subscriber's method, without any view-name appended to the URL:
event.REQUEST.RESPONSE.redirect(my_container.absolute_url())

Alfresco custom model with sys:base as parent is having property cm:name

I have created a custom model with parent as sys:base and modified the share-config-custom.xml so that I can create the content from the share. After creating the content from share am unable to see the content in share or explore. Instead am getting the below error when checking from document details page.
The item cannot be found. Either you do not have permissions to view the item, it has been removed or it never existed.
In Node browser I can see cm:name in the property field. But as per the alfresco svn, sys:base is not having the property cm:name.
<type name="sys:base">
<title>Base</title>
<mandatory-aspects>
<aspect>sys:referenceable</aspect>
<aspect>sys:localized</aspect>
</mandatory-aspects>
</type>
Can someone please tell how the custom model get the cm:name property?
Also I want to delete the content. Is there any way to delete that content from share or explore?
Thanks in advance!
To delete your content, call the webscript
/slingshot/doclib/action/aspects/node/{store_type}/{store_id}/{id}
and send the sys:temporary as an argument.

Plone: Shown default views on navtree

My question is quite simple....
In Plone 4 (4.2) what I need to setup to make a default view, for example a simple page, to be shown in the navigation tree.
The navigation tree uses the INavigationQueryBuilder component to find all elements shown. The default implementation filters out anything used as a default page.
You'll have to provide your own implementation instead; but you can re-use the original implementation. All you have to do is alter the generated query a little; normally, if no more specific query is present, the is_default_page index is used to filter out default pages. But if your altered query adds a search for that index, then it'll not try to add a more specific filter. Setting it to search for (True, False) means it'll return both default and non-default pages, effectively neutralizing the filter.
The implementation then becomes:
from plone.app.portlets.portlets.navigation import QueryBuilder, INavigationPortlet
from zope.component import adapts
from zope.interface import implements, Interface
class INonDefaultPageFilteringNavigationPortlet(INavigationPortlet):
pass
class DontFilterDefaultQueryBuilder(QueryBuilder):
implements(INavigationQueryBuilder)
adapts(Interface, INavigationPortlet)
def __init__(self, context, portlet):
super(DontFilterDefaultQueryBuilder, self).__init__(context, portlet)
self.query['is_default_page'] = (True, False) # Don't filter out default pages
You'll have to register this as an adapter, and add the INonDefaultPageFilteringNavigationPortlet to your portlet to 'activate' this builder:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five">
<adapter factory=".yourmodule.DontFilterDefaultQueryBuilder" />
<five:implements
class="plone.app.portlets.portlets.navigation.Assignment"
interface=".yourmodule.INonDefaultPageFilteringNavigationPortlet" />
</configure>
All with the caveat that this is untested, but it should work.
You might also create a link in the folder, set destination to './idOfPage1' and set the link as defaultview of the folder.
Users without editing-rights will be redirected to Page1 then and the page itself will be shown in the navportlet.

If a user doesn't have permission to render a View (configured on configure.zcml), how do I raise Forbidden instead of redirecting to login_form?

I have a browser view, with some utilities. Is mainly an "utility view" that I traverse using old-style pt templates (that are inside skins folder). My browser/configure.zcml:
<browser:page
for="*"
name="my_view"
class=".myview.MyView"
allowed_interface=".myview.IMyView"
permission="my.permission"
/>
As you can see, it has a custom permission: this is needed because anonymous users can't render this view and this permission is really specific to a certain situation in my portal.
I thought: I'm going to try to render the view in my template.pt: since I've already set a permission in browser/configure.zcml, when trying to render Plone itself is going to handle this for me. So I did in my template
<span tal:define="my_view here/##myview">
</span>
So far, so good. A user without my.permission trying to get into /Plone/template.pt will fail. But Plone redirects to the login form, and I would prefer to raise a Forbidden exception instead. Something like:
<span tal:define="my_view here/##myview | here/raiseForbidden">
</span>
...but, of course, this doesn't work since the view rendering didn't throw an error. (I know here/raiseForbidden doesn't exist, it's here/raiseUnauthorized that is usually used but the concept is the same)
My question is: is it possible to do it? Configuring my permission somewhere, or configuring some method in my view (like render or __call__), that when a user doesn't have permission to render it, an exception like Forbidden is raised?
Plone redirects to the login form because you raise Unauthorized. If you want different behaviour you'll need to do something different.
In this case, you could directly redirect the user to a new page with an error message tailored to the situation.
actually you don't need to do this:
"tal:define="my_view here/##myview>"
because for browser views there's a default variable named "view" that already contain your class.
For raising an exception you should remove permission check from the zml directive and modify your class as below:
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from AccessControl import getSecurityManager
from AccessControl import Unauthorized
class YourBrowserView(BrowserView):
""" .. """
index = ViewPageTemplateFile("templates/yourtemplate.pt")
...
def __call__(self):
if not getSecurityManager().checkPermission(your.permission, self.context):
raise Unauthorized("You are not authorized! Go away!")
else: return index()
Bye
Giacomo

Resources