[MERGE] [IMP] 'Social Aspects' Task
Purpose: - mail is now focused on messaging; partner document is now a classic document, without specific behavior; removed the concept of 'my followers' from mail; - hr adds social features to mail: employee profile is used to display internal messages; employees can follow other employees, comment and react on their profile messages; - display suggestion of Groups and Employees to follow in the Inbox, using a new widget. The purpose is to promote social interactions between employees and to improve the visibility of groups; mail: - add suggestions.Group widget that allows to display a list of suggested groups to follow; this widget is displayed in the Inbox; - display 'Partner profile of' or 'News from' when reading messages from a partner profile / employee profile in the Inbox; - 'Compose a new message or Write to my followers' is not present anymore when hr is not installed, because this social aspect comes with HR; - mail_thread: add a search function on message_is_follower; - mail_group: implement suggested groups behavior; - res_partner: removed specific code changing message_post with type='email' to a private discussion between author and destination partner; partner document behaves like a classic document; - res_users: add 'display_groups_suggestions' field that controls the display of suggested groups to follow; - res_users: writing on a res.users object is considered as a private discussion; when Hr is not installed, only aliases should be able to post on a user; hr_employee: - when creating an employee, post a message on its profile and push it to every employees of the same company; - add follow/unfollow and message and follower count on employee kanban view; - implement suggested employee behavior; - HR improves the basic Inbox by adding the 'Compose a new message or Write to my followers'; - allow to post on an employee profile when having read access right if the user that posts is an employee; HR: - add suggestions.Employee widget that allows to display a list of suggested employees to follow; this widget is displayed in the Inbox; - res_users: add 'display_employees_suggestions' field that controls the display of suggested employees to follow; - res_users: do not welcome new users anymore, welcome new employees instead - res_users: incoming emails are still considered as private messages (using aliases); however messages posted on user profile are redirected to the related employee profiles (used for 'Write to my followers') bzr revid: tde@openerp.com-20130612121258-j38do5opsot2ur7c
This commit is contained in:
commit
43d08b898f
|
@ -23,5 +23,6 @@ import hr_department
|
|||
import hr
|
||||
|
||||
import res_config
|
||||
import res_users
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -59,6 +59,8 @@ You can manage:
|
|||
'hr_installer.xml',
|
||||
'hr_data.xml',
|
||||
'res_config_view.xml',
|
||||
'mail_hr_view.xml',
|
||||
'res_users_view.xml',
|
||||
],
|
||||
'demo': ['hr_demo.xml'],
|
||||
'test': [
|
||||
|
@ -69,5 +71,7 @@ You can manage:
|
|||
'application': True,
|
||||
'auto_install': False,
|
||||
'css': [ 'static/src/css/hr.css' ],
|
||||
'js': [ 'static/src/js/suggestions.js' ],
|
||||
'qweb': [ 'static/src/xml/suggestions.xml' ],
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
107
addons/hr/hr.py
107
addons/hr/hr.py
|
@ -25,9 +25,11 @@ from openerp.modules.module import get_module_resource
|
|||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp import tools
|
||||
from openerp.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class hr_employee_category(osv.osv):
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
|
@ -150,6 +152,7 @@ class hr_job(osv.osv):
|
|||
class hr_employee(osv.osv):
|
||||
_name = "hr.employee"
|
||||
_description = "Employee"
|
||||
_order = 'name_related'
|
||||
_inherits = {'resource.resource': "resource_id"}
|
||||
_inherit = ['mail.thread']
|
||||
|
||||
|
@ -158,10 +161,10 @@ class hr_employee(osv.osv):
|
|||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
result[obj.id] = tools.image_get_resized_images(obj.image)
|
||||
return result
|
||||
|
||||
|
||||
def _set_image(self, cr, uid, id, name, value, args, context=None):
|
||||
return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
|
||||
|
||||
|
||||
_columns = {
|
||||
#we need a related field in order to be able to sort the employee by name
|
||||
'name_related': fields.related('resource_id', 'name', type='char', string='Name', readonly=True, store=True),
|
||||
|
@ -171,12 +174,12 @@ class hr_employee(osv.osv):
|
|||
'sinid': fields.char('SIN No', size=32, help="Social Insurance Number"),
|
||||
'identification_id': fields.char('Identification No', size=32),
|
||||
'otherid': fields.char('Other Id', size=64),
|
||||
'gender': fields.selection([('male', 'Male'),('female', 'Female')], 'Gender'),
|
||||
'gender': fields.selection([('male', 'Male'), ('female', 'Female')], 'Gender'),
|
||||
'marital': fields.selection([('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')], 'Marital Status'),
|
||||
'department_id':fields.many2one('hr.department', 'Department'),
|
||||
'department_id': fields.many2one('hr.department', 'Department'),
|
||||
'address_id': fields.many2one('res.partner', 'Working Address'),
|
||||
'address_home_id': fields.many2one('res.partner', 'Home Address'),
|
||||
'bank_account_id':fields.many2one('res.partner.bank', 'Bank Account Number', domain="[('partner_id','=',address_home_id)]", help="Employee bank salary account"),
|
||||
'bank_account_id': fields.many2one('res.partner.bank', 'Bank Account Number', domain="[('partner_id','=',address_home_id)]", help="Employee bank salary account"),
|
||||
'work_phone': fields.char('Work Phone', size=32, readonly=False),
|
||||
'mobile_phone': fields.char('Work Mobile', size=32, readonly=False),
|
||||
'work_email': fields.char('Work Email', size=240),
|
||||
|
@ -207,25 +210,42 @@ class hr_employee(osv.osv):
|
|||
help="Small-sized photo of the employee. It is automatically "\
|
||||
"resized as a 64x64px image, with aspect ratio preserved. "\
|
||||
"Use this field anywhere a small image is required."),
|
||||
'passport_id':fields.char('Passport No', size=64),
|
||||
'passport_id': fields.char('Passport No', size=64),
|
||||
'color': fields.integer('Color Index'),
|
||||
'city': fields.related('address_id', 'city', type='char', string='City'),
|
||||
'login': fields.related('user_id', 'login', type='char', string='Login', readonly=1),
|
||||
'last_login': fields.related('user_id', 'date', type='datetime', string='Latest Connection', readonly=1),
|
||||
}
|
||||
|
||||
_order='name_related'
|
||||
def _get_default_image(self, cr, uid, context=None):
|
||||
image_path = get_module_resource('hr', 'static/src/img', 'default_image.png')
|
||||
return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
|
||||
|
||||
defaults = {
|
||||
'active': 1,
|
||||
'image': _get_default_image,
|
||||
'color': 0,
|
||||
}
|
||||
|
||||
def create(self, cr, uid, data, context=None):
|
||||
employee_id = super(hr_employee, self).create(cr, uid, data, context=context)
|
||||
try:
|
||||
(model, mail_group_id) = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'mail', 'group_all_employees')
|
||||
employee = self.browse(cr, uid, employee_id, context=context)
|
||||
self.pool.get('mail.group').message_post(cr, uid, [mail_group_id],
|
||||
body=_('Welcome to %s! Please help him/her take the first steps with OpenERP!') % (employee.name),
|
||||
subtype='mail.mt_comment', context=context)
|
||||
except:
|
||||
pass # group deleted: do not push a message
|
||||
if context is None:
|
||||
context = {}
|
||||
create_ctx = dict(context, mail_create_nolog=True)
|
||||
employee_id = super(hr_employee, self).create(cr, uid, data, context=create_ctx)
|
||||
employee = self.browse(cr, uid, employee_id, context=context)
|
||||
if employee.user_id:
|
||||
# send a copy to every user of the company
|
||||
company_id = employee.user_id.partner_id.company_id.id
|
||||
partner_ids = self.pool.get('res.partner').search(cr, uid, [
|
||||
('company_id', '=', company_id),
|
||||
('user_ids', '!=', False)], context=context)
|
||||
else:
|
||||
partner_ids = []
|
||||
self.message_post(cr, uid, [employee_id],
|
||||
body=_('Welcome to %s! Please help him/her take the first steps with OpenERP!') % (employee.name),
|
||||
partner_ids=partner_ids,
|
||||
subtype='mail.mt_comment', context=context
|
||||
)
|
||||
return employee_id
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
|
@ -246,7 +266,7 @@ class hr_employee(osv.osv):
|
|||
company_id = self.pool.get('res.company').browse(cr, uid, company, context=context)
|
||||
address = self.pool.get('res.partner').address_get(cr, uid, [company_id.partner_id.id], ['default'])
|
||||
address_id = address and address['default'] or False
|
||||
return {'value': {'address_id' : address_id}}
|
||||
return {'value': {'address_id': address_id}}
|
||||
|
||||
def onchange_department_id(self, cr, uid, ids, department_id, context=None):
|
||||
value = {'parent_id': False}
|
||||
|
@ -259,17 +279,36 @@ class hr_employee(osv.osv):
|
|||
work_email = False
|
||||
if user_id:
|
||||
work_email = self.pool.get('res.users').browse(cr, uid, user_id, context=context).email
|
||||
return {'value': {'work_email' : work_email}}
|
||||
return {'value': {'work_email': work_email}}
|
||||
|
||||
def _get_default_image(self, cr, uid, context=None):
|
||||
image_path = get_module_resource('hr', 'static/src/img', 'default_image.png')
|
||||
return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64'))
|
||||
def action_follow(self, cr, uid, ids, context=None):
|
||||
""" Wrapper because message_subscribe_users take a user_ids=None
|
||||
that receive the context without the wrapper. """
|
||||
return self.message_subscribe_users(cr, uid, ids, context=context)
|
||||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'image': _get_default_image,
|
||||
'color': 0,
|
||||
}
|
||||
def action_unfollow(self, cr, uid, ids, context=None):
|
||||
""" Wrapper because message_unsubscribe_users take a user_ids=None
|
||||
that receive the context without the wrapper. """
|
||||
return self.message_unsubscribe_users(cr, uid, ids, context=context)
|
||||
|
||||
def get_suggested_thread(self, cr, uid, removed_suggested_threads=None, context=None):
|
||||
"""Show the suggestion of employees if display_employees_suggestions if the
|
||||
user perference allows it. """
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context)
|
||||
if not user.display_employees_suggestions:
|
||||
return []
|
||||
else:
|
||||
return super(hr_employee, self).get_suggested_thread(cr, uid, removed_suggested_threads, context)
|
||||
|
||||
def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=['user_id'], context=None):
|
||||
""" Overwrite of the original method to always follow user_id field,
|
||||
even when not track_visibility so that a user will follow it's employee
|
||||
"""
|
||||
user_field_lst = []
|
||||
for name, column_info in self._all_columns.items():
|
||||
if name in auto_follow_fields and name in updated_fields and column_info.column._obj == 'res.users':
|
||||
user_field_lst.append(name)
|
||||
return user_field_lst
|
||||
|
||||
def _check_recursion(self, cr, uid, ids, context=None):
|
||||
level = 100
|
||||
|
@ -285,6 +324,22 @@ class hr_employee(osv.osv):
|
|||
(_check_recursion, 'Error! You cannot create recursive hierarchy of Employee(s).', ['parent_id']),
|
||||
]
|
||||
|
||||
# ---------------------------------------------------
|
||||
# Mail gateway
|
||||
# ---------------------------------------------------
|
||||
|
||||
def check_mail_message_access(self, cr, uid, mids, operation, model_obj=None, context=None):
|
||||
""" mail.message document permission rule: can post a new message if can read
|
||||
because of portal document. """
|
||||
if not model_obj:
|
||||
model_obj = self
|
||||
employee_ids = model_obj.search(cr, uid, [('user_id', '=', uid)], context=context)
|
||||
if employee_ids and operation == 'create':
|
||||
model_obj.check_access_rights(cr, uid, 'read')
|
||||
model_obj.check_access_rule(cr, uid, mids, 'read', context=context)
|
||||
else:
|
||||
return super(hr_employee, self).check_mail_message_access(cr, uid, mids, operation, model_obj=model_obj, context=context)
|
||||
|
||||
|
||||
class hr_department(osv.osv):
|
||||
_description = "Department"
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
</h1>
|
||||
<label for="category_ids" class="oe_edit_only" groups="base.group_hr_user"/>
|
||||
<field name="category_ids" widget="many2many_tags" placeholder="e.g. Part Time" groups="base.group_hr_user"/>
|
||||
<label for="work_email" class="oe_edit_only"/>
|
||||
<field name="work_email" widget="email"/>
|
||||
<label for="work_phone" class="oe_edit_only"/>
|
||||
<field name="work_phone"/>
|
||||
</div>
|
||||
<div class="oe_right oe_button_box" name="button_box">
|
||||
<!-- Put here related buttons -->
|
||||
|
@ -36,8 +40,6 @@
|
|||
<group>
|
||||
<group string="Contact Information">
|
||||
<field name="address_id" on_change="onchange_address_id(address_id)" context="{'show_address': 1}" options='{"always_reload": True, "highlight_first_line": True}'/>
|
||||
<field name="work_email" widget="email"/>
|
||||
<field name="work_phone"/>
|
||||
<field name="mobile_phone"/>
|
||||
<field name="work_location"/>
|
||||
</group>
|
||||
|
@ -136,6 +138,9 @@
|
|||
<field name="arch" type="xml">
|
||||
<kanban>
|
||||
<field name="last_login"/>
|
||||
<field name="message_is_follower"/>
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="message_ids"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_employee_vignette">
|
||||
|
@ -154,10 +159,19 @@
|
|||
</li>
|
||||
<li t-if="record.job_id.raw_value"><field name="job_id"/></li>
|
||||
<li t-if="record.work_location.raw_value"><field name="work_location"/></li>
|
||||
<li t-if="record.work_phone.raw_value">Tel: <field name="work_phone"/></li>
|
||||
<li t-if="record.mobile_phone.raw_value">Mobile: <field name="mobile_phone"/></li>
|
||||
<li t-if="record.work_email.raw_value"><a t-attf-href="mailto:#{record.work_email.value}"><field name="work_email"/></a></li>
|
||||
</ul>
|
||||
<div class="oe_kanban_footer_left">
|
||||
<span title='Messages'><span class='oe_e'>9</span><t t-esc="record.message_ids.raw_value.length"/></span>
|
||||
<span title='Followers'><span class='oe_e'>+</span><t t-esc="record.message_follower_ids.raw_value.length"/></span>
|
||||
</div>
|
||||
<div class="oe_followers" groups="base.group_user">
|
||||
<button t-if="record.message_is_follower.raw_value" name="action_unfollow" type="object" class="oe_follower oe_following">
|
||||
<span class="oe_unfollow">Unfollow</span>
|
||||
<span class="oe_following">Following</span>
|
||||
</button>
|
||||
<button t-if="! record.message_is_follower.raw_value" name="action_follow" type="object" class="oe_follower oe_notfollow">Follow</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="mail.action_mail_inbox_feeds" model="ir.actions.client">
|
||||
<field name="params" eval=""{
|
||||
'domain': [
|
||||
('to_read', '=', True),
|
||||
('starred', '=', False),
|
||||
],
|
||||
'view_mailbox': True,
|
||||
'view_inbox': True,
|
||||
'read_action': 'read',
|
||||
'show_compose_message': True
|
||||
}""/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,65 @@
|
|||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class res_users(osv.Model):
|
||||
""" Update of res.users class
|
||||
- if adding groups to an user, check if base.group_user is in it
|
||||
(member of 'Employee'), create an employee form linked to it.
|
||||
"""
|
||||
_name = 'res.users'
|
||||
_inherit = ['res.users']
|
||||
|
||||
_columns = {
|
||||
'display_employees_suggestions': fields.boolean("Display Employees Suggestions"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'display_employees_suggestions': True,
|
||||
}
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
""" Override of __init__ to add access rights on
|
||||
display_employees_suggestions fields. Access rights are disabled by
|
||||
default, but allowed on some specific fields defined in
|
||||
self.SELF_{READ/WRITE}ABLE_FIELDS.
|
||||
"""
|
||||
init_res = super(res_users, self).__init__(pool, cr)
|
||||
# duplicate list to avoid modifying the original reference
|
||||
self.SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS)
|
||||
self.SELF_WRITEABLE_FIELDS.append('display_employees_suggestions')
|
||||
# duplicate list to avoid modifying the original reference
|
||||
self.SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS)
|
||||
self.SELF_READABLE_FIELDS.append('display_employees_suggestions')
|
||||
return init_res
|
||||
|
||||
def stop_showing_employees_suggestions(self, cr, uid, user_id, context=None):
|
||||
"""Update display_employees_suggestions value to False"""
|
||||
if context is None:
|
||||
context = {}
|
||||
self.write(cr, uid, user_id, {"display_employees_suggestions": False}, context)
|
||||
|
||||
def _create_welcome_message(self, cr, uid, user, context=None):
|
||||
"""Do not welcome new users anymore, welcome new employees instead"""
|
||||
return True
|
||||
|
||||
def _message_post_get_eid(self, cr, uid, thread_id, context=None):
|
||||
assert thread_id, "res.users does not support posting global messages"
|
||||
if context and 'thread_model' in context:
|
||||
context['thread_model'] = 'hr.employee'
|
||||
if isinstance(thread_id, (list, tuple)):
|
||||
thread_id = thread_id[0]
|
||||
return self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', thread_id)], context=context)
|
||||
|
||||
def message_post(self, cr, uid, thread_id, context=None, **kwargs):
|
||||
""" Redirect the posting of message on res.users to the related employee.
|
||||
This is done because when giving the context of Chatter on the
|
||||
various mailboxes, we do not have access to the current partner_id. """
|
||||
if kwargs.get('type') == 'email':
|
||||
return super(res_users, self).message_post(cr, uid, thread_id, context=context, **kwargs)
|
||||
employee_ids = self._message_post_get_eid(cr, uid, thread_id, context=context)
|
||||
if not employee_ids:
|
||||
pass # dpo something
|
||||
for employee_id in employee_ids:
|
||||
res = self.pool.get('hr.employee').message_post(cr, uid, employee_id, context=context, **kwargs)
|
||||
return res
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Update user form !-->
|
||||
<record id="view_users_form_mail" model="ir.ui.view">
|
||||
<field name="name">res.users.form.hr</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="mail.view_users_form_mail"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="display_groups_suggestions" position="after">
|
||||
<field name="display_employees_suggestions"/>
|
||||
</field>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -68,3 +68,8 @@
|
|||
margin: 2px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.openerp .oe_employee_vignette .oe_followers {
|
||||
width: auto;
|
||||
float: none;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
openerp.hr = function(session) {
|
||||
var _t = session.web._t;
|
||||
var QWeb = session.web.qweb;
|
||||
|
||||
var suggestions = session.suggestions;
|
||||
var removed_suggested_employee = session.suggestions.removed_suggested_employee = [];
|
||||
|
||||
suggestions.Employees = session.web.Widget.extend({
|
||||
events: {
|
||||
'click .oe_suggestion_remove.oe_suggestion_employee': 'stop_employee_suggestion',
|
||||
'click .oe_suggestion_remove_item.oe_suggestion_employee': 'remove_employee_suggestion',
|
||||
'click .oe_suggestion_follow': 'follow_employee',
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this._super(this, arguments);
|
||||
this.hr_employee = new session.web.DataSetSearch(this, 'hr.employee');
|
||||
this.res_users = new session.web.DataSetSearch(this, 'res.users');
|
||||
this.employees = [];
|
||||
},
|
||||
|
||||
start: function () {
|
||||
this._super.apply(this, arguments);
|
||||
return this.fetch_suggested_employee();
|
||||
},
|
||||
|
||||
fetch_suggested_employee: function () {
|
||||
var self = this;
|
||||
var employee = self.hr_employee.call('get_suggested_thread', {'removed_suggested_threads': removed_suggested_employee}).then(function (res) {
|
||||
_(res).each(function (result) {
|
||||
result['image']=self.session.url('/web/binary/image', {model: 'hr.employee', field: 'image_small', id: result.id});
|
||||
});
|
||||
self.employees = res;
|
||||
});
|
||||
return $.when(employee).done(this.proxy('display_suggested_employees'));
|
||||
},
|
||||
|
||||
display_suggested_employees: function () {
|
||||
var suggested_employees = this.$('.oe_sidebar_suggestion.oe_suggestion_employee');
|
||||
if (suggested_employees) {
|
||||
suggested_employees.remove();
|
||||
}
|
||||
if (this.employees.length === 0) {
|
||||
return this.$el.empty();
|
||||
}
|
||||
return this.$el.empty().html(QWeb.render('hr.suggestions.employees', {'widget': this}));
|
||||
},
|
||||
|
||||
follow_employee: function (event) {
|
||||
var self = this;
|
||||
var employee_id = parseInt($(event.currentTarget).attr('id'), 10);
|
||||
return this.hr_employee.call('message_subscribe_users', [[employee_id], [this.session.uid], undefined]).then(function(res) {
|
||||
self.fetch_suggested_employee();
|
||||
});
|
||||
},
|
||||
|
||||
remove_employee_suggestion: function (event) {
|
||||
removed_suggested_employee.push($(event.currentTarget).attr('id'));
|
||||
return this.fetch_suggested_employee();
|
||||
},
|
||||
|
||||
stop_employee_suggestion: function (event) {
|
||||
var self = this;
|
||||
return this.res_users.call('stop_showing_employees_suggestions', [this.session.uid]).then(function(res) {
|
||||
self.$(".oe_sidebar_suggestion.oe_suggestion_employee").hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
session.mail.WallSidebar.include({
|
||||
start: function () {
|
||||
this._super.apply(this, arguments);
|
||||
var sug_employees = new suggestions.Employees(this);
|
||||
return sug_employees.appendTo(this.$('.oe_suggestions_employees'));
|
||||
},
|
||||
});
|
||||
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<template>
|
||||
|
||||
<!-- Employees placeholder in sidebar -->
|
||||
<t t-extend="mail.wall.sidebar">
|
||||
<t t-jquery=".oe_mail_wall_sidebar" t-operation="append">
|
||||
<div class="oe_suggestions_employees"></div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Suggested employees -->
|
||||
<div t-name="hr.suggestions.employees" class="oe_sidebar_suggestion oe_suggestion_employee">
|
||||
<div class="oe_suggest_title">
|
||||
<a class="oe_suggestion_remove oe_suggestion_employee oe_e">X</a>
|
||||
<h2>Suggested Employees</h2>
|
||||
</div>
|
||||
<div class="oe_suggest_items">
|
||||
<t t-foreach="widget.employees" t-as="result">
|
||||
<div class="oe_suggested_item">
|
||||
<div class="oe_suggested_item_image">
|
||||
<a t-attf-href="#model=hr.employee&id=#{result.id}">
|
||||
<img t-attf-src="{result.image}" t-attf-alt="{result.name}"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="oe_suggested_item_content">
|
||||
<a class="oe_suggestion_item_name" t-attf-href="#model=hr.employee&id=#{result.id}"><t t-esc="result.name"/></a>
|
||||
<a class="oe_suggestion_remove_item oe_suggestion_employee oe_e" t-attf-id="{result.id}">X</a>
|
||||
<br/>
|
||||
<button class="oe_suggestion_follow" t-att-id="result.id">Follow</button>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
|
@ -87,10 +87,12 @@ Main Features
|
|||
'static/src/js/mail.js',
|
||||
'static/src/js/mail_followers.js',
|
||||
'static/src/js/many2many_tags_email.js',
|
||||
'static/src/js/suggestions.js',
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/mail.xml',
|
||||
'static/src/xml/mail_followers.xml',
|
||||
'static/src/xml/suggestions.xml',
|
||||
],
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -208,3 +208,12 @@ class mail_group(osv.Model):
|
|||
""" Wrapper because message_unsubscribe_users take a user_ids=None
|
||||
that receive the context without the wrapper. """
|
||||
return self.message_unsubscribe_users(cr, uid, ids, context=context)
|
||||
|
||||
def get_suggested_thread(self, cr, uid, removed_suggested_threads=None, context=None):
|
||||
"""Show the suggestion of groups if display_groups_suggestions if the
|
||||
user perference allows it."""
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context)
|
||||
if not user.display_groups_suggestions:
|
||||
return []
|
||||
else:
|
||||
return super(mail_group, self).get_suggested_thread(cr, uid, removed_suggested_threads, context)
|
||||
|
|
|
@ -240,21 +240,42 @@ class mail_thread(osv.AbstractModel):
|
|||
fol_obj.create(cr, SUPERUSER_ID, {'res_model': self._name, 'res_id': id, 'partner_id': partner_id})
|
||||
|
||||
def _search_followers(self, cr, uid, obj, name, args, context):
|
||||
"""Search function for message_follower_ids
|
||||
|
||||
Do not use with operator 'not in'. Use instead message_is_followers
|
||||
"""
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
res = []
|
||||
for field, operator, value in args:
|
||||
assert field == name
|
||||
# TOFIX make it work with not in
|
||||
assert operator != "not in", "Do not search message_follower_ids with 'not in'"
|
||||
fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('partner_id', operator, value)])
|
||||
res_ids = [fol.res_id for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids)]
|
||||
res.append(('id', 'in', res_ids))
|
||||
return res
|
||||
|
||||
def _search_is_follower(self, cr, uid, obj, name, args, context):
|
||||
"""Search function for message_is_follower"""
|
||||
fol_obj = self.pool.get('mail.followers')
|
||||
res = []
|
||||
for field, operator, value in args:
|
||||
assert field == name
|
||||
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||
if (operator == '=' and value) or (operator == '!=' and not value): # is a follower
|
||||
res_ids = self.search(cr, uid, [('message_follower_ids', 'in', [partner_id])], context=context)
|
||||
else: # is not a follower or unknown domain
|
||||
mail_ids = self.search(cr, uid, [('message_follower_ids', 'in', [partner_id])], context=context)
|
||||
res_ids = self.search(cr, uid, [('id', 'not in', mail_ids)], context=context)
|
||||
res.append(('id', 'in', res_ids))
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'message_is_follower': fields.function(_get_followers,
|
||||
type='boolean', string='Is a Follower', multi='_get_followers,'),
|
||||
'message_is_follower': fields.function(_get_followers, type='boolean',
|
||||
fnct_search=_search_is_follower, string='Is a Follower', multi='_get_followers,'),
|
||||
'message_follower_ids': fields.function(_get_followers, fnct_inv=_set_followers,
|
||||
fnct_search=_search_followers, type='many2many',
|
||||
obj='res.partner', string='Followers', multi='_get_followers'),
|
||||
fnct_search=_search_followers, type='many2many',
|
||||
obj='res.partner', string='Followers', multi='_get_followers'),
|
||||
'message_ids': fields.one2many('mail.message', 'res_id',
|
||||
domain=lambda self: [('model', '=', self._name)],
|
||||
auto_join=True,
|
||||
|
@ -1454,4 +1475,33 @@ class mail_thread(osv.AbstractModel):
|
|||
''', (ids, self._name, partner_id))
|
||||
return True
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
#------------------------------------------------------
|
||||
# Thread suggestion
|
||||
#------------------------------------------------------
|
||||
|
||||
def get_suggested_thread(self, cr, uid, removed_suggested_threads=None, context=None):
|
||||
"""Return a list of suggested threads, sorted by the numbers of followers"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
# TDE HACK: originally by MAT from portal/mail_mail.py but not working until the inheritance graph bug is not solved in trunk
|
||||
# TDE FIXME: relocate in portal when it won't be necessary to reload the hr.employee model in an additional bridge module
|
||||
if self.pool['res.groups']._all_columns.get('is_portal'):
|
||||
user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context)
|
||||
if any(group.is_portal for group in user.groups_id):
|
||||
return []
|
||||
|
||||
threads = []
|
||||
if removed_suggested_threads is None:
|
||||
removed_suggested_threads = []
|
||||
|
||||
thread_ids = self.search(cr, uid, [('id', 'not in', removed_suggested_threads), ('message_is_follower', '=', False)], context=context)
|
||||
for thread in self.browse(cr, uid, thread_ids, context=context):
|
||||
data = {
|
||||
'id': thread.id,
|
||||
'popularity': len(thread.message_follower_ids),
|
||||
'name': thread.name,
|
||||
'image_small': thread.image_small
|
||||
}
|
||||
threads.append(data)
|
||||
return sorted(threads, key=lambda x: (x['popularity'], x['id']), reverse=True)[:3]
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
],
|
||||
'view_mailbox': True,
|
||||
'view_inbox': True,
|
||||
'read_action': 'read'
|
||||
'read_action': 'read',
|
||||
'show_compose_message': False
|
||||
}""/>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.tools.translate import _
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
|
@ -52,21 +53,4 @@ class res_partner_mail(osv.Model):
|
|||
self._message_add_suggested_recipient(cr, uid, recipients, partner, partner=partner, reason=_('Partner Profile'))
|
||||
return recipients
|
||||
|
||||
def message_post(self, cr, uid, thread_id, **kwargs):
|
||||
""" Override related to res.partner. In case of email message, set it as
|
||||
private:
|
||||
- add the target partner in the message partner_ids
|
||||
- set thread_id as None, because this will trigger the 'private'
|
||||
aspect of the message (model=False, res_id=False)
|
||||
"""
|
||||
if isinstance(thread_id, (list, tuple)):
|
||||
thread_id = thread_id[0]
|
||||
if kwargs.get('type') == 'email':
|
||||
partner_ids = kwargs.get('partner_ids', [])
|
||||
if thread_id not in [command[1] for command in partner_ids]:
|
||||
partner_ids.append((4, thread_id))
|
||||
kwargs['partner_ids'] = partner_ids
|
||||
thread_id = False
|
||||
return super(res_partner_mail, self).message_post(cr, uid, thread_id, **kwargs)
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -28,6 +28,7 @@ class res_users(osv.Model):
|
|||
- add a preference about sending emails about notifications
|
||||
- make a new user follow itself
|
||||
- add a welcome message
|
||||
- add suggestion preference
|
||||
"""
|
||||
_name = 'res.users'
|
||||
_inherit = ['res.users']
|
||||
|
@ -37,10 +38,12 @@ class res_users(osv.Model):
|
|||
'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True,
|
||||
help="Email address internally associated with this user. Incoming "\
|
||||
"emails will appear in the user's notifications."),
|
||||
'display_groups_suggestions': fields.boolean("Display Groups Suggestions"),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'alias_domain': False, # always hide alias during creation
|
||||
'display_groups_suggestions': True,
|
||||
}
|
||||
|
||||
def __init__(self, pool, cr):
|
||||
|
@ -51,10 +54,10 @@ class res_users(osv.Model):
|
|||
init_res = super(res_users, self).__init__(pool, cr)
|
||||
# duplicate list to avoid modifying the original reference
|
||||
self.SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS)
|
||||
self.SELF_WRITEABLE_FIELDS.append('notification_email_send')
|
||||
self.SELF_WRITEABLE_FIELDS.extend(['notification_email_send', 'display_groups_suggestions'])
|
||||
# duplicate list to avoid modifying the original reference
|
||||
self.SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS)
|
||||
self.SELF_READABLE_FIELDS.extend(['notification_email_send', 'alias_domain', 'alias_name'])
|
||||
self.SELF_READABLE_FIELDS.extend(['notification_email_send', 'alias_domain', 'alias_name', 'display_groups_suggestions'])
|
||||
return init_res
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
|
@ -109,7 +112,7 @@ class res_users(osv.Model):
|
|||
def _message_post_get_pid(self, cr, uid, thread_id, context=None):
|
||||
assert thread_id, "res.users does not support posting global messages"
|
||||
if context and 'thread_model' in context:
|
||||
context['thread_model'] = 'res.partner'
|
||||
context['thread_model'] = 'res.users'
|
||||
if isinstance(thread_id, (list, tuple)):
|
||||
thread_id = thread_id[0]
|
||||
return self.browse(cr, SUPERUSER_ID, thread_id).partner_id.id
|
||||
|
@ -118,44 +121,32 @@ class res_users(osv.Model):
|
|||
""" Redirect the posting of message on res.users to the related partner.
|
||||
This is done because when giving the context of Chatter on the
|
||||
various mailboxes, we do not have access to the current partner_id. """
|
||||
if isinstance(thread_id, (list, tuple)):
|
||||
thread_id = thread_id[0]
|
||||
partner_ids = kwargs.get('partner_ids', [])
|
||||
partner_id = self._message_post_get_pid(cr, uid, thread_id, context=context)
|
||||
return self.pool.get('res.partner').message_post(cr, uid, partner_id, context=context, **kwargs)
|
||||
if partner_id not in [command[1] for command in partner_ids]:
|
||||
partner_ids.append(partner_id)
|
||||
kwargs['partner_ids'] = partner_ids
|
||||
return self.pool.get('mail.thread').message_post(cr, uid, False, **kwargs)
|
||||
|
||||
def message_update(self, cr, uid, ids, msg_dict, update_vals=None, context=None):
|
||||
for id in ids:
|
||||
partner_id = self.browse(cr, SUPERUSER_ID, id).partner_id.id
|
||||
self.pool.get('res.partner').message_update(cr, uid, [partner_id], msg_dict, update_vals=update_vals, context=context)
|
||||
return True
|
||||
|
||||
def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
|
||||
for id in ids:
|
||||
partner_id = self.browse(cr, SUPERUSER_ID, id).partner_id.id
|
||||
self.pool.get('res.partner').message_subscribe(cr, uid, [partner_id], partner_ids, subtype_ids=subtype_ids, context=context)
|
||||
return True
|
||||
|
||||
def message_get_partner_info_from_emails(self, cr, uid, emails, link_mail=False, context=None):
|
||||
return self.pool.get('res.partner').message_get_partner_info_from_emails(cr, uid, emails, link_mail=link_mail, context=context)
|
||||
return self.pool.get('mail.thread').message_get_partner_info_from_emails(cr, uid, emails, link_mail=link_mail, context=context)
|
||||
|
||||
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
|
||||
partner_ids = []
|
||||
for id in ids:
|
||||
partner_ids.append(self.browse(cr, SUPERUSER_ID, id).partner_id.id)
|
||||
return self.pool.get('res.partner').message_get_suggested_recipients(cr, uid, partner_ids, context=context)
|
||||
return dict.fromkeys(ids, list())
|
||||
|
||||
#------------------------------------------------------
|
||||
# Compatibility methods: do not use
|
||||
# TDE TODO: remove me in 8.0
|
||||
#------------------------------------------------------
|
||||
|
||||
def message_post_user_api(self, cr, uid, thread_id, context=None, **kwargs):
|
||||
""" Redirect the posting of message on res.users to the related partner.
|
||||
This is done because when giving the context of Chatter on the
|
||||
various mailboxes, we do not have access to the current partner_id. """
|
||||
partner_id = self._message_post_get_pid(cr, uid, thread_id, context=context)
|
||||
return self.pool.get('res.partner').message_post_user_api(cr, uid, partner_id, context=context, **kwargs)
|
||||
|
||||
def message_create_partners_from_emails(self, cr, uid, emails, context=None):
|
||||
return self.pool.get('res.partner').message_create_partners_from_emails(cr, uid, emails, context=context)
|
||||
def stop_showing_groups_suggestions(self, cr, uid, user_id, context=None):
|
||||
"""Update display_groups_suggestions value to False"""
|
||||
if context is None:
|
||||
context = {}
|
||||
self.write(cr, uid, user_id, {"display_groups_suggestions": False}, context)
|
||||
|
||||
|
||||
class res_users_mail_group(osv.Model):
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
<field name="alias_domain" invisible="1"/>
|
||||
<field name="alias_id" readonly="1" required="0" attrs="{'invisible': [('alias_domain', '=', False)]}"/>
|
||||
</field>
|
||||
<group string="Email preferences" position="after">
|
||||
<group name="misc" string="Miscellaneous"
|
||||
groups="base.group_no_one">
|
||||
<field name="display_groups_suggestions"/>
|
||||
</group>
|
||||
</group>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0px;
|
||||
margin: 0px
|
||||
margin: 0px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
|
@ -665,8 +665,72 @@
|
|||
.openerp .oe_mail_wall .oe_mail{
|
||||
margin: 16px;
|
||||
width: 600px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.openerp .oe_mail .oe_view_nocontent > p {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
|
||||
/* ------------- WALL SIDEBAR ------------- */
|
||||
|
||||
.openerp .oe_mail_wall .oe_mail_wall_aside {
|
||||
margin: 16px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 260px;
|
||||
}
|
||||
.openerp .oe_mail_wall_aside .oe_sidebar_suggestion {
|
||||
background-color: #EDEDF6;
|
||||
border-radius: 2px;
|
||||
padding-top: 1px;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_title h2 {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-left: 10px;
|
||||
padding: 0px;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items .oe_suggested_item {
|
||||
border-radius: 2px;
|
||||
width: 100%;
|
||||
margin-left: 10px;
|
||||
min-height: 67px; /* image_small 66x66px */
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items .oe_suggested_item_image {
|
||||
float: left;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items .oe_suggested_item_image img {
|
||||
border-radius: 2px;
|
||||
border: solid 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items .oe_suggested_item_content button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items .oe_suggested_item_content a.oe_suggestion_item_name {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 90%;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_title a.oe_suggestion_remove {
|
||||
line-height: 15px;
|
||||
margin-top: -2px;
|
||||
float: right;
|
||||
visibility: hidden;
|
||||
margin-right: 7px;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items .oe_suggested_item_content a.oe_suggestion_remove_item {
|
||||
line-height: 15px;
|
||||
margin-top: -2px;
|
||||
float: right;
|
||||
visibility: hidden;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_title:hover a.oe_suggestion_remove,
|
||||
.openerp .oe_sidebar_suggestion .oe_suggest_items:hover a.oe_suggestion_remove_item {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
text-align: center;
|
||||
overflow: hidden;
|
||||
-moz-border-radius: 3px;
|
||||
border-collapse: separate;
|
||||
-webkit-border-radius: 3px;
|
||||
-o-border-radius: 3px;
|
||||
-ms-border-radius: 3px;
|
||||
|
|
|
@ -4,8 +4,8 @@ openerp.mail = function (session) {
|
|||
|
||||
var mail = session.mail = {};
|
||||
|
||||
openerp_mail_followers(session, mail); // import mail_followers.js
|
||||
openerp_FieldMany2ManyTagsEmail(session); // import manyy2many_tags_email.js
|
||||
openerp_mail_followers(session, mail); // import mail_followers.js
|
||||
openerp_FieldMany2ManyTagsEmail(session); // import manyy2many_tags_email.js
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------
|
||||
|
@ -237,8 +237,15 @@ openerp.mail = function (session) {
|
|||
|
||||
this.format_data();
|
||||
|
||||
// update record_name: Partner profile
|
||||
if (this.model == 'res.partner') {
|
||||
this.record_name = 'Partner Profile of ' + this.record_name;
|
||||
}
|
||||
else if (this.model == 'hr.employee') {
|
||||
this.record_name = 'News from ' + this.record_name;
|
||||
}
|
||||
// record options and data
|
||||
this.show_record_name = this.options.show_record_name && this.record_name && !this.thread_level && this.model != 'res.partner';
|
||||
this.show_record_name = this.options.show_record_name && this.record_name && !this.thread_level;
|
||||
this.options.show_read = false;
|
||||
this.options.show_unread = false;
|
||||
if (this.options.show_read_unread_button) {
|
||||
|
@ -257,6 +264,7 @@ openerp.mail = function (session) {
|
|||
|
||||
/* Convert date, timerelative and avatar in displayable data. */
|
||||
format_data: function () {
|
||||
|
||||
//formating and add some fields for render
|
||||
this.date = this.date ? session.web.str_to_datetime(this.date) : false;
|
||||
if (this.date && new Date().getTime()-this.date.getTime() < 7*24*60*60*1000) {
|
||||
|
@ -745,7 +753,7 @@ openerp.mail = function (session) {
|
|||
}
|
||||
// create object and attach to the thread object
|
||||
thread.message_fetch([["id", "=", message_id]], false, [message_id], function (arg, data) {
|
||||
var message = thread.create_message_object( data[0] );
|
||||
var message = thread.create_message_object( data.slice(-1)[0] );
|
||||
// insert the message on dom
|
||||
thread.insert_message( message, root ? undefined : self.$el, root );
|
||||
});
|
||||
|
@ -1840,6 +1848,19 @@ openerp.mail = function (session) {
|
|||
});
|
||||
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------
|
||||
* Aside Widget
|
||||
* ------------------------------------------------------------
|
||||
*
|
||||
* This widget handles the display of a sidebar on the Wall. Its main use
|
||||
* is to display group and employees suggestion (if hr is installed).
|
||||
*/
|
||||
mail.WallSidebar = session.web.Widget.extend({
|
||||
template: 'mail.wall.sidebar',
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------
|
||||
* Wall Widget
|
||||
|
@ -1901,6 +1922,9 @@ openerp.mail = function (session) {
|
|||
if (! this.searchview.has_defaults) {
|
||||
this.message_render();
|
||||
}
|
||||
// render sidebar
|
||||
var wall_sidebar = new mail.WallSidebar(this);
|
||||
wall_sidebar.appendTo(this.$el.find('.oe_mail_wall_aside'));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2018,4 +2042,16 @@ openerp.mail = function (session) {
|
|||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------
|
||||
* Sub-widgets loading
|
||||
* ------------------------------------------------------------
|
||||
*
|
||||
* Load here widgets that could depend on widgets defined in mail.js
|
||||
*/
|
||||
|
||||
openerp.mail.suggestions(session, mail); // import suggestion.js (suggestion widget)
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
openerp.mail.suggestions = function(session, mail) {
|
||||
var _t = session.web._t;
|
||||
var QWeb = session.web.qweb;
|
||||
|
||||
var suggestions = session.suggestions = {};
|
||||
var removed_suggested_group = session.suggestions.removed_suggested_group = [];
|
||||
|
||||
suggestions.Groups = session.web.Widget.extend({
|
||||
events: {
|
||||
'click .oe_suggestion_remove.oe_suggestion_group': 'stop_group_suggestion',
|
||||
'click .oe_suggestion_remove_item.oe_suggestion_group': 'remove_group_suggestion',
|
||||
'click .oe_suggestion_join': 'join_group',
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.mail_group = new session.web.DataSetSearch(this, 'mail.group');
|
||||
this.res_users = new session.web.DataSetSearch(this, 'res.users');
|
||||
this.groups = [];
|
||||
},
|
||||
|
||||
start: function () {
|
||||
this._super.apply(this, arguments);
|
||||
return this.fetch_suggested_groups();
|
||||
},
|
||||
|
||||
fetch_suggested_groups: function () {
|
||||
var self = this;
|
||||
var group = self.mail_group.call('get_suggested_thread', {'removed_suggested_threads': removed_suggested_group}).then(function (res) {
|
||||
_(res).each(function (result) {
|
||||
result['image']=self.session.url('/web/binary/image', {model: 'mail.group', field: 'image_small', id: result.id});
|
||||
});
|
||||
self.groups = res;
|
||||
});
|
||||
return $.when(group).then(this.proxy('display_suggested_groups'));
|
||||
},
|
||||
|
||||
display_suggested_groups: function () {
|
||||
var suggested_groups = this.$('.oe_sidebar_suggestion.oe_suggestion_group');
|
||||
if (suggested_groups) {
|
||||
suggested_groups.empty();
|
||||
}
|
||||
if (this.groups.length === 0) {
|
||||
return this.$el.empty();
|
||||
}
|
||||
return this.$el.empty().html(QWeb.render('mail.suggestions.groups', {'widget': this}));
|
||||
},
|
||||
|
||||
join_group: function (event) {
|
||||
var self = this;
|
||||
return this.mail_group.call('message_subscribe_users', [[$(event.currentTarget).attr('id')],[this.session.uid]]).then(function(res) {
|
||||
self.fetch_suggested_groups();
|
||||
});
|
||||
},
|
||||
|
||||
remove_group_suggestion: function (event) {
|
||||
removed_suggested_group.push($(event.currentTarget).attr('id'));
|
||||
return this.fetch_suggested_groups();
|
||||
},
|
||||
|
||||
stop_group_suggestion: function (event) {
|
||||
var self = this;
|
||||
return this.res_users.call('stop_showing_groups_suggestions', [this.session.uid]).then(function(res) {
|
||||
self.$(".oe_sidebar_suggestion.oe_suggestion_group").hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
session.mail.WallSidebar.include({
|
||||
start: function () {
|
||||
this._super.apply(this, arguments);
|
||||
var sug_groups = new suggestions.Groups(this);
|
||||
return sug_groups.appendTo(this.$('.oe_suggestions_groups'));
|
||||
},
|
||||
});
|
||||
|
||||
};
|
|
@ -121,9 +121,11 @@
|
|||
To:
|
||||
<t t-if="!widget.is_private">
|
||||
<span class="oe_all_follower">
|
||||
Followers of
|
||||
<t t-if="widget.parent_thread.parent_message.record_name" t-raw="'"' + widget.parent_thread.parent_message.record_name + '"'"/>
|
||||
<t t-if="!widget.parent_thread.parent_message.record_name">this document</t>
|
||||
<t t-if="widget.parent_thread.parent_message.record_name" t-raw="'"' + widget.parent_thread.parent_message.record_name + '"'">
|
||||
Followers of <t t-raw="'"' + widget.parent_thread.parent_message.record_name + '"'"/>
|
||||
</t>
|
||||
<t t-if="!widget.parent_thread.parent_message.record_name and widget.options.view_inbox">My Followers</t>
|
||||
<t t-if="!widget.parent_thread.parent_message.record_name and !widget.options.view_inbox">Followers of this document</t>
|
||||
</span>
|
||||
</t>
|
||||
<t t-if="!widget.is_private and (widget.partner_ids.length or (widget.author_id and widget.author_id[0]))"> and </t>
|
||||
|
@ -197,8 +199,16 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<div class="oe_mail-placeholder"></div>
|
||||
<aside class="oe_mail_wall_aside"></aside>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
Empty template that holds the sidebar of the Wall
|
||||
-->
|
||||
<t t-name="mail.wall.sidebar">
|
||||
<div class="oe_mail_wall_sidebar"></div>
|
||||
</t>
|
||||
|
||||
<!--
|
||||
display message on the wall when there are no message
|
||||
-->
|
||||
|
@ -339,7 +349,4 @@
|
|||
</a>
|
||||
</span>
|
||||
|
||||
<!-- mail.thread.message.star
|
||||
Template used to display stared/unstared message in a mail.message
|
||||
-->
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<template>
|
||||
|
||||
<!-- Groups placeholder in sidebar -->
|
||||
<t t-extend="mail.wall.sidebar">
|
||||
<t t-jquery=".oe_mail_wall_sidebar" t-operation="append">
|
||||
<div class="oe_suggestions_groups"></div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
<!-- Suggested groups -->
|
||||
<div t-name="mail.suggestions.groups" class="oe_sidebar_suggestion oe_suggestion_group">
|
||||
<div class="oe_suggest_title">
|
||||
<a class="oe_suggestion_remove oe_suggestion_group oe_e">X</a>
|
||||
<h2>Suggested Groups</h2>
|
||||
</div>
|
||||
<div class="oe_suggest_items">
|
||||
<t t-foreach="widget.groups" t-as="result">
|
||||
<div class="oe_suggested_item">
|
||||
<div class="oe_suggested_item_image">
|
||||
<a t-attf-href="#model=mail.group&id=#{result.id}">
|
||||
<img t-attf-src="{result.image}" t-attf-alt="{result.name}"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="oe_suggested_item_content">
|
||||
<a class="oe_suggestion_item_name" t-attf-href="#model=mail.group&id=#{result.id}"><t t-esc="result.name"/></a>
|
||||
<a class="oe_suggestion_remove_item oe_suggestion_group oe_e" t-attf-id="{result.id}">X</a>
|
||||
<br/>
|
||||
<button t-att-id="result.id" class="oe_suggestion_join">Join Group</button>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
Loading…
Reference in New Issue