Custom user preferences storage - plone

I’m creating a new add-on that will include some user preferences.
Let’s say each user can select multiple categories from a list of all content categories.
My goals are:
the users preferences must be persistent (maybe OK to have them still here if I reinstall the add-on)
the register and personal preferences pages to remain the same. I will have a custom view - form to update the preferences related to this add-on.
easy to index the values in a custom catalog. The catalog will be used to search users interested in a subject (Example: my_custom_catalog.query(subject=“Education”) -> list of brains containing users data subscribed to “Education” topic). The catalog is removed on uninstall and updated when a user changes his preferences.
Can you recommend the best way to store this data? Can I use memberdata without changes in register and personal default forms? Or better to use persistent objects (import persistent)? (Any example very appreciated.)

In profiles/default/memberdata_properties.xml:
<?xml version="1.0"?>
<object name="portal_memberdata">
<property name="custom_topics" type="lines"></property>
</object>
You will create an upgrade step to import memberdata-properties.
Then use:
user = api.user.get(user_id)
user.getProperty("custom_topics")
to get the values and
user.setMemberProperties({'custom_topics':list_of_selected_topics})
to update them.
These values remain stored when the catalog is removed / add-on is uninstalled.
Also no changes in register page and personal preferences form, only if you want to (by extending them).

Related

Audit Alfresco Share previews

Obsolete Alfresco documentation says:
the download or preview of content are recorded as a single read
However, with Alfresco 5+ preview does not generate any audit event (I just tried).
QUESTION: How to make Alfresco log an audit event when someone previews a document on Alfresco Share? I am not too worried about thumbnails, but at least for the "Document Details" page:
Here is my audit application configuration:
audit.alfresco-access.enabled=true
audit.tagging.enabled=false
audit.filter.alfresco-access.default.enabled=true
audit.filter.alfresco-access.transaction.type=cm:folder;cm:content
audit.filter.alfresco-access.transaction.action=CREATE|READ|UPDATE CONTENT|CHECK IN|DELETE|COPY|MOVE
audit.audit-custom.enabled=true
audit.audit-custom.sub-actions.enabled=false
Your filter for actions is not set right,
Please note that you should be using ; for separating multiple possible values, not |.
So, I think you should be able to get previews and downloads audited with:
audit.filter.alfresco-access.transaction.action=CREATE;READ;UPDATE CONTENT;CHECK IN;DELETE;COPY;MOVE
Please note also that you might want to audit one extra action : READCONTENT

Keep a log of user actions in Symfony2

I'm working on a project where I'm using Symfony2 (latest) and SonataAdmin. I need to keep log of users actions by logging:
action/event date/time (when and at which time the user did something)
the user himself (the id of the user who did the action/event)
affected rows (which rows was affected by for example changing some data in a form)
I find in KnpBundles and over Google without success, can any give me some tips or ideas? Or if someone did this before give me some code as start point? Take in mind that I'm using SonataAdmin and this is a bit complicated.
The stofDoctrineExtensions (a Symfony wrapper for Gedmo's DoctrineExtensions) Loggable extension would do this for you.
This extensions can be set to log a username, changed (create, updated & remove) and the data changed (if specified) in a table that can then be used to log and/or revert changes.
StofDoctrineExtensions (Wrapper of below)
Gedmo\DoctrineExtensions (Loggable)

User edits only its own post.Using Plone permisisons

I have a Plone website and create a menu item.
In the sharing tab I add each user that can post a topic.
How can I prevent that user1 edits posts owned by user2? Currently user1 can edit user2 posts.
Previously I try creating a group, assign each user to this group and add the group using the sharing tab, but in this way one user edit posts from another user.
Just subtract (uncheck) the 'Can edit'-permission of the sharing-tab.
The creator of an item is by default also owner, owners have edit-permission, thus users can edit their own items but not the ones of others.
Update (according to the new comment):
To inhibit the add-privilege on subfolders you'll need to break the inheritage of the Contributors-role, to which the 'Can add'-permission is assigned to.
However this seems not to be possible, yet. Quoting Martin Aspeli from his article "Understanding permissions and roles":
"Currently (until Plone 2.1, most likely), local roles can be added at a lower level in the acqusition tree, but not taken away".
So you need to look for another approach and, as Martijn already suggested, you'll most likely want to go with a custom workflow for your - assumingly folderish - contenttype and to all types that should be allowed to add in it (fortunately by default, Images and Files inherit the state of its parent, otherwise you probably have to think of a multi-chained workflow, but that's worth a new post even, or - ugly - create copies of contenttypes only to give them another workflow).
In that case, do as follows:
Create a workflow as adviced in http://developer.plone.org/content/workflow.html (I updated it lately, please let us know, if you have suggestions for improvements or contribute yourself).
Add the 'Add portal content'-permission to your workflow (in ZMI clickon your workflowname andhit the permissions-tab, select it from the dropdown).
For each state in your workflow (click on the state's name), uncheck 'Aquire permission settings', this way you break the inheritage of the Contibutors-role. Then check the 'Add portal content'-permission for each role you want to grant it, which would be at least the Owner-role in your case, and you might also Managers be able to access everything.
Update2:
Another, more challenging but IMHO much better, approach could be:
On your contenttype's inititialization (=your ct's class is called) trigger a script (f.e. with a contentrule/eventhandler/subscriber or in you ct's class-definition, itself), which looks up the inherited sharing-permissions on the parent, blocks them (__ac_local_roles_block__ = True) and reassign all roles again, but the Contributor's one, for the new born object (your folderish contenttype).
This would avoid creating a whole new workflow just to solve this case.
To do this, please read the docs (just updated, comments always welcome), to see how an event-handler is registrated:
http://developer.plone.org/components/events.html?highlight=events#example-register-an-event-handler-on-your-contenttype-s-creation
The executed python-script could contain s.th. like:
from Acquisition import aq_parent
def inhibit_parent_inherited_contributor_role(self, event):
""" Blocks local-roles on freshly created children in our
contenttype and re-assigns all its parent's local-roles but
'Contributor' to the child.
"""
# Block all inherited local-permissions, also of grand-parents:
self.__ac_local_roles_block__ = True
# Get local-roles assigned to parent and only to parent:
parent_roles = self.aq_parent.get_local_roles()
# Iterate over each assigned user and group to get their roles:
for userid, roles in parent_roles:
# Provide a list variable, to collect the new roles:
# of a group or user:
new_roles = []
# Iterate over the user's, respectively group's, roles:
for role in roles:
# Exclude 'Contributor' of new role-list:
if role != u'Contributor':
# Add all other roles to list of new roles:
new_roles.append(role)
# Finally assign new roles to the child for each found user and group:
self.manage_setLocalRoles(userid, new_roles)
Disclaimer:
I have tested this with IObjectEditedEvent, which works fine. Whereas the IObjectAddedEvent is fired four times (why?) and I wasn't able to tame that quickly, but plone.app.contentrules.handlers.py, does :) Have a closer look at it, maybe including a contentrule in the solution can be even better.
For an in-depth code-example about roles, see Andreas Jung's lovely zopyx.plone.cassandra and its computeRoleMap.py .
And I haven't looked at collective.subtractiveworkflow, yet. In case you do, please tell us about it :)
You need to restrict editing to the Owner role if you only want to have users edit their own content.

How do I prevent a content type from appearing in collections?

How do I prevent a specific content type from appearing in collections (smart folders) site wide in Plone 3? I've looked for relevant options in portal_types and the types and search control panel (turning off the content type for searching doesn't seem to have an effect on collections).
Specific situation: I recently installed plone.app.discussion on a Plone 3.3.5 installation and now comments appear in all the collections. We want to remove them from the collections.
Thanks.
Portal Types criterion is based on plone.app.vocabularies.ReallyUserFriendlyTypes, a vocabulary factory defined in http://svn.plone.org/svn/plone/plone.app.vocabularies/trunk/plone/app/vocabularies/types.py.
If you patch BAD_TYPES by adding discussion comments you'll exclude them from Collections, but you'll also hide them from anywhere this vocabulary factory is used. As far as I know they are also used in contentrules and search control panel.
You can patch BAD_TYPES by adding these lines into __init__.py file of a custom package:
def initialize(context):
"""Initializer called when used as a Zope 2 product."""
from plone.app.vocabularies import types
types.BAD_TYPES = types.BAD_TYPES + ('Discussion Item',)
If you don't have too many collections, the simplest solution might be to add criteria to exclude comments. You can easily get a list of all your collections:
http://your-site/search?portal_type%3Alist=Topic
If you have a lot of collections, you might need to write some custom code to do this. It doesn't have to be a product or anything serious, just some code you can run to add an 'exclude comments' criteria to existing collections. I would start by looking around line 507 of http://svn.plone.org/svn/collective/Products.ATContentTypes/branches/1.3/Products/ATContentTypes/tests/test_criteria.py
You can add criteria to your collections stating which content types you want to display. You can not (without patching/hacking) choose which to exclude.
I.e collections have can have type whitelilsts not blacklists.

Take data from a field from exsisting node and make that the default value of a field in different content type

I don't know if I'm on the right track but I'm trying to let users of my web site create there own versions of pages on my web site.
Basically I'd like to make our documentation used as a starting point where they just add details and make a new page for themselves in the process.
I have a 'book' content type that I have changed with CCK and a 'client edits' content type that uses a nodereferencefromURL widget to link itself to the book node.
So simple version of what I'm saying is I have a link on my book pages that creates a node using client edits content type. I would like to put some fields on the client edits content type that take the values of some of the fields from the book page it is linked from.
I'm sure I'm missing something as I would have thought someone would have tried this before but I can't even find a hint on how to go about this.
All I really need is a point in the right direction if my current thinking is wrong.
Current thinking is that I use a php script to get the default value for a field on the new node add screen that drags the value for a field from the book I'm linking from.
I'm thinking this is the case because there is an option for default values for the field in cck manage fields that lets you put in a php value to return a default value for your field.
Am I on the right track or is there already a module or process that does what I'm talking about and I'm just too dumb to find it.
This sounds a little strange, are your client edits going to be a diff from the original node or just coppied data?
I would prehaps do it a more simple way, just have book nodes, and have different fields disaply depending on who edits it (enable the content_permissions module). That way you can use the node clone module to create the users copy.
You will need to make a module to contain your custom php code.
I ended up using rules to save information from the user and the cloned node into hidden fields.
One that saved the original node ID into a field when ever you create content of that type unless the url ends with Clone. This means that when you create the clone the original node ID is kept in the field.
That made it easy to use a views argument that took the node ID to make the clone appear along side the original when a user visits the original page.
The second rule trick was to compute a field that saved the "store name" from the profile of the user only when saving clone content.
This meant that there was a hidden field on the clone that stored the info so I could then use another views argument to restrict the view to only people with the same store name in their profile.
I am no good with PHP but I managed to find a snippet (can't remember where) that returns the store name of the current logged in user as the argument.
global $user;
profile_load_profile($user);
return $user->profile_store_name;

Resources