Commit f86cd124 authored by Jérome Perrin's avatar Jérome Perrin

first submission of PortalPreferences, a tool for managing user profiles.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@3605 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 6d3ab3ec
##############################################################################
#
# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
# Jerome Perrin <jerome@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Products.ERP5Type.Document.Folder import Folder
class Priority:
""" names for priorities """
SITE = 1
GROUP = 2
USER = 3
class Preference( Folder ):
"""
An user preference
"""
# CMF Type Definition
meta_type ='ERP5 Preference'
portal_type = 'Preference'
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.View)
def __init__(self, id) :
Folder.__init__(self, id)
self.priority = Priority.USER
security.declareProtected(Permissions.ViewManagementScreens, 'setPriority')
def setPriority(self, priority) :
""" Sets the priority of the preference"""
self.priority = priority
security.declareProtected(Permissions.View, 'getPriority')
def getPriority(self) :
""" Returns the priority of the preference """
return self.priority
##############################################################################
#
# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
# Jerome Perrin <jerome@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass, DTMLFile
from Acquisition import aq_base
from zLOG import LOG, DEBUG, BLATHER
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type import Permissions
from Products.ERP5Type.Cache import CachingMethod
from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Form import _dtmldir
class PreferenceTool(BaseTool):
""" PreferenceTool manages User Preferences / User profiles. """
id = 'portal_preferences'
meta_type = 'ERP5 Preference Tool'
portal_type = 'Preference Tool'
allowed_types = ( 'ERP5 Preference',)
security = ClassSecurityInfo()
security.declareProtected(
Permissions.ManagePortal, 'manage_overview' )
manage_overview = DTMLFile( 'explainPreferenceTool', _dtmldir )
security.declareProtected(
Permissions.ManagePortal, 'manage_group_preferences' )
manage_group_preferences = DTMLFile(
'PreferenceTool_managePreferences', _dtmldir )
manage_options = ( BaseTool.manage_options +
( { 'label' : 'User Groups Preferences'
, 'action' : 'manage_group_preferences'},))
__ac_permissions__ = ((Permissions.AddPortalContent, [], ['Member']),)
def _aq_dynamic(self, name):
""" if the name is a valid preference, then start a lookup on
active preferences. """
dynamic = BaseTool._aq_dynamic(self, name)
if dynamic is not None :
return dynamic
aq_base_name = getattr(aq_base(self), name, None)
if aq_base_name is not None :
return aq_base_name
if name in self.getValidPreferenceNames() :
LOG('PreferenceTool._aq_dynamic',
BLATHER, "good preference %s, looking up ..."%name)
return self.getPreference(name)
security.declareProtected(Permissions.View, "getPreference")
def getPreference(self, pref_name) :
""" get the preference on the most appopriate Preference object. """
found = 0
for pref in self._getMostAppropriatePreferences() :
attr = getattr(pref, pref_name, None)
if attr is not None :
found = 1
# test the attr is set
if callable(attr) :
value = attr()
else :
value = attr
if value not in (None, '', (), []) :
LOG('PreferenceTool.getPreference',
BLATHER, "found preference %s on %s"%(pref_name, pref))
return attr
if found :
return attr
security.declareProtected(Permissions.ModifyPortalContent, "setPreference")
def setPreference(self, pref_name, value) :
""" set the preference on the active Preference object"""
self.getActivePreference()._edit(**{pref_name:value})
security.declareProtected(Permissions.View, "getValidPreferenceNames")
def getValidPreferenceNames(self) :
""" return the list of attributes that are preferences names and
should be looked up on Preferences. """
def _getValidPreferenceNames(self) :
""" a cache for this method """
attr_list = []
try :
pref_portal_type = getToolByName(self, 'portal_types')['Preference']
except KeyError :
LOG('PreferenceTool', DEBUG, 'Preference type definition not found')
# When creating an ERP5 Site, this method is called, but the
# type is not installed yet
return []
for property_sheet in pref_portal_type.property_sheet_list :
# import the property sheet
property_sheet = getattr(__import__(property_sheet), property_sheet)
# then generate common method names
# (XXX should be available from ERP5Type API ?)
for attribute in property_sheet._properties :
attr_name = attribute['id']
attr_list += [ attr_name,
'get%s' % convertToUpperCase(attr_name),
'get%sList' % convertToUpperCase(attr_name), ]
for cat in getattr(property_sheet, '_categories', []) :
attr_list += [ 'get%s' % convertToUpperCase(cat),
'get%sId' % convertToUpperCase(cat),
'get%sTitle' % convertToUpperCase(cat),
'get%sValue' % convertToUpperCase(cat),
'get%sValueList' % convertToUpperCase(cat),
'get%sItemList' % convertToUpperCase(cat),
'get%sIdList' % convertToUpperCase(cat),
'get%sTitleList' % convertToUpperCase(cat),
'get%sList' % convertToUpperCase(cat),
]
LOG('PreferenceTool.getValidPreferenceNames', BLATHER, attr_list)
return attr_list
_getValidPreferenceNames = CachingMethod(
_getValidPreferenceNames, cache_duration = 600,
id = 'PreferenceTool._getPreferenceAttributes')
return _getValidPreferenceNames(self)
security.declarePrivate('_getMostAppropriatePreferences')
def _getMostAppropriatePreferences(self) :
""" return the most appropriate preferences objects,
sorted so that the first in the list should be applied first """
prefs = []
for pref in self.objectValues(spec=('ERP5 Preference', )) :
pref = pref.getObject()
if pref.getPreferenceState() == 'enabled' and \
self.getPortalObject().portal_membership.\
getAuthenticatedMember().allowed(pref, ['Owner']) :
prefs.append(pref)
prefs.sort(lambda b, a: cmp(a.getPriority(), b.getPriority()))
return prefs
security.declareProtected(Permissions.View, 'getActivePreference')
def getActivePreference(self) :
""" returns the current preference for the user.
Note that this preference may be read only. """
enabled_prefs = self._getMostAppropriatePreferences()
if len(enabled_prefs) > 0 :
return enabled_prefs[0]
security.declareProtected(Permissions.View, 'getDocumentTemplatesForFolder')
def getDocumentTemplatesForFolder(self, folder) :
""" returns all document templates that are in acceptable Preferences
for the folder """
acceptable_templates = []
for pref in self._getMostAppropriatePreferences() :
for doc in pref.objectValues() :
if hasattr(doc, 'getTemplateDestinationUidList') and \
folder.getUid() in doc.getTemplateDestinationUidList() :
acceptable_templates.append (doc)
LOG('PreferenceTool.getDocumentTemplatesForFolder',
BLATHER, 'templates for %s : %s' % (folder, acceptable_templates))
return acceptable_templates
security.declareProtected(Permissions.ManagePortal,
'manage_updateUserGroupsPreferences')
def manage_updateUserGroupsPreferences(self, REQUEST) :
""" action edit Users Groups Preferences from the management sceen """
for k, v in REQUEST.items() :
if k.startswith("preference_priority_") :
self[k[len('preference_priority_'):]].setPriority(v)
if REQUEST is not None:
return self.manage_group_preferences( self, REQUEST,
manage_tabs_message='Preference Priorities Updated')
InitializeClass(PreferenceTool)
##############################################################################
#
# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved.
# Jerome Perrin <jerome@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class AccountingPreferences :
"""
User Preferences for erp5_accounting
"""
_properties = (
{ 'id' : 'preferred_accounting_transaction_from_date',
'description' : 'The minimal date (inclusive) for transactions',
'type' : 'date',
'mode' : 'w' },
{ 'id' : 'preferred_accounting_transaction_at_date',
'description' : 'The maximal date (inclusive) for transactions',
'type' : 'date',
'mode' : 'w' },
{ 'id' : 'preferred_accounting_transaction_simulation_state',
'description' : 'The simulation state for transactions',
'type' : 'tokens',
'mode' : 'w'},
{ 'id' : 'preferred_accounting_transaction_section_category',
'description' : 'The section category for transactions; '\
'usually something like group/nexedi.',
'type' : 'string',
'mode' : 'w'},
{ 'id' : 'preferred_accounting_transaction_source_section',
'description' : 'The preferred section organisation.',
'type' : 'string',
'mode' : 'w'},
{ 'id' : 'preferred_accounting_transaction_currency',
'description' : 'The preferred currency.',
'type' : 'string',
'mode' : 'w'},
)
_categories = ('gap', 'group')
...@@ -34,24 +34,26 @@ ...@@ -34,24 +34,26 @@
from Products.ERP5Type.Utils import initializeProduct, updateGlobals from Products.ERP5Type.Utils import initializeProduct, updateGlobals
from AccessControl import ModuleSecurityInfo from AccessControl import ModuleSecurityInfo
import sys, Permissions import sys, Permissions
this_module = sys.modules[ __name__ ]
document_classes = updateGlobals( this_module, globals(), permissions_module = Permissions)
from Products.PythonScripts.Utility import allow_class from Products.PythonScripts.Utility import allow_class
this_module = sys.modules[ __name__ ]
import Selection document_classes = updateGlobals( this_module, globals(),
allow_class(Selection) permissions_module = Permissions)
# Define object classes and tools # Define object classes and tools
import Form, FSForm, ListBox, MatrixBox, SelectionTool, ZGDChart, PDFTemplate,\ import Form, FSForm, ZGDChart, PDFTemplate, Report, PDFForm
Report, PDFForm, ParallelListField import PlanningBox, ListBox, MatrixBox
import PlanningBox import RelationField, ImageField, MultiRelationField, ParallelListField
import RelationField, ImageField, MultiRelationField import SelectionTool, PreferenceTool
from Products.Formulator.FieldRegistry import FieldRegistry from Products.Formulator.FieldRegistry import FieldRegistry
from Products.Formulator import StandardFields, HelperFields from Products.Formulator import StandardFields, HelperFields
from Products.CMFCore.utils import registerIcon from Products.CMFCore.utils import registerIcon
object_classes = ( Form.ERP5Form, FSForm.ERP5FSForm, PDFTemplate.PDFTemplate, Report.ERP5Report, PDFForm.PDFForm)
portal_tools = ( SelectionTool.SelectionTool, )
content_classes = () object_classes = ( Form.ERP5Form, FSForm.ERP5FSForm, PDFTemplate.PDFTemplate,
Report.ERP5Report, PDFForm.PDFForm)
portal_tools = ( SelectionTool.SelectionTool, PreferenceTool.PreferenceTool )
content_classes = ( )
content_constructors = () content_constructors = ()
# Import patch # Import patch
...@@ -159,4 +161,8 @@ def initialize( context ): ...@@ -159,4 +161,8 @@ def initialize( context ):
'www/PDF.png', globals()) 'www/PDF.png', globals())
## Initialize security ##
ModuleSecurityInfo('Products.ERP5Form.Report').declarePublic('ReportSection',) ModuleSecurityInfo('Products.ERP5Form.Report').declarePublic('ReportSection',)
import Selection
allow_class(Selection)
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<dtml-var "manage_form_title(this(), _,
form_title='Edit Preferences',
help_product='ERP5Form',
)">
<p class="form-help">
This page allows you to set the priority for preferences.<br/>
Lowest priority is <em>Site</em> preferences, then <em>Users Group</em> and the
higher priority will be <em>User</em> preference.
</p>
<form action="." method="POST">
<table cellspacing="0" cellpadding="2" border="1">
<tr>
<th> Preference Name </th>
<th> Preference Owner </th>
<th> Preference Priority </th>
</tr>
<dtml-in objectValues>
<tr>
<td> <dtml-var title_or_id> </td>
<td> <dtml-var getOwner> </td>
<td>
<select name='preference_priority_&dtml-id;:int'>
<option value="1"
<dtml-if expr="getObject().getPriority() == 1">
selected="selected"
</dtml-if>
> Site </option>
<option value="2"
<dtml-if expr="getObject().getPriority() == 2">
selected="selected"
</dtml-if>
> Users Group </option>
<option value="3"
<dtml-if expr="getObject().getPriority() not in (1, 2)">
selected="selected"
</dtml-if>
> User </option>
</select>
</td>
</tr>
</dtml-in>
</table>
<input type='submit'
value='Set User Groups Preference Parameters'
name="manage_updateUserGroupsPreferences:method">
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<h3> <code>portal_preferences</code> Tool </h3>
<p> This tool add the ability to manage user preferences in ERP5.
</p>
<dtml-var manage_page_footer>
##############################################################################
#
# ZopeTestCase
#
# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
#
# This version of framework.py will use the SOFTWARE_HOME
# environment variable to locate Zope and the Testing package.
#
# If the tests are run in an INSTANCE_HOME installation of Zope,
# Products.__path__ and sys.path with be adjusted to include the
# instance's Products and lib/python directories respectively.
#
# If you explicitly set INSTANCE_HOME prior to running the tests,
# auto-detection is disabled and the specified path will be used
# instead.
#
# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
# will be adjusted to use it.
#
# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup
# is assumed, and you can attach to a running ZEO server (via the
# instance's custom_zodb.py).
#
##############################################################################
#
# The following code should be at the top of every test module:
#
# import os, sys
# if __name__ == '__main__':
# execfile(os.path.join(sys.path[0], 'framework.py'))
#
# ...and the following at the bottom:
#
# if __name__ == '__main__':
# framework()
#
##############################################################################
__version__ = '0.2.3'
# Save start state
#
__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
if __SOFTWARE_HOME.endswith(os.sep):
__SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
if __INSTANCE_HOME.endswith(os.sep):
__INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
# Find and import the Testing package
#
if not sys.modules.has_key('Testing'):
p0 = sys.path[0]
if p0 and __name__ == '__main__':
os.chdir(p0)
p0 = ''
s = __SOFTWARE_HOME
p = d = s and s or os.getcwd()
while d:
if os.path.isdir(os.path.join(p, 'Testing')):
zope_home = os.path.dirname(os.path.dirname(p))
sys.path[:1] = [p0, p, zope_home]
break
p, d = s and ('','') or os.path.split(p)
else:
print 'Unable to locate Testing package.',
print 'You might need to set SOFTWARE_HOME.'
sys.exit(1)
import Testing, unittest
execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
# Include ZopeTestCase support
#
if 1: # Create a new scope
p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
if not os.path.isdir(p):
print 'Unable to locate ZopeTestCase package.',
print 'You might need to install ZopeTestCase.'
sys.exit(1)
ztc_common = 'ztc_common.py'
ztc_common_global = os.path.join(p, ztc_common)
f = 0
if os.path.exists(ztc_common_global):
execfile(ztc_common_global)
f = 1
if os.path.exists(ztc_common):
execfile(ztc_common)
f = 1
if not f:
print 'Unable to locate %s.' % ztc_common
sys.exit(1)
# Debug
#
print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
sys.stdout.flush()
export INSTANCE_HOME=/home/$USER/zope
export SOFTWARE_HOME=/usr/lib/zope/lib/python/
export COPY_OF_INSTANCE_HOME=$INSTANCE_HOME
export COPY_OF_SOFTWARE_HOME=$SOFTWARE_HOME
dir="`dirname $0`"
if test -n "$dir"; then
cd $dir
fi
python runalltests.py
#
# Runs all tests in the current directory
#
# Execute like:
# python runalltests.py
#
# Alternatively use the testrunner:
# python /path/to/Zope/utilities/testrunner.py -qa
#
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
import unittest
TestRunner = unittest.TextTestRunner
suite = unittest.TestSuite()
tests = os.listdir(os.curdir)
tests = [n[:-3] for n in tests if n.startswith('test') and n.endswith('.py')]
for test in tests:
m = __import__(test)
if hasattr(m, 'test_suite'):
suite.addTest(m.test_suite())
if __name__ == '__main__':
TestRunner().run(suite)
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment