[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):
user_id = super(res_users, self).create(cr, uid, data, context=context)
data_obj = self.pool.get('ir.model.data')
try:
data_id = data_obj._get_id(cr, uid, 'crm', 'ir_ui_view_sc_calendar0')
view_id = data_obj.browse(cr, uid, data_id, context=context).res_id
self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = {
'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'))
# add shortcut unless 'noshortcut' is True in context
if not(context and context.get('noshortcut', False)):
data_obj = self.pool.get('ir.model.data')
try:
data_id = data_obj._get_id(cr, uid, 'crm', 'ir_ui_view_sc_calendar0')
view_id = data_obj.browse(cr, uid, data_id, context=context).res_id
self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = {
'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
res_users()

View File

@ -241,16 +241,19 @@ class res_users(osv.osv):
def create(self, cr, uid, data, context=None):
user_id = super(res_users, self).create(cr, uid, data, context=context)
data_obj = self.pool.get('ir.model.data')
try:
data_id = data_obj._get_id(cr, uid, 'hr', 'ir_ui_view_sc_employee')
view_id = data_obj.browse(cr, uid, data_id, context=context).res_id
self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = {
'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'))
# add shortcut unless 'noshortcut' is True in context
if not(context and context.get('noshortcut', False)):
data_obj = self.pool.get('ir.model.data')
try:
data_id = data_obj._get_id(cr, uid, 'hr', 'ir_ui_view_sc_employee')
view_id = data_obj.browse(cr, uid, data_id, context=context).res_id
self.pool.get('ir.ui.view_sc').copy(cr, uid, view_id, default = {
'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
res_users()

View File

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

View File

@ -19,14 +19,13 @@
#
##############################################################################
{
"name" : "Portal",
"version" : "0.3",
"depends" : ["base", "share"],
"author" : "OpenERP SA",
"category": 'Tools',
"description": """
'name' : "Portal",
'version' : "1.0",
'depends' : ["base", "share"],
'author' : "OpenERP SA",
'category': 'Tools',
'description': """
This module defines 'portals' to customize the access to your OpenERP database
for external users.
@ -37,12 +36,14 @@ users, etc). That feature is very handy when used in combination with the
module 'share'.
""",
'website': 'http://www.openerp.com',
'data': ['security/portal_security.xml',
'security/ir.model.access.csv',
'portal_view.xml',
'wizard_view.xml',
'wizard/share_wizard_view.xml',
],
'data': [
'security/portal_security.xml',
'security/ir.model.access.csv',
'portal_view.xml',
'res_user_view.xml',
'wizard/portal_wizard_view.xml',
'wizard/share_wizard_view.xml',
],
'installable': True,
'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 tools.safe_eval import safe_eval
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'
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
if context is None:
context = {}
# if the current user belongs to a portal, we have to
# rewrite any search on the top menus to be under the
# portal's root menu:
# if the user belongs to a portal, we have to rewrite any search on the
# top menus to be under the portal's parent menu
if not context.get('ir.ui.menu.full_list') and uid != 1 and \
args and len(args) == 1 and \
len(args[0]) == 3 and \
(args[0][0] == 'parent_id' \
and args[0][1] == '=' \
and args[0][2] == False):
Portals = self.pool.get('res.portal')
portal_id = Portals.search(cr, uid, [('group_id.users', 'in', uid)])
if portal_id:
assert len(portal_id) == 1, "Users may only belong to one portal at a time!"
portal_data = Portals.read(cr, uid, portal_id[0], ['parent_menu_id'])
menu_id_pair = portal_data.get('parent_menu_id') # (ID, Name)
if menu_id_pair:
args = [('parent_id', '=', menu_id_pair[0])]
ids = super(portal_menu, self).search(cr, uid, args, offset=0,
limit=None, order=order, context=context, count=False)
return len(ids) if count else ids
portal_menu()
args == [('parent_id', '=', False)]:
portal_obj = self.pool.get('res.portal')
portal_ids = portal_obj.search(cr, uid, [('users', 'in', uid)])
if portal_ids:
if len(portal_ids) > 1:
log = logging.getLogger('ir.ui.menu')
log.warning('User %s belongs to several portals', str(uid))
p = portal_obj.browse(cr, uid, portal_ids[0])
# if the portal overrides the menu, use its domain
if p.menu_action_id:
args = safe_eval(p.menu_action_id.domain)
return super(portal_menu, self).search(cr, uid, args, offset=offset,
limit=limit, order=order, context=context, count=count)
portal_menu()

View File

@ -22,116 +22,83 @@
from osv import osv, fields
from tools.translate import _
class portal(osv.osv):
"""
A portal is a group of users with specific menu, widgets, and typically
restricted access rights.
"""
_name = 'res.portal'
_description = 'Portal'
_rec_name = 'group_id'
_inherits = {'res.groups': 'group_id'}
_columns = {
'group_id': fields.many2one('res.groups', required=True,
string='Portal Group',
help=_('This group defines the users associated to this portal')),
'user_ids': fields.related('group_id', 'users',
type='many2many', relation='res.users', store=False,
string='Portal Users'),
'menu_action_id': fields.many2one('ir.actions.actions', readonly=True,
'group_id': fields.many2one('res.groups', required=True, ondelete='cascade',
string='Group',
help='The group extended by this portal'),
'other_group_ids': fields.many2many('res.groups',
'portal_group_rel', 'portal_id', 'group_id',
string='Other User Groups',
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',
help=_("What replaces the standard menu for the portal's users")),
'parent_menu_id': fields.many2one('ir.ui.menu',
help="If set, replaces the standard menu for the portal's users"),
'parent_menu_id': fields.many2one('ir.ui.menu', ondelete='restrict',
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',
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):
""" override copy(): group_id and menu_action_id must be different """
# copy the former group_id
groups_obj = self.pool.get('res.groups')
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 copy(self, cr, uid, id, values, context=None):
""" override copy(): menu_action_id must be different """
values['menu_action_id'] = None
return super(portal, self).copy(cr, uid, id, values, context)
def create(self, cr, uid, values, context=None):
""" extend create() to assign the portal group and menu to users """
# first create the 'menu_action_id'
assert not values.get('menu_action_id')
values['menu_action_id'] = self._create_menu_action(cr, uid, values, context)
""" extend create() to assign the portal menu to users """
if context is None:
context = {}
if 'user_ids' in values:
# set menu action of users
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
# create portal (admin should not be included)
context['noadmin'] = True
portal_id = super(portal, self).create(cr, uid, values, context)
# assign widgets to users
if 'user_ids' in values:
self._assign_widgets_to_users(cr, uid, [portal_id], context)
# assign menu action and widgets to users
if values.get('users') or values.get('other_group_ids') or values.get('menu_action_id'):
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
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):
""" extend write() to reflect menu and groups changes on users """
""" extend write() to reflect changes on users """
# first apply portal changes
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
if 'menu_action_id' in values:
user_values = {'menu_id': values['menu_action_id']}
user_ids = [u.id for p in portals for u in p.user_ids if u.id != 1]
self.pool.get('res.users').write(cr, uid, user_ids, user_values, context)
# assign menu action and widgets to users
if values.get('users') or values.get('other_group_ids') or values.get('menu_action_id'):
self._assign_menu_and_groups(cr, uid, ids, context)
if values.get('users') or values.get('widget_ids'):
self._assign_widgets(cr, uid, ids, context)
# if parent_menu_id has changed, apply the change on menu_action_id
if 'parent_menu_id' in values:
act_window_obj = self.pool.get('ir.actions.act_window')
action_ids = [p.menu_action_id.id for p in portals]
action_values = {'domain': [('parent_id', '=', values['parent_menu_id'])]}
act_window_obj.write(cr, uid, action_ids, action_values, context)
# assign portal widgets to users, if widgets or users changed
if ('user_ids' in values) or ('widget_ids' in values):
self._assign_widgets_to_users(cr, uid, ids, context)
portals = self.browse(cr, uid, ids, context)
action_ids = [p.menu_action_id.id for p in portals if p.menu_action_id]
if action_ids:
action_values = {'domain': [('parent_id', '=', values['parent_menu_id'])]}
act_window_obj.write(cr, uid, action_ids, action_values, context)
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):
""" create a parent menu for the given portals """
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):
# create a menuitem under 'portal.portal_menu'
menu_values = {
'name': p.group_id.name + ' Menu',
'name': _('%s Menu') % p.name,
'parent_id': menu_root,
'groups_id': [(6, 0, [p.group_id.id])],
}
@ -150,28 +117,30 @@ class portal(osv.osv):
return True
def _assign_widgets_to_users(self, cr, uid, ids, context=None):
""" assign portal widgets to users for the given portal ids """
def _assign_menu_and_groups(self, cr, uid, ids, context=None):
""" 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')
portals = self.browse(cr, uid, ids, context)
for p in portals:
for p in self.browse(cr, uid, ids, context):
for w in p.widget_ids:
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
values['user_id'] = u.id
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):
""" return the resource id associated to the given xml_id """
data_obj = self.pool.get('ir.model.data')
@ -182,21 +151,55 @@ portal()
class users(osv.osv):
_name = 'res.users'
_inherit = 'res.users'
class portal_override_menu(osv.osv):
"""
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):
""" override default value of menu_id for portal users """
defs = super(users, self).default_get(cr, uid, fields, context)
# the value of 'menu_id' is passed in context by the portal form view
if ('menu_id' in context) and ('menu_id' in fields):
defs['menu_id'] = context['menu_id']
return defs
def _get_override_menu(self, cr, uid, ids, field_name, arg, context=None):
assert field_name == 'override_menu'
result = {}
for p in self.browse(cr, uid, ids, context):
result[p.id] = bool(p.menu_action_id)
return result
def _set_override_menu(self, cr, uid, id, field_name, field_value, arg, context=None):
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'
_columns = {
'sequence': fields.integer('Sequence'),
'portal_id': fields.many2one('res.portal', select=1,
'portal_id': fields.many2one('res.portal', select=1, ondelete='cascade',
string='Portal'),
'widget_id': fields.many2one('res.widget', required=True, ondelete='cascade',
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>
<data>
<!-- 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 -->
<record id="portal_list_action" model="ir.actions.act_window">
@ -10,83 +11,65 @@
<field name="res_model">res.portal</field>
<field name="view_type">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">
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
is assigned to the portal's users. Groups can be added to or removed from the
portal's users.
portal group). A portal menu, widgets and specific groups may be assigned to
the portal's users.
</field>
</record>
<menuitem name="Portals" id="portal_list_menu"
parent="portal_menu" sequence="1" action="portal_list_action"/>
<!-- portal list view -->
<record id="portal_list" model="ir.ui.view">
<!-- portal tree view -->
<record id="portal_list_view" model="ir.ui.view">
<field name="name">Portal List</field>
<field name="model">res.portal</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Portal List">
<field name="group_id"/>
<field name="user_ids"/>
<tree string="Portals">
<field name="name" string="Portal Name"/>
</tree>
</field>
</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 -->
<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="model">res.portal</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_groups_form"/>
<field name="arch" type="xml">
<form string="Portal Form">
<field name="group_id" on_change="onchange_group(group_id)"/>
<notebook>
<page string="Users">
<field name="user_ids" nolabel="1" colspan="3"
context="{'menu_id': menu_action_id}"/>
<group name="user_panel" colspan="1"/>
<!-- wizards insert buttons inside the group 'user_panel' -->
</page>
<page string="Menu &amp; Widgets">
<group colspan="2" col="2">
<separator string="Portal Menu" colspan="2"/>
<group colspan="2" col="2">
<field name="menu_action_id"/>
<field name="parent_menu_id"
context="{'ir.ui.menu.full_list': True}"/>
</group>
<button name="do_create_menu" type="object"
string="Create Parent Menu"/>
</group>
<group colspan="2" col="2">
<separator string="Portal Widgets" colspan="2"/>
<field name="widget_ids" nolabel="1" rowspan="7">
<tree string="Widgets" editable="bottom">
<field name="sequence"/>
<field name="widget_id"/>
</tree>
</field>
</group>
</page>
</notebook>
</form>
<page string="Users" position="before">
<page string="Portal">
<group colspan="2" col="2">
<separator string="Website" colspan="2"/>
<field name="url" widget="url"/>
</group>
<group colspan="2" col="2">
<separator string="Portal Menu" colspan="2"/>
<field name="override_menu"/>
<field name="parent_menu_id"
context="{'ir.ui.menu.full_list': True}"/>
<label colspan="1"/>
<button name="do_create_menu" type="object"
string="Create Parent Menu"/>
</group>
<separator string="Other Groups assigned to Users" colspan="2"/>
<separator string="Widgets assigned to Users" colspan="2"/>
<!-- load group_id in order to exclude it from other_group_ids -->
<field name="group_id" invisible="1"/>
<field name="other_group_ids" nolabel="1" colspan="2"
domain="[('id', '!=', group_id)]"/>
<field name="widget_ids" nolabel="1" colspan="2">
<tree string="Widgets" editable="bottom">
<field name="sequence"/>
<field name="widget_id"/>
</tree>
</field>
</page>
</page>
</field>
</record>
</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"
"access_portal_manager","access.portal.manager","model_res_portal","group_portal_manager",1,1,1,1
"access_portal_all","access.portal.all","model_res_portal",,1,0,0,0
"access_portal_widget_all","access.portal.widget.all","model_res_portal_widget",,1,0,0,0
"access_portal_widget_manager","access.portal.widget.manager","model_res_portal_widget",group_portal_manager,1,1,1,1
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_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_manager,access.portal.manager,model_res_portal,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">
<record id="group_portal_manager" model="res.groups">
<field name="name">Portal / Manager</field>
<field name="comment">
Members of this groups have access to the portal definitions, and can easily manage the users, access right and menus of portal users.
Members of this group who are also members of the Sharing/User group get additional options in the sharing wizard:
- they may select a list of existing users to share with, without having to give a list of emails
- they may choose to share with a Portal group instead of sharing with users, effectively extending the Portal content
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>
<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>
</record>
<record id="group_portal_officer" model="res.groups">
<field name="name">Portal / Officer</field>
<field name="comment">Portal officers can create new portal users with the portal wizard.</field>
</record>
</data>
</openerp>
</openerp>

View File

@ -19,5 +19,6 @@
#
##############################################################################
import portal_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)
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>