[MERGE] trunk-portal-rco

bzr revid: rco@openerp.com-20110705125010-9pc0robqw66dtwuu
This commit is contained in:
Raphael Collet 2011-07-05 14:50:10 +02:00
commit 7c7e977b23
19 changed files with 1386 additions and 367 deletions

View File

@ -138,16 +138,19 @@ class res_users(osv.osv):
def create(self, cr, uid, data, context=None): def create(self, cr, uid, data, context=None):
user_id = super(res_users, self).create(cr, uid, data, context=context) user_id = super(res_users, self).create(cr, uid, data, context=context)
data_obj = self.pool.get('ir.model.data')
try: # add shortcut unless 'noshortcut' is True in context
data_id = data_obj._get_id(cr, uid, 'crm', 'ir_ui_view_sc_calendar0') if not(context and context.get('noshortcut', False)):
view_id = data_obj.browse(cr, uid, data_id, context=context).res_id data_obj = self.pool.get('ir.model.data')
self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = { try:
'user_id': user_id}, context=context) data_id = data_obj._get_id(cr, uid, 'crm', 'ir_ui_view_sc_calendar0')
except: view_id = data_obj.browse(cr, uid, data_id, context=context).res_id
# Tolerate a missing shortcut. See product/product.py for similar code. self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = {
logging.getLogger('orm').debug('Skipped meetings shortcut for user "%s"', data.get('name','<new')) 'user_id': user_id}, context=context)
except:
# Tolerate a missing shortcut. See product/product.py for similar code.
logging.getLogger('orm').debug('Skipped meetings shortcut for user "%s"', data.get('name','<new'))
return user_id return user_id
res_users() res_users()

View File

@ -241,16 +241,19 @@ class res_users(osv.osv):
def create(self, cr, uid, data, context=None): def create(self, cr, uid, data, context=None):
user_id = super(res_users, self).create(cr, uid, data, context=context) user_id = super(res_users, self).create(cr, uid, data, context=context)
data_obj = self.pool.get('ir.model.data')
try: # add shortcut unless 'noshortcut' is True in context
data_id = data_obj._get_id(cr, uid, 'hr', 'ir_ui_view_sc_employee') if not(context and context.get('noshortcut', False)):
view_id = data_obj.browse(cr, uid, data_id, context=context).res_id data_obj = self.pool.get('ir.model.data')
self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = { try:
'user_id': user_id}, context=context) data_id = data_obj._get_id(cr, uid, 'hr', 'ir_ui_view_sc_employee')
except: view_id = data_obj.browse(cr, uid, data_id, context=context).res_id
# Tolerate a missing shortcut. See product/product.py for similar code. self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = {
logging.getLogger('orm').debug('Skipped meetings shortcut for user "%s"', data.get('name','<new')) 'user_id': user_id}, context=context)
except:
# Tolerate a missing shortcut. See product/product.py for similar code.
logging.getLogger('orm').debug('Skipped meetings shortcut for user "%s"', data.get('name','<new'))
return user_id return user_id
res_users() res_users()

View File

@ -21,4 +21,6 @@
import portal import portal
import wizard import wizard
import ir_ui_menu import res_user
import ir_ui_menu

View File

@ -19,14 +19,13 @@
# #
############################################################################## ##############################################################################
{ {
"name" : "Portal", 'name' : "Portal",
"version" : "0.3", 'version' : "1.0",
"depends" : ["base", "share"], 'depends' : ["base", "share"],
"author" : "OpenERP SA", 'author' : "OpenERP SA",
"category": 'Tools', 'category': 'Tools',
"description": """ 'description': """
This module defines 'portals' to customize the access to your OpenERP database This module defines 'portals' to customize the access to your OpenERP database
for external users. for external users.
@ -37,12 +36,14 @@ users, etc). That feature is very handy when used in combination with the
module 'share'. module 'share'.
""", """,
'website': 'http://www.openerp.com', 'website': 'http://www.openerp.com',
'data': ['security/portal_security.xml', 'data': [
'security/ir.model.access.csv', 'security/portal_security.xml',
'portal_view.xml', 'security/ir.model.access.csv',
'wizard_view.xml', 'portal_view.xml',
'wizard/share_wizard_view.xml', 'res_user_view.xml',
], 'wizard/portal_wizard_view.xml',
'wizard/share_wizard_view.xml',
],
'installable': True, 'installable': True,
'certificate' : '', 'certificate' : '',
} }

393
addons/portal/i18n/en_US.po Normal file
View File

@ -0,0 +1,393 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * portal
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.1-dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-07-04 14:16+0000\n"
"PO-Revision-Date: 2011-07-04 14:16+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: portal
#: code:addons/portal/wizard/share_wizard.py:55
#, python-format
msgid "Please select at least one user to share with"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/share_wizard.py:59
#, python-format
msgid "Please select at least one group to share with"
msgstr ""
#. module: portal
#: field:res.portal,group_id:0
msgid "Group"
msgstr ""
#. module: portal
#: help:res.portal,other_group_ids:0
msgid "Those groups are assigned to the portal's users"
msgstr ""
#. module: portal
#: view:share.wizard:0
#: field:share.wizard,group_ids:0
msgid "Existing groups"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal_wizard_user
msgid "Portal User Config"
msgstr ""
#. module: portal
#: view:res.portal.wizard.user:0
msgid "Portal User"
msgstr ""
#. module: portal
#: help:res.portal,override_menu:0
msgid "Enable this option to override the Menu Action of portal users"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,user_email:0
msgid "E-mail"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Other Groups assigned to Users"
msgstr ""
#. module: portal
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
#. module: portal
#: view:res.portal:0
#: field:res.portal,widget_ids:0
msgid "Widgets"
msgstr ""
#. module: portal
#: model:ir.module.module,description:portal.module_meta_information
msgid "\n"
"This module defines 'portals' to customize the access to your OpenERP database\n"
"for external users.\n"
"\n"
"A portal defines customized user menu and access rights for a group of users\n"
"(the ones associated to that portal). It also associates user groups to the\n"
"portal users (adding a group in the portal automatically adds it to the portal\n"
"users, etc). That feature is very handy when used in combination with the\n"
"module 'share'.\n"
" "
msgstr ""
#. module: portal
#: view:share.wizard:0
msgid "Who do you want to share with?"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
msgid "Send Invitations"
msgstr ""
#. module: portal
#: help:res.portal,url:0
msgid "The url where portal users can connect to the server"
msgstr ""
#. module: portal
#: field:res.portal.widget,widget_id:0
msgid "Widget"
msgstr ""
#. module: portal
#: help:res.portal.wizard,message:0
msgid "This text is included in the welcome email sent to the users"
msgstr ""
#. module: portal
#: help:res.portal,menu_action_id:0
msgid "If set, replaces the standard menu for the portal's users"
msgstr ""
#. module: portal
#: field:res.portal,parent_menu_id:0
msgid "Parent Menu"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Portal Name"
msgstr ""
#. module: portal
#: view:res.portal.wizard.user:0
msgid "Portal Users"
msgstr ""
#. module: portal
#: field:res.portal,override_menu:0
msgid "Override Menu Action of Users"
msgstr ""
#. module: portal
#: field:res.portal,menu_action_id:0
msgid "Menu Action"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,name:0
msgid "User Name"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal_widget
msgid "Portal Widgets"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal
#: model:ir.module.module,shortdesc:portal.module_meta_information
#: view:res.portal:0
#: field:res.portal.widget,portal_id:0
#: field:res.portal.wizard,portal_id:0
msgid "Portal"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:35
#, python-format
msgid "Your OpenERP account at %(company)s"
msgstr ""
#. module: portal
#: code:addons/portal/portal.py:110
#: code:addons/portal/portal.py:184
#, python-format
msgid "%s Menu"
msgstr ""
#. module: portal
#: help:res.portal.wizard,portal_id:0
msgid "The portal in which new users must be added"
msgstr ""
#. module: portal
#: help:res.portal,widget_ids:0
msgid "Widgets assigned to portal users"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:163
#, python-format
msgid "(missing url)"
msgstr ""
#. module: portal
#: view:share.wizard:0
#: field:share.wizard,user_ids:0
msgid "Existing users"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,wizard_id:0
msgid "Wizard"
msgstr ""
#. module: portal
#: help:res.portal.wizard.user,user_email:0
msgid "Will be used as user login. Also necessary to send the account information to new users"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,lang:0
msgid "Language"
msgstr ""
#. module: portal
#: field:res.portal,url:0
msgid "URL"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Widgets assigned to Users"
msgstr ""
#. module: portal
#: help:res.portal.wizard.user,lang:0
msgid "The language for the user's user interface"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
msgid "Cancel"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Website"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Create Parent Menu"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
msgid "The following text will be included in the welcome email sent to users."
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:135
#, python-format
msgid "Email required"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_users
msgid "res.users"
msgstr ""
#. module: portal
#: constraint:res.portal.wizard.user:0
msgid "Invalid email address"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:136
#, python-format
msgid "You must have an email address in your User Preferences to send emails."
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_ir_ui_menu
msgid "ir.ui.menu"
msgstr ""
#. module: portal
#: help:res.portal,group_id:0
msgid "The group extended by this portal"
msgstr ""
#. module: portal
#: view:res.portal:0
#: view:res.portal.wizard:0
#: field:res.portal.wizard,user_ids:0
msgid "Users"
msgstr ""
#. module: portal
#: field:res.portal,other_group_ids:0
msgid "Other User Groups"
msgstr ""
#. module: portal
#: model:ir.actions.act_window,name:portal.portal_list_action
#: model:ir.ui.menu,name:portal.portal_list_menu
#: model:ir.ui.menu,name:portal.portal_menu
#: view:res.portal:0
msgid "Portals"
msgstr ""
#. module: portal
#: help:res.portal,parent_menu_id:0
msgid "The menu action opens the submenus of this menu item"
msgstr ""
#. module: portal
#: field:res.portal.widget,sequence:0
msgid "Sequence"
msgstr ""
#. module: portal
#: field:res.users,partner_id:0
msgid "Related Partner"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Portal Menu"
msgstr ""
#. module: portal
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
#: field:res.portal.wizard,message:0
msgid "Invitation message"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:36
#, python-format
msgid "Dear %(name)s,\n"
"\n"
"You have been created an OpenERP account at %(url)s.\n"
"\n"
"Your login account data is:\n"
"Database: %(db)s\n"
"User: %(login)s\n"
"Password: %(password)s\n"
"\n"
"%(message)s\n"
"\n"
"--\n"
"OpenERP - Open Source Business Applications\n"
"http://www.openerp.com\n"
""
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal_wizard
msgid "Portal Wizard"
msgstr ""
#. module: portal
#: help:res.portal.wizard.user,name:0
msgid "The user's real name"
msgstr ""
#. module: portal
#: model:ir.actions.act_window,name:portal.address_wizard_action
#: model:ir.actions.act_window,name:portal.partner_wizard_action
#: view:res.portal.wizard:0
msgid "Add Portal Access"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,partner_id:0
msgid "Partner"
msgstr ""
#. module: portal
#: model:ir.actions.act_window,help:portal.portal_list_action
msgid "\n"
"A portal helps defining specific views and rules for a group of users (the\n"
"portal group). A portal menu, widgets and specific groups may be assigned to\n"
"the portal's users.\n"
" "
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_share_wizard
msgid "Share Wizard"
msgstr ""

View File

@ -0,0 +1,393 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * portal
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.1-dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-07-04 14:16+0000\n"
"PO-Revision-Date: 2011-07-04 14:16+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: portal
#: code:addons/portal/wizard/share_wizard.py:55
#, python-format
msgid "Please select at least one user to share with"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/share_wizard.py:59
#, python-format
msgid "Please select at least one group to share with"
msgstr ""
#. module: portal
#: field:res.portal,group_id:0
msgid "Group"
msgstr ""
#. module: portal
#: help:res.portal,other_group_ids:0
msgid "Those groups are assigned to the portal's users"
msgstr ""
#. module: portal
#: view:share.wizard:0
#: field:share.wizard,group_ids:0
msgid "Existing groups"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal_wizard_user
msgid "Portal User Config"
msgstr ""
#. module: portal
#: view:res.portal.wizard.user:0
msgid "Portal User"
msgstr ""
#. module: portal
#: help:res.portal,override_menu:0
msgid "Enable this option to override the Menu Action of portal users"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,user_email:0
msgid "E-mail"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Other Groups assigned to Users"
msgstr ""
#. module: portal
#: constraint:res.users:0
msgid "The chosen company is not in the allowed companies for this user"
msgstr ""
#. module: portal
#: view:res.portal:0
#: field:res.portal,widget_ids:0
msgid "Widgets"
msgstr ""
#. module: portal
#: model:ir.module.module,description:portal.module_meta_information
msgid "\n"
"This module defines 'portals' to customize the access to your OpenERP database\n"
"for external users.\n"
"\n"
"A portal defines customized user menu and access rights for a group of users\n"
"(the ones associated to that portal). It also associates user groups to the\n"
"portal users (adding a group in the portal automatically adds it to the portal\n"
"users, etc). That feature is very handy when used in combination with the\n"
"module 'share'.\n"
" "
msgstr ""
#. module: portal
#: view:share.wizard:0
msgid "Who do you want to share with?"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
msgid "Send Invitations"
msgstr ""
#. module: portal
#: help:res.portal,url:0
msgid "The url where portal users can connect to the server"
msgstr ""
#. module: portal
#: field:res.portal.widget,widget_id:0
msgid "Widget"
msgstr ""
#. module: portal
#: help:res.portal.wizard,message:0
msgid "This text is included in the welcome email sent to the users"
msgstr ""
#. module: portal
#: help:res.portal,menu_action_id:0
msgid "If set, replaces the standard menu for the portal's users"
msgstr ""
#. module: portal
#: field:res.portal,parent_menu_id:0
msgid "Parent Menu"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Portal Name"
msgstr ""
#. module: portal
#: view:res.portal.wizard.user:0
msgid "Portal Users"
msgstr ""
#. module: portal
#: field:res.portal,override_menu:0
msgid "Override Menu Action of Users"
msgstr ""
#. module: portal
#: field:res.portal,menu_action_id:0
msgid "Menu Action"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,name:0
msgid "User Name"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal_widget
msgid "Portal Widgets"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal
#: model:ir.module.module,shortdesc:portal.module_meta_information
#: view:res.portal:0
#: field:res.portal.widget,portal_id:0
#: field:res.portal.wizard,portal_id:0
msgid "Portal"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:35
#, python-format
msgid "Your OpenERP account at %(company)s"
msgstr ""
#. module: portal
#: code:addons/portal/portal.py:110
#: code:addons/portal/portal.py:184
#, python-format
msgid "%s Menu"
msgstr ""
#. module: portal
#: help:res.portal.wizard,portal_id:0
msgid "The portal in which new users must be added"
msgstr ""
#. module: portal
#: help:res.portal,widget_ids:0
msgid "Widgets assigned to portal users"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:163
#, python-format
msgid "(missing url)"
msgstr ""
#. module: portal
#: view:share.wizard:0
#: field:share.wizard,user_ids:0
msgid "Existing users"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,wizard_id:0
msgid "Wizard"
msgstr ""
#. module: portal
#: help:res.portal.wizard.user,user_email:0
msgid "Will be used as user login. Also necessary to send the account information to new users"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,lang:0
msgid "Language"
msgstr ""
#. module: portal
#: field:res.portal,url:0
msgid "URL"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Widgets assigned to Users"
msgstr ""
#. module: portal
#: help:res.portal.wizard.user,lang:0
msgid "The language for the user's user interface"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
msgid "Cancel"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Website"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Create Parent Menu"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
msgid "The following text will be included in the welcome email sent to users."
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:135
#, python-format
msgid "Email required"
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_users
msgid "res.users"
msgstr ""
#. module: portal
#: constraint:res.portal.wizard.user:0
msgid "Invalid email address"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:136
#, python-format
msgid "You must have an email address in your User Preferences to send emails."
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_ir_ui_menu
msgid "ir.ui.menu"
msgstr ""
#. module: portal
#: help:res.portal,group_id:0
msgid "The group extended by this portal"
msgstr ""
#. module: portal
#: view:res.portal:0
#: view:res.portal.wizard:0
#: field:res.portal.wizard,user_ids:0
msgid "Users"
msgstr ""
#. module: portal
#: field:res.portal,other_group_ids:0
msgid "Other User Groups"
msgstr ""
#. module: portal
#: model:ir.actions.act_window,name:portal.portal_list_action
#: model:ir.ui.menu,name:portal.portal_list_menu
#: model:ir.ui.menu,name:portal.portal_menu
#: view:res.portal:0
msgid "Portals"
msgstr ""
#. module: portal
#: help:res.portal,parent_menu_id:0
msgid "The menu action opens the submenus of this menu item"
msgstr ""
#. module: portal
#: field:res.portal.widget,sequence:0
msgid "Sequence"
msgstr ""
#. module: portal
#: field:res.users,partner_id:0
msgid "Related Partner"
msgstr ""
#. module: portal
#: view:res.portal:0
msgid "Portal Menu"
msgstr ""
#. module: portal
#: sql_constraint:res.users:0
msgid "You can not have two users with the same login !"
msgstr ""
#. module: portal
#: view:res.portal.wizard:0
#: field:res.portal.wizard,message:0
msgid "Invitation message"
msgstr ""
#. module: portal
#: code:addons/portal/wizard/portal_wizard.py:36
#, python-format
msgid "Dear %(name)s,\n"
"\n"
"You have been created an OpenERP account at %(url)s.\n"
"\n"
"Your login account data is:\n"
"Database: %(db)s\n"
"User: %(login)s\n"
"Password: %(password)s\n"
"\n"
"%(message)s\n"
"\n"
"--\n"
"OpenERP - Open Source Business Applications\n"
"http://www.openerp.com\n"
""
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_res_portal_wizard
msgid "Portal Wizard"
msgstr ""
#. module: portal
#: help:res.portal.wizard.user,name:0
msgid "The user's real name"
msgstr ""
#. module: portal
#: model:ir.actions.act_window,name:portal.address_wizard_action
#: model:ir.actions.act_window,name:portal.partner_wizard_action
#: view:res.portal.wizard:0
msgid "Add Portal Access"
msgstr ""
#. module: portal
#: field:res.portal.wizard.user,partner_id:0
msgid "Partner"
msgstr ""
#. module: portal
#: model:ir.actions.act_window,help:portal.portal_list_action
msgid "\n"
"A portal helps defining specific views and rules for a group of users (the\n"
"portal group). A portal menu, widgets and specific groups may be assigned to\n"
"the portal's users.\n"
" "
msgstr ""
#. module: portal
#: model:ir.model,name:portal.model_share_wizard
msgid "Share Wizard"
msgstr ""

View File

@ -19,35 +19,40 @@
# #
############################################################################## ##############################################################################
import logging
from osv import osv, fields from osv import osv, fields
from tools.safe_eval import safe_eval
class portal_menu(osv.osv): class portal_menu(osv.osv):
"""Inherited menu class to customized the login search for menus, """
as web client 6.0 does not support the menu action properly yet""" Fix menu class to customize the login search for menus,
as web client 6.0 does not support the menu action properly yet
"""
_name = 'ir.ui.menu'
_inherit = 'ir.ui.menu' _inherit = 'ir.ui.menu'
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if context is None: if context is None:
context = {} context = {}
# if the current user belongs to a portal, we have to
# rewrite any search on the top menus to be under the # if the user belongs to a portal, we have to rewrite any search on the
# portal's root menu: # top menus to be under the portal's parent menu
if not context.get('ir.ui.menu.full_list') and uid != 1 and \ if not context.get('ir.ui.menu.full_list') and uid != 1 and \
args and len(args) == 1 and \ args == [('parent_id', '=', False)]:
len(args[0]) == 3 and \ portal_obj = self.pool.get('res.portal')
(args[0][0] == 'parent_id' \ portal_ids = portal_obj.search(cr, uid, [('users', 'in', uid)])
and args[0][1] == '=' \ if portal_ids:
and args[0][2] == False): if len(portal_ids) > 1:
Portals = self.pool.get('res.portal') log = logging.getLogger('ir.ui.menu')
portal_id = Portals.search(cr, uid, [('group_id.users', 'in', uid)]) log.warning('User %s belongs to several portals', str(uid))
if portal_id: p = portal_obj.browse(cr, uid, portal_ids[0])
assert len(portal_id) == 1, "Users may only belong to one portal at a time!" # if the portal overrides the menu, use its domain
portal_data = Portals.read(cr, uid, portal_id[0], ['parent_menu_id']) if p.menu_action_id:
menu_id_pair = portal_data.get('parent_menu_id') # (ID, Name) args = safe_eval(p.menu_action_id.domain)
if menu_id_pair:
args = [('parent_id', '=', menu_id_pair[0])] return super(portal_menu, self).search(cr, uid, args, offset=offset,
ids = super(portal_menu, self).search(cr, uid, args, offset=0, limit=limit, order=order, context=context, count=count)
limit=None, order=order, context=context, count=False)
return len(ids) if count else ids portal_menu()
portal_menu()

View File

@ -22,116 +22,83 @@
from osv import osv, fields from osv import osv, fields
from tools.translate import _ from tools.translate import _
class portal(osv.osv): class portal(osv.osv):
"""
A portal is a group of users with specific menu, widgets, and typically
restricted access rights.
"""
_name = 'res.portal' _name = 'res.portal'
_description = 'Portal' _description = 'Portal'
_rec_name = 'group_id' _inherits = {'res.groups': 'group_id'}
_columns = { _columns = {
'group_id': fields.many2one('res.groups', required=True, 'group_id': fields.many2one('res.groups', required=True, ondelete='cascade',
string='Portal Group', string='Group',
help=_('This group defines the users associated to this portal')), help='The group extended by this portal'),
'user_ids': fields.related('group_id', 'users', 'other_group_ids': fields.many2many('res.groups',
type='many2many', relation='res.users', store=False, 'portal_group_rel', 'portal_id', 'group_id',
string='Portal Users'), string='Other User Groups',
'menu_action_id': fields.many2one('ir.actions.actions', readonly=True, help="Those groups are assigned to the portal's users"),
'url': fields.char('URL', size=64,
help="The url where portal users can connect to the server"),
'menu_action_id': fields.many2one('ir.actions.act_window', readonly=True,
# ISSUE: 'ondelete' constraints do not seem effective on this field...
string='Menu Action', string='Menu Action',
help=_("What replaces the standard menu for the portal's users")), help="If set, replaces the standard menu for the portal's users"),
'parent_menu_id': fields.many2one('ir.ui.menu', 'parent_menu_id': fields.many2one('ir.ui.menu', ondelete='restrict',
string='Parent Menu', string='Parent Menu',
help=_('The menu action opens the submenus of this menu item')), help='The menu action opens the submenus of this menu item'),
'widget_ids': fields.one2many('res.portal.widget', 'portal_id', 'widget_ids': fields.one2many('res.portal.widget', 'portal_id',
string='Widgets', string='Widgets',
help=_('Widgets assigned to portal users')), help='Widgets assigned to portal users'),
} }
_sql_constraints = [
('unique_group', 'UNIQUE(group_id)', _('Portals must have distinct groups.'))
]
def copy(self, cr, uid, id, default={}, context=None): def copy(self, cr, uid, id, values, context=None):
""" override copy(): group_id and menu_action_id must be different """ """ override copy(): menu_action_id must be different """
# copy the former group_id values['menu_action_id'] = None
groups_obj = self.pool.get('res.groups') return super(portal, self).copy(cr, uid, id, values, context)
group_id = self.browse(cr, uid, id, context).group_id.id
default['group_id'] = groups_obj.copy(cr, uid, group_id, {}, context)
default['menu_action_id'] = None
return super(portal, self).copy(cr, uid, id, default, context)
def create(self, cr, uid, values, context=None): def create(self, cr, uid, values, context=None):
""" extend create() to assign the portal group and menu to users """ """ extend create() to assign the portal menu to users """
# first create the 'menu_action_id' if context is None:
assert not values.get('menu_action_id') context = {}
values['menu_action_id'] = self._create_menu_action(cr, uid, values, context)
if 'user_ids' in values: # create portal (admin should not be included)
# set menu action of users context['noadmin'] = True
user_values = {'menu_id': values['menu_action_id']}
# values['user_ids'] should match [(6, 0, IDs)]
for id in get_many2many(values['user_ids']):
values['user_ids'].append((1, id, user_values))
# create portal
portal_id = super(portal, self).create(cr, uid, values, context) portal_id = super(portal, self).create(cr, uid, values, context)
# assign widgets to users # assign menu action and widgets to users
if 'user_ids' in values: if values.get('users') or values.get('other_group_ids') or values.get('menu_action_id'):
self._assign_widgets_to_users(cr, uid, [portal_id], context) self._assign_menu_and_groups(cr, uid, [portal_id], context)
if values.get('users') or values.get('widget_ids'):
self._assign_widgets(cr, uid, [portal_id], context)
return portal_id return portal_id
def name_get(self, cr, uid, ids, context=None):
portals = self.browse(cr, uid, ids, context)
return [(p.id, p.group_id.name) for p in portals]
def name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=100):
# first search for group names that match
groups_obj = self.pool.get('res.groups')
group_names = groups_obj.name_search(cr, uid, name, args, operator, context, limit)
# then search for portals that match the groups found so far
domain = [('group_id', 'in', [gn[0] for gn in group_names])]
ids = self.search(cr, uid, domain, context=context)
return self.name_get(cr, uid, ids, context)
def write(self, cr, uid, ids, values, context=None): def write(self, cr, uid, ids, values, context=None):
""" extend write() to reflect menu and groups changes on users """ """ extend write() to reflect changes on users """
# first apply portal changes # first apply portal changes
super(portal, self).write(cr, uid, ids, values, context) super(portal, self).write(cr, uid, ids, values, context)
portals = self.browse(cr, uid, ids, context)
# if 'menu_action_id' has changed, set menu_id on users # assign menu action and widgets to users
if 'menu_action_id' in values: if values.get('users') or values.get('other_group_ids') or values.get('menu_action_id'):
user_values = {'menu_id': values['menu_action_id']} self._assign_menu_and_groups(cr, uid, ids, context)
user_ids = [u.id for p in portals for u in p.user_ids if u.id != 1] if values.get('users') or values.get('widget_ids'):
self.pool.get('res.users').write(cr, uid, user_ids, user_values, context) self._assign_widgets(cr, uid, ids, context)
# if parent_menu_id has changed, apply the change on menu_action_id # if parent_menu_id has changed, apply the change on menu_action_id
if 'parent_menu_id' in values: if 'parent_menu_id' in values:
act_window_obj = self.pool.get('ir.actions.act_window') act_window_obj = self.pool.get('ir.actions.act_window')
action_ids = [p.menu_action_id.id for p in portals] portals = self.browse(cr, uid, ids, context)
action_values = {'domain': [('parent_id', '=', values['parent_menu_id'])]} action_ids = [p.menu_action_id.id for p in portals if p.menu_action_id]
act_window_obj.write(cr, uid, action_ids, action_values, context) if action_ids:
action_values = {'domain': [('parent_id', '=', values['parent_menu_id'])]}
# assign portal widgets to users, if widgets or users changed act_window_obj.write(cr, uid, action_ids, action_values, context)
if ('user_ids' in values) or ('widget_ids' in values):
self._assign_widgets_to_users(cr, uid, ids, context)
return True return True
def _create_menu_action(self, cr, uid, values, context=None):
# create a menu action that opens the menu items below parent_menu_id
groups_obj = self.pool.get('res.groups')
group_name = groups_obj.browse(cr, uid, values['group_id'], context).name
actions_obj = self.pool.get('ir.actions.act_window')
action_values = {
'name': group_name + ' Menu',
'type': 'ir.actions.act_window',
'usage': 'menu',
'res_model': 'ir.ui.menu',
'view_type': 'tree',
'view_id': self._res_xml_id(cr, uid, 'base', 'view_menu'),
'domain': [('parent_id', '=', values.get('parent_menu_id', False))],
}
return actions_obj.create(cr, uid, action_values, context)
def do_create_menu(self, cr, uid, ids, context=None): def do_create_menu(self, cr, uid, ids, context=None):
""" create a parent menu for the given portals """ """ create a parent menu for the given portals """
menu_obj = self.pool.get('ir.ui.menu') menu_obj = self.pool.get('ir.ui.menu')
@ -140,7 +107,7 @@ class portal(osv.osv):
for p in self.browse(cr, uid, ids, context): for p in self.browse(cr, uid, ids, context):
# create a menuitem under 'portal.portal_menu' # create a menuitem under 'portal.portal_menu'
menu_values = { menu_values = {
'name': p.group_id.name + ' Menu', 'name': _('%s Menu') % p.name,
'parent_id': menu_root, 'parent_id': menu_root,
'groups_id': [(6, 0, [p.group_id.id])], 'groups_id': [(6, 0, [p.group_id.id])],
} }
@ -150,28 +117,30 @@ class portal(osv.osv):
return True return True
def _assign_widgets_to_users(self, cr, uid, ids, context=None): def _assign_menu_and_groups(self, cr, uid, ids, context=None):
""" assign portal widgets to users for the given portal ids """ """ assign portal menu and other groups to users of portals (ids) """
user_obj = self.pool.get('res.users')
for p in self.browse(cr, uid, ids, context):
# user groups = portal group + other groups
group_ids = [p.group_id.id] + [g.id for g in p.other_group_ids]
user_values = {'groups_id': [(6, 0, group_ids)]}
# user menu action = portal menu action if set in portal
if p.menu_action_id:
user_values['menu_id'] = p.menu_action_id.id
user_ids = [u.id for u in p.users if u.id != 1]
user_obj.write(cr, uid, user_ids, user_values, context)
def _assign_widgets(self, cr, uid, ids, context=None):
""" assign portal widgets to users of portals (ids) """
widget_user_obj = self.pool.get('res.widget.user') widget_user_obj = self.pool.get('res.widget.user')
portals = self.browse(cr, uid, ids, context) for p in self.browse(cr, uid, ids, context):
for p in portals:
for w in p.widget_ids: for w in p.widget_ids:
values = {'sequence': w.sequence, 'widget_id': w.widget_id.id} values = {'sequence': w.sequence, 'widget_id': w.widget_id.id}
for u in p.user_ids: for u in p.users:
if u.id == 1: continue if u.id == 1: continue
values['user_id'] = u.id values['user_id'] = u.id
widget_user_obj.create(cr, uid, values, context) widget_user_obj.create(cr, uid, values, context)
def onchange_group(self, cr, uid, ids, group_id, context=None):
""" update the users list when the group changes """
user_ids = False
if group_id:
group = self.pool.get('res.groups').browse(cr, uid, group_id, context)
user_ids = [u.id for u in group.users]
return {
'value': {'user_ids': user_ids}
}
def _res_xml_id(self, cr, uid, module, xml_id): def _res_xml_id(self, cr, uid, module, xml_id):
""" return the resource id associated to the given xml_id """ """ return the resource id associated to the given xml_id """
data_obj = self.pool.get('ir.model.data') data_obj = self.pool.get('ir.model.data')
@ -182,21 +151,55 @@ portal()
class users(osv.osv): class portal_override_menu(osv.osv):
_name = 'res.users' """
_inherit = 'res.users' extend res.portal with a boolean field 'Override Users Menu', that
triggers the creation or removal of menu_action_id
"""
_name = 'res.portal'
_inherit = 'res.portal'
def default_get(self, cr, uid, fields, context=None): def _get_override_menu(self, cr, uid, ids, field_name, arg, context=None):
""" override default value of menu_id for portal users """ assert field_name == 'override_menu'
defs = super(users, self).default_get(cr, uid, fields, context) result = {}
for p in self.browse(cr, uid, ids, context):
# the value of 'menu_id' is passed in context by the portal form view result[p.id] = bool(p.menu_action_id)
if ('menu_id' in context) and ('menu_id' in fields): return result
defs['menu_id'] = context['menu_id']
def _set_override_menu(self, cr, uid, id, field_name, field_value, arg, context=None):
return defs assert field_name == 'override_menu'
if field_value:
self.create_menu_action(cr, uid, id, context)
else:
self.write(cr, uid, [id], {'menu_action_id': False}, context)
def create_menu_action(self, cr, uid, id, context=None):
""" create, if necessary, a menu action that opens the menu items below
parent_menu_id """
p = self.browse(cr, uid, id, context)
if not p.menu_action_id:
actions_obj = self.pool.get('ir.actions.act_window')
parent_id = p.parent_menu_id.id if p.parent_menu_id else False
action_values = {
'name': _('%s Menu') % p.name,
'type': 'ir.actions.act_window',
'usage': 'menu',
'res_model': 'ir.ui.menu',
'view_type': 'tree',
'view_id': self._res_xml_id(cr, uid, 'base', 'view_menu'),
'domain': [('parent_id', '=', parent_id)],
}
action_id = actions_obj.create(cr, uid, action_values, context)
self.write(cr, uid, [id], {'menu_action_id': action_id}, context)
_columns = {
'override_menu': fields.function(
_get_override_menu, fnct_inv=_set_override_menu,
type='boolean', string='Override Menu Action of Users',
help='Enable this option to override the Menu Action of portal users'),
}
users() portal_override_menu()
@ -210,7 +213,7 @@ class portal_widget(osv.osv):
_order = 'sequence' _order = 'sequence'
_columns = { _columns = {
'sequence': fields.integer('Sequence'), 'sequence': fields.integer('Sequence'),
'portal_id': fields.many2one('res.portal', select=1, 'portal_id': fields.many2one('res.portal', select=1, ondelete='cascade',
string='Portal'), string='Portal'),
'widget_id': fields.many2one('res.widget', required=True, ondelete='cascade', 'widget_id': fields.many2one('res.widget', required=True, ondelete='cascade',
string='Widget'), string='Widget'),
@ -230,17 +233,3 @@ portal_widget()
# utils
def get_browse_id(obj):
""" return the id of a browse() object, or None """
return (obj and obj.id or None)
def get_browse_ids(objs):
""" return the ids of a list of browse() objects """
return map(get_browse_id, objs)
def get_many2many(arg):
""" get the list of ids from a many2many 'values' field """
assert len(arg) == 1 and arg[0][0] == 6 # arg = [(6, _, IDs)]
return arg[0][2]

View File

@ -2,7 +2,8 @@
<openerp> <openerp>
<data> <data>
<!-- menu Administration/Portals --> <!-- menu Administration/Portals -->
<menuitem name="Portals" id="portal_menu" parent="base.menu_administration" groups="group_portal_manager"/> <menuitem name="Portals" id="portal_menu" parent="base.menu_administration"
groups="group_portal_manager"/>
<!-- menu Administration/Portals/Portals --> <!-- menu Administration/Portals/Portals -->
<record id="portal_list_action" model="ir.actions.act_window"> <record id="portal_list_action" model="ir.actions.act_window">
@ -10,83 +11,65 @@
<field name="res_model">res.portal</field> <field name="res_model">res.portal</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<!-- a context is necessary to get the right portal form view -->
<field name="context">{'form_view_ref': 'portal.portal_form_view'}</field>
<field name="help"> <field name="help">
A portal helps defining specific views and rules for a group of users (the A portal helps defining specific views and rules for a group of users (the
portal group). A portal is associated with a menu; when changed, the portal menu portal group). A portal menu, widgets and specific groups may be assigned to
is assigned to the portal's users. Groups can be added to or removed from the the portal's users.
portal's users.
</field> </field>
</record> </record>
<menuitem name="Portals" id="portal_list_menu" <menuitem name="Portals" id="portal_list_menu"
parent="portal_menu" sequence="1" action="portal_list_action"/> parent="portal_menu" sequence="1" action="portal_list_action"/>
<!-- portal tree view -->
<!-- portal list view --> <record id="portal_list_view" model="ir.ui.view">
<record id="portal_list" model="ir.ui.view">
<field name="name">Portal List</field> <field name="name">Portal List</field>
<field name="model">res.portal</field> <field name="model">res.portal</field>
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Portal List"> <tree string="Portals">
<field name="group_id"/> <field name="name" string="Portal Name"/>
<field name="user_ids"/>
</tree> </tree>
</field> </field>
</record> </record>
<!-- portal search view -->
<record id="portal_search" model="ir.ui.view">
<field name="name">Portal Search</field>
<field name="model">res.portal</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Portal Search">
<field name="group_id"/>
<field name="user_ids"/>
<field name="menu_action_id"/>
<field name="parent_menu_id"/>
</search>
</field>
</record>
<!-- portal form view --> <!-- portal form view -->
<record id="portal_form" model="ir.ui.view"> <record id="portal_form_view" model="ir.ui.view">
<field name="name">Portal Form</field> <field name="name">Portal Form</field>
<field name="model">res.portal</field> <field name="model">res.portal</field>
<field name="type">form</field> <field name="type">form</field>
<field name="inherit_id" ref="base.view_groups_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Portal Form"> <page string="Users" position="before">
<field name="group_id" on_change="onchange_group(group_id)"/> <page string="Portal">
<notebook> <group colspan="2" col="2">
<page string="Users"> <separator string="Website" colspan="2"/>
<field name="user_ids" nolabel="1" colspan="3" <field name="url" widget="url"/>
context="{'menu_id': menu_action_id}"/> </group>
<group name="user_panel" colspan="1"/> <group colspan="2" col="2">
<!-- wizards insert buttons inside the group 'user_panel' --> <separator string="Portal Menu" colspan="2"/>
</page> <field name="override_menu"/>
<page string="Menu &amp; Widgets"> <field name="parent_menu_id"
<group colspan="2" col="2"> context="{'ir.ui.menu.full_list': True}"/>
<separator string="Portal Menu" colspan="2"/> <label colspan="1"/>
<group colspan="2" col="2"> <button name="do_create_menu" type="object"
<field name="menu_action_id"/> string="Create Parent Menu"/>
<field name="parent_menu_id" </group>
context="{'ir.ui.menu.full_list': True}"/> <separator string="Other Groups assigned to Users" colspan="2"/>
</group> <separator string="Widgets assigned to Users" colspan="2"/>
<button name="do_create_menu" type="object" <!-- load group_id in order to exclude it from other_group_ids -->
string="Create Parent Menu"/> <field name="group_id" invisible="1"/>
</group> <field name="other_group_ids" nolabel="1" colspan="2"
<group colspan="2" col="2"> domain="[('id', '!=', group_id)]"/>
<separator string="Portal Widgets" colspan="2"/> <field name="widget_ids" nolabel="1" colspan="2">
<field name="widget_ids" nolabel="1" rowspan="7"> <tree string="Widgets" editable="bottom">
<tree string="Widgets" editable="bottom"> <field name="sequence"/>
<field name="sequence"/> <field name="widget_id"/>
<field name="widget_id"/> </tree>
</tree> </field>
</field> </page>
</group> </page>
</page>
</notebook>
</form>
</field> </field>
</record> </record>
</data> </data>

34
addons/portal/res_user.py Normal file
View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
class res_users(osv.osv):
_inherit = 'res.users'
_columns = {
'partner_id': fields.many2one('res.partner',
string='Related Partner'),
}
res_users()

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- add partner field in user form -->
<record id="view_users_form" model="ir.ui.view">
<field name="name">res.portal.users.form</field>
<field name="model">res.users</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<field name="address_id" position="before">
<field name="partner_id"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@ -1,5 +1,5 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
"access_portal_manager","access.portal.manager","model_res_portal","group_portal_manager",1,1,1,1 access_all,access.portal.all,model_res_portal,,1,0,0,0
"access_portal_all","access.portal.all","model_res_portal",,1,0,0,0 access_widget_all,access.portal.widget.all,model_res_portal_widget,,1,0,0,0
"access_portal_widget_all","access.portal.widget.all","model_res_portal_widget",,1,0,0,0 access_manager,access.portal.manager,model_res_portal,group_portal_manager,1,1,1,1
"access_portal_widget_manager","access.portal.widget.manager","model_res_portal_widget",group_portal_manager,1,1,1,1 access_widget_manager,access.portal.widget.manager,model_res_portal_widget,group_portal_manager,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_portal_manager access_all access.portal.manager access.portal.all model_res_portal group_portal_manager 1 1 0 1 0 1 0
3 access_portal_all access_widget_all access.portal.all access.portal.widget.all model_res_portal model_res_portal_widget 1 0 0 0
4 access_portal_widget_all access_manager access.portal.widget.all access.portal.manager model_res_portal_widget model_res_portal group_portal_manager 1 0 1 0 1 0 1
5 access_portal_widget_manager access_widget_manager access.portal.widget.manager model_res_portal_widget group_portal_manager 1 1 1 1

View File

@ -3,14 +3,11 @@
<data noupdate="1"> <data noupdate="1">
<record id="group_portal_manager" model="res.groups"> <record id="group_portal_manager" model="res.groups">
<field name="name">Portal / Manager</field> <field name="name">Portal / Manager</field>
<field name="comment"> <field name="comment">Portal managers have access to the portal definitions, and can easily configure the users, access rights and menus of portal users.</field>
Members of this groups have access to the portal definitions, and can easily manage the users, access right and menus of portal users. </record>
Members of this group who are also members of the Sharing/User group get additional options in the sharing wizard: <record id="group_portal_officer" model="res.groups">
- they may select a list of existing users to share with, without having to give a list of emails <field name="name">Portal / Officer</field>
- they may choose to share with a Portal group instead of sharing with users, effectively extending the Portal content <field name="comment">Portal officers can create new portal users with the portal wizard.</field>
These features are useful for setting up Portals, but this could result in an alteration of the system's security policy.
Therefore this should be granted only to trustworthy users who know the security policy very well.
This group must not be deleted.</field>
</record> </record>
</data> </data>
</openerp> </openerp>

View File

@ -19,5 +19,6 @@
# #
############################################################################## ##############################################################################
import portal_wizard
import share_wizard import share_wizard
import groups_wizard

View File

@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
from tools.translate import _
class groups_wizard(osv.osv_memory):
_name = 'res.portal.groups'
_description = 'Portal Groups Wizard'
_columns = {
'portal_id': fields.many2one('res.portal', required=True, readonly=True,
string='Portal'),
'add_group_ids': fields.many2many('res.groups',
'portal_groups_add', 'portal_groups_id', 'group_ids',
string='Add Groups'),
'remove_group_ids': fields.many2many('res.groups',
'portal_groups_remove', 'portal_groups_id', 'group_ids',
string='Remove Groups'),
}
_defaults = {
'portal_id': (lambda self,cr,uid,context: context and context.get('active_id'))
}
def do_apply(self, cr, uid, ids, context=None, *args):
assert len(ids) == 1
wizard = self.browse(cr, uid, ids[0], context)
# select all portal users except admin
user_ids = [u.id for u in wizard.portal_id.user_ids if u.id != 1]
# apply group adds and removals to portal users
add_gids = [(4, g.id) for g in wizard.add_group_ids]
rem_gids = [(3, g.id) for g in wizard.remove_group_ids]
user_values = {'groups_id': add_gids + rem_gids}
self.pool.get('res.users').write(cr, uid, user_ids, user_values, context)
# return an empty dictionary to close the wizard window
return {}
groups_wizard()

View File

@ -0,0 +1,226 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2011 OpenERP S.A (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
import random
from osv import osv, fields
from tools.misc import email_re, email_send
from tools.translate import _
from base.res.res_user import _lang_get
# welcome email sent to new portal users (note that calling tools.translate._
# has no effect except exporting those strings for translation)
WELCOME_EMAIL_SUBJECT = _("Your OpenERP account at %(company)s")
WELCOME_EMAIL_BODY = _("""Dear %(name)s,
You have been created an OpenERP account at %(url)s.
Your login account data is:
Database: %(db)s
User: %(login)s
Password: %(password)s
%(message)s
--
OpenERP - Open Source Business Applications
http://www.openerp.com
""")
ROOT_UID = 1
# character sets for passwords, excluding 0, O, o, 1, I, l
_PASSU = 'ABCDEFGHIJKLMNPQRSTUVWXYZ'
_PASSL = 'abcdefghijkmnpqrstuvwxyz'
_PASSD = '23456789'
def random_password():
# get 3 uppercase letters, 3 lowercase letters, 2 digits, and shuffle them
chars = map(random.choice, [_PASSU] * 3 + [_PASSL] * 3 + [_PASSD] * 2)
random.shuffle(chars)
return ''.join(chars)
def extract_email(user_email):
""" extract the email address from a user-friendly email address """
m = email_re.search(user_email or "")
return m and m.group(0) or ""
class wizard(osv.osv_memory):
"""
A wizard to create portal users from instances of either 'res.partner'
or 'res.partner.address'. The purpose is to provide an OpenERP database
access to customers or suppliers.
"""
_name = 'res.portal.wizard'
_description = 'Portal Wizard'
_columns = {
'portal_id': fields.many2one('res.portal', required=True,
string='Portal',
help="The portal in which new users must be added"),
'user_ids': fields.one2many('res.portal.wizard.user', 'wizard_id',
string='Users'),
'message': fields.text(string='Invitation message',
help="This text is included in the welcome email sent to the users"),
}
def _default_user_ids(self, cr, uid, context):
""" determine default user_ids from the active records """
def create_user_from_address(address):
return { # a user config based on a contact (address)
'name': address.name,
'user_email': extract_email(address.email),
'lang': address.partner_id and address.partner_id.lang or 'en_US',
'partner_id': address.partner_id and address.partner_id.id,
}
user_ids = []
if context.get('active_model') == 'res.partner.address':
address_obj = self.pool.get('res.partner.address')
address_ids = context.get('active_ids', [])
addresses = address_obj.browse(cr, uid, address_ids, context)
user_ids = map(create_user_from_address, addresses)
elif context.get('active_model') == 'res.partner':
partner_obj = self.pool.get('res.partner')
partner_ids = context.get('active_ids', [])
partners = partner_obj.browse(cr, uid, partner_ids, context)
for p in partners:
# add one user per contact, or one user if no contact
if p.address:
user_ids.extend(map(create_user_from_address, p.address))
else:
user_ids.append({'lang': p.lang or 'en_US', 'partner_id': p.id})
return user_ids
_defaults = {
'user_ids': _default_user_ids
}
def action_create(self, cr, uid, ids, context=None):
""" create new users in portal(s), and notify them by email """
# we copy the context to change the language for translating emails
context0 = context or {}
context0['noshortcut'] = True # prevent shortcut creation
context = context0.copy()
user_obj = self.pool.get('res.users')
user = user_obj.browse(cr, ROOT_UID, uid, context0)
if not user.user_email:
raise osv.except_osv(_('Email required'),
_('You must have an email address in your User Preferences'
' to send emails.'))
portal_obj = self.pool.get('res.portal')
for wiz in self.browse(cr, uid, ids, context):
# determine existing users
login_cond = [('login', 'in', [u.user_email for u in wiz.user_ids])]
user_ids = user_obj.search(cr, ROOT_UID, login_cond)
users = user_obj.browse(cr, ROOT_UID, user_ids)
logins = [u.login for u in users]
# create new users in portal (skip existing logins)
new_users_data = [ {
'name': u.name,
'login': u.user_email,
'password': random_password(),
'user_email': u.user_email,
'context_lang': u.lang,
'partner_id': u.partner_id and u.partner_id.id,
} for u in wiz.user_ids if u.user_email not in logins ]
portal_obj.write(cr, ROOT_UID, [wiz.portal_id.id],
{'users': [(0, 0, data) for data in new_users_data]}, context0)
# send email to all users (translated in their language)
data = {
'company': user.company_id.name,
'message': wiz.message or "",
'url': wiz.portal_id.url or _("(missing url)"),
'db': cr.dbname,
}
dest_uids = user_obj.search(cr, ROOT_UID, login_cond)
dest_users = user_obj.browse(cr, ROOT_UID, user_ids)
for dest_user in dest_users:
context['lang'] = dest_user.context_lang
data['login'] = dest_user.login
data['password'] = dest_user.password
data['name'] = dest_user.name
email_from = user.user_email
email_to = dest_user.user_email
subject = _(WELCOME_EMAIL_SUBJECT) % data
body = _(WELCOME_EMAIL_BODY) % data
res = email_send(email_from, [email_to], subject, body)
if not res:
logging.getLogger('res.portal.wizard').warning(
'Failed to send email from %s to %s', email_from, email_to)
return {'type': 'ir.actions.act_window_close'}
wizard()
class wizard_user(osv.osv_memory):
"""
A model to configure users in the portal wizard.
"""
_name = 'res.portal.wizard.user'
_description = 'Portal User Config'
_columns = {
'wizard_id': fields.many2one('res.portal.wizard', required=True,
string='Wizard'),
'name': fields.char(size=64, required=True,
string='User Name',
help="The user's real name"),
'user_email': fields.char(size=64, required=True,
string='E-mail',
help="Will be used as user login. "
"Also necessary to send the account information to new users"),
'lang': fields.selection(_lang_get, required=True,
string='Language',
help="The language for the user's user interface"),
'partner_id': fields.many2one('res.partner',
string='Partner'),
}
def _check_email(self, cr, uid, ids):
""" check syntax of email address """
for wuser in self.browse(cr, uid, ids):
if not email_re.match(wuser.user_email): return False
return True
_constraints = [
(_check_email, 'Invalid email address', ['email']),
]
wizard_user()

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- wizard action on res.partner -->
<act_window id="partner_wizard_action"
name="Add Portal Access"
src_model="res.partner"
res_model="res.portal.wizard"
view_type="form" view_mode="form"
key2="client_action_multi" target="new"
groups="group_portal_officer"/>
<!-- wizard action on res.partner.address -->
<act_window id="address_wizard_action"
name="Add Portal Access"
src_model="res.partner.address"
res_model="res.portal.wizard"
view_type="form" view_mode="form"
key2="client_action_multi" target="new"
groups="group_portal_officer"/>
<!-- wizard view -->
<record id="wizard_view" model="ir.ui.view">
<field name="name">Add Portal Access</field>
<field name="model">res.portal.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Add Portal Access">
<field name="portal_id" widget="selection"/>
<newline/>
<notebook colspan="4">
<page string="Users">
<field name="user_ids" nolabel="1" colspan="4"/>
</page>
<page string="Invitation message">
<label string="The following text will be included in the welcome email sent to users."/>
<field name="message" nolabel="1" colspan="4"/>
</page>
</notebook>
<label colspan="2"/>
<button string="Cancel" special="cancel" icon="gtk-cancel"/>
<button string="Send Invitations"
name="action_create" type="object" icon="gtk-ok"/>
</form>
</field>
</record>
<!-- wizard user list view -->
<record id="wizard_user_tree_view" model="ir.ui.view">
<field name="name">Portal Users</field>
<field name="model">res.portal.wizard.user</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<!-- the attribute 'editable' is set below to make the elements
editable in the web client 6.0 -->
<tree string="Portal Users" editable="bottom">
<field name="name"/>
<field name="user_email"/>
<field name="partner_id"/>
</tree>
</field>
</record>
<!-- wizard user form view -->
<record id="wizard_user_form_view" model="ir.ui.view">
<field name="name">Portal User</field>
<field name="model">res.portal.wizard.user</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Portal User">
<group colspan="2" col="2">
<field name="name"/>
<field name="user_email"/>
<field name="lang"/>
<field name="partner_id"/>
</group>
</form>
</field>
</record>
</data>
</openerp>

View File

@ -186,4 +186,5 @@ class share_wizard_portal(osv.osv_memory):
super(share_wizard_portal,self)._finish_result_lines(cr, uid, wizard_data, share_group_id, context=context) super(share_wizard_portal,self)._finish_result_lines(cr, uid, wizard_data, share_group_id, context=context)
self.copy_share_group_access_and_delete(cr, wizard_data, share_group_id, context=context) self.copy_share_group_access_and_delete(cr, wizard_data, share_group_id, context=context)
share_wizard_portal() share_wizard_portal()

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- groups wizard action -->
<record id="groups_wizard_action" model="ir.actions.act_window">
<field name="name">Add/Remove Groups</field>
<field name="res_model">res.portal.groups</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- groups wizard form -->
<record id="groups_wizard_form" model="ir.ui.view">
<field name="name">Portal Groups Wizard</field>
<field name="model">res.portal.groups</field>
<field name="type">form</field>
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<form string="Portal Groups Wizard">
<group colspan="4">
<field name="portal_id"/>
</group>
<separator string="Add Groups" colspan="2"/>
<separator string="Remove Groups" colspan="2"/>
<field name="add_group_ids" nolabel="1" colspan="2"/>
<field name="remove_group_ids" nolabel="1" colspan="2"/>
<separator colspan="4"/>
<label colspan="2"/>
<button special="cancel"
string="Cancel" icon="gtk-cancel"/>
<button name="do_apply" type="object"
string="Apply" icon="gtk-apply"/>
</form>
</field>
</record>
<!-- add a button in the portal form view -->
<record id="portal_form_with_groups_wizard" model="ir.ui.view">
<field name="name">Portal Form</field>
<field name="model">res.portal</field>
<field name="inherit_id" ref="portal_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='user_panel']" position="inside">
<button name="%(groups_wizard_action)d" type="action"
string="Add/Remove Groups"/>
</xpath>
</field>
</record>
</data>
</openerp>