@ -5,32 +5,34 @@
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api
from odoo import fields
from odoo import models
from odoo import api , exceptions , fields , models
from odoo.tools import email_split
from odoo.tools import email_split
from odoo.tools.translate import _
from odoo.tools.translate import _
from odoo import exceptions
class Wizard ( models . TransientModel ) :
class Wizard ( models . TransientModel ) :
_name = ' mail_move_message.wizard '
_description = ' Mail move message wizard '
_name = " mail_move_message.wizard "
_description = " Mail move message wizard "
@api.model
@api.model
def _model_selection ( self ) :
def _model_selection ( self ) :
selection = [ ]
selection = [ ]
config_parameters = self . env [ ' ir.config_parameter ' ]
model_names = config_parameters . sudo ( ) . get_param ( ' mail_relocation_models ' )
model_names = model_names . split ( ' , ' ) if model_names else [ ]
if ' default_message_id ' in self . env . context :
message = self . env [ ' mail.message ' ] . browse ( self . env . context [ ' default_message_id ' ] )
config_parameters = self . env [ " ir.config_parameter " ]
model_names = config_parameters . sudo ( ) . get_param ( " mail_relocation_models " )
model_names = model_names . split ( " , " ) if model_names else [ ]
if " default_message_id " in self . env . context :
message = self . env [ " mail.message " ] . browse (
self . env . context [ " default_message_id " ]
)
if message . model and message . model not in model_names :
if message . model and message . model not in model_names :
model_names . append ( message . model )
model_names . append ( message . model )
if message . moved_from_model and message . moved_from_model not in model_names :
if message . moved_from_model and message . moved_from_model not in model_names :
model_names . append ( message . moved_from_model )
model_names . append ( message . moved_from_model )
if model_names :
if model_names :
selection = [ ( m . model , m . display_name ) for m in self . env [ ' ir.model ' ] . search ( [ ( ' model ' , ' in ' , model_names ) ] ) ]
selection = [
( m . model , m . display_name )
for m in self . env [ " ir.model " ] . search ( [ ( " model " , " in " , model_names ) ] )
]
return selection
return selection
@api.model
@api.model
@ -40,70 +42,107 @@ class Wizard(models.TransientModel):
available_models = self . _model_selection ( )
available_models = self . _model_selection ( )
if len ( available_models ) :
if len ( available_models ) :
record = self . env [ available_models [ 0 ] [ 0 ] ] . search ( [ ] , limit = 1 )
record = self . env [ available_models [ 0 ] [ 0 ] ] . search ( [ ] , limit = 1 )
res [ ' model_record ' ] = len ( record ) and ( available_models [ 0 ] [ 0 ] + ' , ' + str ( record . id ) ) or False
res [ " model_record " ] = (
len ( record ) and ( available_models [ 0 ] [ 0 ] + " , " + str ( record . id ) ) or False
)
if ' message_id ' in res :
message = self . env [ ' mail.message ' ] . browse ( res [ ' message_id ' ] )
if " message_id " in res :
message = self . env [ " mail.message " ] . browse ( res [ " message_id " ] )
email_from = message . email_from
email_from = message . email_from
parts = email_split ( email_from . replace ( ' ' , ' , ' ) )
parts = email_split ( email_from . replace ( " " , " , " ) )
if parts :
if parts :
email = parts [ 0 ]
email = parts [ 0 ]
name = email_from . find ( email ) != - 1 and email_from [ : email_from . index ( email ) ] . replace ( ' " ' , ' ' ) . replace ( ' < ' , ' ' ) . strip ( ) or email_from
name = (
email_from . find ( email ) != - 1
and email_from [ : email_from . index ( email ) ]
. replace ( ' " ' , " " )
. replace ( " < " , " " )
. strip ( )
or email_from
)
else :
else :
name , email = email_from
name , email = email_from
res [ ' message_name_from ' ] = name
res [ ' message_email_from ' ] = email
res [ ' partner_id ' ] = message . author_id . id
if message . author_id and self . env . uid not in [ u . id for u in message . author_id . user_ids ] :
res [ ' filter_by_partner ' ] = True
if message . author_id and res . get ( ' model ' ) :
res_id = self . env [ res [ ' model ' ] ] . search ( [ ] , order = ' id desc ' , limit = 1 )
res [ " message_name_from " ] = name
res [ " message_email_from " ] = email
res [ " partner_id " ] = message . author_id . id
if message . author_id and self . env . uid not in [
u . id for u in message . author_id . user_ids
] :
res [ " filter_by_partner " ] = True
if message . author_id and res . get ( " model " ) :
res_id = self . env [ res [ " model " ] ] . search ( [ ] , order = " id desc " , limit = 1 )
if res_id :
if res_id :
res [ ' res_id ' ] = res_id [ 0 ] . id
res [ " res_id " ] = res_id [ 0 ] . id
config_parameters = self . env [ ' ir.config_parameter ' ]
res [ ' move_followers ' ] = config_parameters . sudo ( ) . get_param ( ' mail_relocation_move_followers ' )
config_parameters = self . env [ " ir.config_parameter " ]
res [ " move_followers " ] = config_parameters . sudo ( ) . get_param (
" mail_relocation_move_followers "
)
res [ ' uid ' ] = self . env . uid
res [ " uid " ] = self . env . uid
return res
return res
message_id = fields . Many2one ( ' mail.message ' , string = ' Message ' )
message_body = fields . Html ( related = ' message_id.body ' , string = ' Message to move ' , readonly = True )
message_from = fields . Char ( related = ' message_id.email_from ' , string = ' From ' , readonly = True )
message_subject = fields . Char ( related = ' message_id.subject ' , string = ' Subject ' , readonly = True )
message_moved_by_message_id = fields . Many2one ( ' mail.message ' , related = ' message_id.moved_by_message_id ' , string = ' Moved with ' , readonly = True )
message_moved_by_user_id = fields . Many2one ( ' res.users ' , related = ' message_id.moved_by_user_id ' , string = ' Moved by ' , readonly = True )
message_is_moved = fields . Boolean ( string = ' Is Moved ' , related = ' message_id.is_moved ' , readonly = True )
parent_id = fields . Many2one ( ' mail.message ' , string = ' Search by name ' , )
model_record = fields . Reference ( selection = " _model_selection " , string = ' Record ' )
model = fields . Char ( compute = " _compute_model_res_id " , string = ' Model ' )
res_id = fields . Integer ( compute = " _compute_model_res_id " , string = ' Record ID ' )
can_move = fields . Boolean ( ' Can move ' , compute = ' _compute_get_can_move ' )
move_back = fields . Boolean ( ' MOVE TO ORIGIN ' , help = ' Move message and submessages to original place ' )
partner_id = fields . Many2one ( ' res.partner ' , string = ' Author ' )
filter_by_partner = fields . Boolean ( ' Filter Records by partner ' )
message_id = fields . Many2one ( " mail.message " , string = " Message " )
message_body = fields . Html (
related = " message_id.body " , string = " Message to move " , readonly = True
)
message_from = fields . Char (
related = " message_id.email_from " , string = " From " , readonly = True
)
message_subject = fields . Char (
related = " message_id.subject " , string = " Subject " , readonly = True
)
message_moved_by_message_id = fields . Many2one (
" mail.message " ,
related = " message_id.moved_by_message_id " ,
string = " Moved with " ,
readonly = True ,
)
message_moved_by_user_id = fields . Many2one (
" res.users " ,
related = " message_id.moved_by_user_id " ,
string = " Moved by " ,
readonly = True ,
)
message_is_moved = fields . Boolean (
string = " Is Moved " , related = " message_id.is_moved " , readonly = True
)
parent_id = fields . Many2one ( " mail.message " , string = " Search by name " , )
model_record = fields . Reference ( selection = " _model_selection " , string = " Record " )
model = fields . Char ( compute = " _compute_model_res_id " , string = " Model " )
res_id = fields . Integer ( compute = " _compute_model_res_id " , string = " Record ID " )
can_move = fields . Boolean ( " Can move " , compute = " _compute_get_can_move " )
move_back = fields . Boolean (
" MOVE TO ORIGIN " , help = " Move message and submessages to original place "
)
partner_id = fields . Many2one ( " res.partner " , string = " Author " )
filter_by_partner = fields . Boolean ( " Filter Records by partner " )
message_email_from = fields . Char ( )
message_email_from = fields . Char ( )
message_name_from = fields . Char ( )
message_name_from = fields . Char ( )
# FIXME message_to_read should be True even if current message or any his childs are unread
# FIXME message_to_read should be True even if current message or any his childs are unread
message_to_read = fields . Boolean ( compute = ' _compute_is_read ' , string = " Unread message " ,
help = " Service field shows that this message were unread when moved " )
message_to_read = fields . Boolean (
compute = " _compute_is_read " ,
string = " Unread message " ,
help = " Service field shows that this message were unread when moved " ,
)
uid = fields . Integer ( )
uid = fields . Integer ( )
move_followers = fields . Boolean (
move_followers = fields . Boolean (
' Move Followers ' ,
" Move Followers " ,
help = " Add followers of current record to a new record. \n "
help = " Add followers of current record to a new record. \n "
" You must use this option, if new record has restricted access. \n "
" You must use this option, if new record has restricted access. \n "
" You can change default value for this option at Settings/System Parameters " )
" You can change default value for this option at Settings/System Parameters " ,
)
@api.multi
@api.multi
@api.depends ( ' model_record ' )
@api.depends ( " model_record " )
def _compute_model_res_id ( self ) :
def _compute_model_res_id ( self ) :
for rec in self :
for rec in self :
rec . model = rec . model_record and rec . model_record . _name or False
rec . model = rec . model_record and rec . model_record . _name or False
rec . res_id = rec . model_record and rec . model_record . id or False
rec . res_id = rec . model_record and rec . model_record . id or False
@api.depends ( ' message_id ' )
@api.depends ( " message_id " )
@api.multi
@api.multi
def _compute_get_can_move ( self ) :
def _compute_get_can_move ( self ) :
for r in self :
for r in self :
@ -111,32 +150,43 @@ class Wizard(models.TransientModel):
@api.multi
@api.multi
def _compute_is_read ( self ) :
def _compute_is_read ( self ) :
messages = self . env [ ' mail.message ' ] . sudo ( ) . browse ( self . message_id . all_child_ids . ids + [ self . message_id . id ] )
messages = (
self . env [ " mail.message " ]
. sudo ( )
. browse ( self . message_id . all_child_ids . ids + [ self . message_id . id ] )
)
self . message_to_read = True in [ m . needaction for m in messages ]
self . message_to_read = True in [ m . needaction for m in messages ]
@api.multi
@api.multi
def get_can_move_one ( self ) :
def get_can_move_one ( self ) :
self . ensure_one ( )
self . ensure_one ( )
# message was not moved before OR message is a top message of previous move
# message was not moved before OR message is a top message of previous move
self . can_move = not self . message_id . moved_by_message_id or self . message_id . moved_by_message_id . id == self . message_id . id
self . can_move = (
not self . message_id . moved_by_message_id
or self . message_id . moved_by_message_id . id == self . message_id . id
)
@api.onchange ( ' move_back ' )
@api.onchange ( " move_back " )
def on_change_move_back ( self ) :
def on_change_move_back ( self ) :
if not self . move_back :
if not self . move_back :
return
return
self . parent_id = self . message_id . moved_from_parent_id
self . parent_id = self . message_id . moved_from_parent_id
message = self . message_id
message = self . message_id
if message . is_moved :
if message . is_moved :
self . model_record = self . env [ message . moved_from_model ] . browse ( message . moved_from_res_id )
self . model_record = self . env [ message . moved_from_model ] . browse (
message . moved_from_res_id
)
@api.onchange ( ' parent_id ' , ' model_record ' )
@api.onchange ( " parent_id " , " model_record " )
def update_move_back ( self ) :
def update_move_back ( self ) :
model = self . message_id . moved_from_model
model = self . message_id . moved_from_model
self . move_back = self . parent_id == self . message_id . moved_from_parent_id \
and self . res_id == self . message_id . moved_from_res_id \
self . move_back = (
self . parent_id == self . message_id . moved_from_parent_id
and self . res_id == self . message_id . moved_from_res_id
and ( self . model == model or ( not self . model and not model ) )
and ( self . model == model or ( not self . model and not model ) )
)
@api.onchange ( ' parent_id ' )
@api.onchange ( " parent_id " )
def on_change_parent_id ( self ) :
def on_change_parent_id ( self ) :
if self . parent_id and self . parent_id . model :
if self . parent_id and self . parent_id . model :
self . model = self . parent_id . model
self . model = self . parent_id . model
@ -145,24 +195,26 @@ class Wizard(models.TransientModel):
self . model = None
self . model = None
self . res_id = None
self . res_id = None
@api.onchange ( ' model ' , ' filter_by_partner ' , ' partner_id ' )
@api.onchange ( " model " , " filter_by_partner " , " partner_id " )
def on_change_partner ( self ) :
def on_change_partner ( self ) :
domain = { ' res_id ' : [ ( ' id ' , ' != ' , self . message_id . res_id ) ] }
domain = { " res_id " : [ ( " id " , " != " , self . message_id . res_id ) ] }
if self . model and self . filter_by_partner and self . partner_id :
if self . model and self . filter_by_partner and self . partner_id :
fields = self . env [ self . model ] . fields_get ( False )
fields = self . env [ self . model ] . fields_get ( False )
contact_field = False
contact_field = False
for n , f in fields . items ( ) :
for n , f in fields . items ( ) :
if f [ ' type ' ] == ' many2one ' and f [ ' relation ' ] == ' res.partner ' :
if f [ " type " ] == " many2one " and f [ " relation " ] == " res.partner " :
contact_field = n
contact_field = n
break
break
if contact_field :
if contact_field :
domain [ ' res_id ' ] . append ( ( contact_field , ' = ' , self . partner_id . id ) )
domain [ " res_id " ] . append ( ( contact_field , " = " , self . partner_id . id ) )
if self . model :
if self . model :
res_id = self . env [ self . model ] . search ( domain [ ' res_id ' ] , order = ' id desc ' , limit = 1 )
res_id = self . env [ self . model ] . search (
domain [ " res_id " ] , order = " id desc " , limit = 1
)
self . res_id = res_id and res_id [ 0 ] . id
self . res_id = res_id and res_id [ 0 ] . id
else :
else :
self . res_id = None
self . res_id = None
return { ' domain ' : domain }
return { " domain " : domain }
@api.multi
@api.multi
def check_access ( self ) :
def check_access ( self ) :
@ -172,16 +224,18 @@ class Wizard(models.TransientModel):
@api.multi
@api.multi
def check_access_one ( self ) :
def check_access_one ( self ) :
self . ensure_one ( )
self . ensure_one ( )
operation = ' write '
operation = " write "
if not ( self . model and self . res_id ) :
if not ( self . model and self . res_id ) :
return True
return True
model_obj = self . env [ self . model ]
model_obj = self . env [ self . model ]
mids = model_obj . browse ( self . res_id ) . exists ( )
mids = model_obj . browse ( self . res_id ) . exists ( )
if hasattr ( model_obj , ' check_mail_message_access ' ) :
if hasattr ( model_obj , " check_mail_message_access " ) :
model_obj . check_mail_message_access ( mids . ids , operation )
model_obj . check_mail_message_access ( mids . ids , operation )
else :
else :
self . env [ ' mail.thread ' ] . check_mail_message_access ( mids . ids , operation , model_name = self . model )
self . env [ " mail.thread " ] . check_mail_message_access (
mids . ids , operation , model_name = self . model
)
@api.multi
@api.multi
def open_moved_by_message_id ( self ) :
def open_moved_by_message_id ( self ) :
@ -189,44 +243,60 @@ class Wizard(models.TransientModel):
for r in self :
for r in self :
message_id = r . message_moved_by_message_id . id
message_id = r . message_moved_by_message_id . id
return {
return {
' type ' : ' ir.actions.act_window ' ,
' res_model ' : ' mail_move_message.wizard ' ,
' view_mode ' : ' form ' ,
' view_type ' : ' form ' ,
' views ' : [ [ False , ' form ' ] ] ,
' target ' : ' new ' ,
' context ' : { ' default_message_id ' : message_id } ,
" type " : " ir.actions.act_window " ,
" res_model " : " mail_move_message.wizard " ,
" view_mode " : " form " ,
" view_type " : " form " ,
" views " : [ [ False , " form " ] ] ,
" target " : " new " ,
" context " : { " default_message_id " : message_id } ,
}
}
@api.multi
@api.multi
def move ( self ) :
def move ( self ) :
for r in self :
for r in self :
if not r . model :
if not r . model :
raise exceptions . except_orm ( _ ( ' Record field is empty! ' ) , _ ( ' Select a record for relocation first ' ) )
raise exceptions . except_orm (
_ ( " Record field is empty! " ) ,
_ ( " Select a record for relocation first " ) ,
)
for r in self :
for r in self :
r . check_access ( )
r . check_access ( )
if not r . parent_id or not ( r . parent_id . model == r . model and
r . parent_id . res_id == r . res_id ) :
if not r . parent_id or not (
r . parent_id . model == r . model and r . parent_id . res_id == r . res_id
) :
# link with the first message of record
# link with the first message of record
parent = self . env [ ' mail.message ' ] . search ( [ ( ' model ' , ' = ' , r . model ) , ( ' res_id ' , ' = ' , r . res_id ) ] , order = ' id ' , limit = 1 )
parent = self . env [ " mail.message " ] . search (
[ ( " model " , " = " , r . model ) , ( " res_id " , " = " , r . res_id ) ] ,
order = " id " ,
limit = 1 ,
)
r . parent_id = parent . id or None
r . parent_id = parent . id or None
r . message_id . move ( r . parent_id . id , r . res_id , r . model , r . move_back , r . move_followers , r . message_to_read , r . partner_id )
r . message_id . move (
r . parent_id . id ,
r . res_id ,
r . model ,
r . move_back ,
r . move_followers ,
r . message_to_read ,
r . partner_id ,
)
if r . model in [ ' mail.message ' , ' mail.channel ' , False ] :
if r . model in [ " mail.message " , " mail.channel " , False ] :
return {
return {
' name ' : ' Chess game page ' ,
' type ' : ' ir.actions.act_url ' ,
' url ' : ' /web ' ,
' target ' : ' self ' ,
" name " : " Chess game page " ,
" type " : " ir.actions.act_url " ,
" url " : " /web " ,
" target " : " self " ,
}
}
return {
return {
' name ' : _ ( ' Record ' ) ,
' view_type ' : ' form ' ,
' view_mode ' : ' form ' ,
' res_model ' : r . model ,
' res_id ' : r . res_id ,
' views ' : [ ( False , ' form ' ) ] ,
' type ' : ' ir.actions.act_window ' ,
" name " : _ ( " Record " ) ,
" view_type " : " form " ,
" view_mode " : " form " ,
" res_model " : r . model ,
" res_id " : r . res_id ,
" views " : [ ( False , " form " ) ] ,
" type " : " ir.actions.act_window " ,
}
}
@api.multi
@api.multi
@ -240,8 +310,10 @@ class Wizard(models.TransientModel):
msg_id = self . message_id . id
msg_id = self . message_id . id
# Send notification
# Send notification
notification = { ' id ' : msg_id }
self . env [ ' bus.bus ' ] . sendone ( ( self . _cr . dbname , ' mail_move_message.delete_message ' ) , notification )
notification = { " id " : msg_id }
self . env [ " bus.bus " ] . sendone (
( self . _cr . dbname , " mail_move_message.delete_message " ) , notification
)
self . message_id . unlink ( )
self . message_id . unlink ( )
return { }
return { }
@ -256,20 +328,34 @@ class Wizard(models.TransientModel):
self . ensure_one ( )
self . ensure_one ( )
self . message_id . set_message_done ( )
self . message_id . set_message_done ( )
self . message_id . child_ids . set_message_done ( )
self . message_id . child_ids . set_message_done ( )
return { ' type ' : ' ir.actions.act_window_close ' }
return { " type " : " ir.actions.act_window_close " }
class MailMessage ( models . Model ) :
class MailMessage ( models . Model ) :
_inherit = ' mail.message '
_inherit = " mail.message "
is_moved = fields . Boolean ( ' Is moved ' )
moved_from_res_id = fields . Integer ( ' Related Document ID (Original) ' )
moved_from_model = fields . Char ( ' Related Document Model (Original) ' )
moved_from_parent_id = fields . Many2one ( ' mail.message ' , ' Parent Message (Original) ' , ondelete = ' set null ' )
moved_by_message_id = fields . Many2one ( ' mail.message ' , ' Moved by message ' , ondelete = ' set null ' , help = ' Top message, that initate moving this message ' )
moved_by_user_id = fields . Many2one ( ' res.users ' , ' Moved by user ' , ondelete = ' set null ' )
all_child_ids = fields . One2many ( ' mail.message ' , string = ' All childs ' , compute = ' _compute_get_all_childs ' , help = ' all childs, including subchilds ' )
moved_as_unread = fields . Boolean ( ' Was Unread ' , default = False )
is_moved = fields . Boolean ( " Is moved " )
moved_from_res_id = fields . Integer ( " Related Document ID (Original) " )
moved_from_model = fields . Char ( " Related Document Model (Original) " )
moved_from_parent_id = fields . Many2one (
" mail.message " , " Parent Message (Original) " , ondelete = " set null "
)
moved_by_message_id = fields . Many2one (
" mail.message " ,
" Moved by message " ,
ondelete = " set null " ,
help = " Top message, that initate moving this message " ,
)
moved_by_user_id = fields . Many2one (
" res.users " , " Moved by user " , ondelete = " set null "
)
all_child_ids = fields . One2many (
" mail.message " ,
string = " All childs " ,
compute = " _compute_get_all_childs " ,
help = " all childs, including subchilds " ,
)
moved_as_unread = fields . Boolean ( " Was Unread " , default = False )
@api.multi
@api.multi
def _compute_get_all_childs ( self , include_myself = True ) :
def _compute_get_all_childs ( self , include_myself = True ) :
@ -283,30 +369,59 @@ class MailMessage(models.Model):
if include_myself :
if include_myself :
ids . append ( self . id )
ids . append ( self . id )
while True :
while True :
new_ids = self . search ( [ ( ' parent_id ' , ' in ' , ids ) , ( ' id ' , ' not in ' , ids ) ] ) . ids
new_ids = self . search ( [ ( " parent_id " , " in " , ids ) , ( " id " , " not in " , ids ) ] ) . ids
if new_ids :
if new_ids :
ids = ids + new_ids
ids = ids + new_ids
continue
continue
break
break
moved_childs = self . search ( [ ( ' moved_by_message_id ' , ' = ' , self . id ) ] ) . ids
moved_childs = self . search ( [ ( " moved_by_message_id " , " = " , self . id ) ] ) . ids
self . all_child_ids = ids + moved_childs
self . all_child_ids = ids + moved_childs
@api.multi
@api.multi
def move_followers ( self , model , ids ) :
def move_followers ( self , model , ids ) :
fol_obj = self . env [ ' mail.followers ' ]
fol_obj = self . env [ " mail.followers " ]
for message in self :
for message in self :
followers = fol_obj . sudo ( ) . search ( [ ( ' res_model ' , ' = ' , message . model ) ,
( ' res_id ' , ' = ' , message . res_id ) ] )
followers = fol_obj . sudo ( ) . search (
[ ( " res_model " , " = " , message . model ) , ( " res_id " , " = " , message . res_id ) ]
)
for f in followers :
for f in followers :
self . env [ model ] . browse ( ids ) . message_subscribe ( [ f . partner_id . id ] , [ s . id for s in f . subtype_ids ] )
self . env [ model ] . browse ( ids ) . message_subscribe (
[ f . partner_id . id ] , [ s . id for s in f . subtype_ids ]
)
@api.multi
@api.multi
def move ( self , parent_id , res_id , model , move_back , move_followers = False , message_to_read = False , author = False ) :
def move (
self ,
parent_id ,
res_id ,
model ,
move_back ,
move_followers = False ,
message_to_read = False ,
author = False ,
) :
for r in self :
for r in self :
r . move_one ( parent_id , res_id , model , move_back , move_followers = move_followers , message_to_read = message_to_read , author = author )
r . move_one (
parent_id ,
res_id ,
model ,
move_back ,
move_followers = move_followers ,
message_to_read = message_to_read ,
author = author ,
)
@api.multi
@api.multi
def move_one ( self , parent_id , res_id , model , move_back , move_followers = False , message_to_read = False , author = False ) :
def move_one (
self ,
parent_id ,
res_id ,
model ,
move_back ,
move_followers = False ,
message_to_read = False ,
author = False ,
) :
self . ensure_one ( )
self . ensure_one ( )
if parent_id == self . id :
if parent_id == self . id :
# if for any reason method is called to move message with parent
# if for any reason method is called to move message with parent
@ -314,116 +429,126 @@ class MailMessage(models.Model):
# building message tree
# building message tree
return
return
if not self . author_id :
if not self . author_id :
self . write ( {
' author_id ' : author . id ,
} )
self . write ( { " author_id " : author . id } )
vals = { }
vals = { }
if move_back :
if move_back :
# clear variables if we move everything back
# clear variables if we move everything back
vals [ ' is_moved ' ] = False
vals [ ' moved_by_user_id ' ] = None
vals [ ' moved_by_message_id ' ] = None
vals [ ' moved_from_res_id ' ] = None
vals [ ' moved_from_model ' ] = None
vals [ ' moved_from_parent_id ' ] = None
vals [ ' moved_as_unread ' ] = None
vals [ " is_moved " ] = False
vals [ " moved_by_user_id " ] = None
vals [ " moved_by_message_id " ] = None
vals [ " moved_from_res_id " ] = None
vals [ " moved_from_model " ] = None
vals [ " moved_from_parent_id " ] = None
vals [ " moved_as_unread " ] = None
else :
else :
vals [ ' parent_id ' ] = parent_id
vals [ ' res_id ' ] = res_id
vals [ ' model ' ] = model
vals [ ' is_moved ' ] = True
vals [ ' moved_by_user_id ' ] = self . env . user . id
vals [ ' moved_by_message_id ' ] = self . id
vals [ ' moved_as_unread ' ] = message_to_read
vals [ " parent_id " ] = parent_id
vals [ " res_id " ] = res_id
vals [ " model " ] = model
vals [ " is_moved " ] = True
vals [ " moved_by_user_id " ] = self . env . user . id
vals [ " moved_by_message_id " ] = self . id
vals [ " moved_as_unread " ] = message_to_read
# Update record_name in message
# Update record_name in message
vals [ ' record_name ' ] = self . _get_record_name ( vals )
vals [ " record_name " ] = self . _get_record_name ( vals )
# unread message remains unread after moving back to origin
# unread message remains unread after moving back to origin
if self . moved_as_unread and move_back :
if self . moved_as_unread and move_back :
notification = {
notification = {
' mail_message_id ' : self . id ,
' res_partner_id ' : self . env . user . partner_id . id ,
' is_read ' : False ,
" mail_message_id " : self . id ,
" res_partner_id " : self . env . user . partner_id . id ,
" is_read " : False ,
}
}
self . write ( {
' notification_ids ' : [ ( 0 , 0 , notification ) ] ,
} )
self . write ( { " notification_ids " : [ ( 0 , 0 , notification ) ] } )
for r in self . all_child_ids :
for r in self . all_child_ids :
r_vals = vals . copy ( )
r_vals = vals . copy ( )
if not r . is_moved :
if not r . is_moved :
# moved_from_* variables contain not last, but original
# moved_from_* variables contain not last, but original
# reference
# reference
r_vals [ ' moved_from_parent_id ' ] = r . parent_id . id or r . env . context . get ( ' uid ' )
r_vals [ ' moved_from_res_id ' ] = r . res_id or r . id
r_vals [ ' moved_from_model ' ] = r . model or r . _name
r_vals [ " moved_from_parent_id " ] = r . parent_id . id or r . env . context . get (
" uid "
)
r_vals [ " moved_from_res_id " ] = r . res_id or r . id
r_vals [ " moved_from_model " ] = r . model or r . _name
elif move_back :
elif move_back :
r_vals [ ' parent_id ' ] = r . moved_from_parent_id . id
r_vals [ ' res_id ' ] = r . moved_from_res_id
r_vals [ ' model ' ] = ( r . moved_from_model and r . moved_from_model not in [ ' mail.message ' , ' mail.channel ' , False ] ) and r . moved_from_model
r_vals [ ' record_name ' ] = r_vals [ ' model ' ] and self . env [ r . moved_from_model ] . browse ( r . moved_from_res_id ) . name
r_vals [ " parent_id " ] = r . moved_from_parent_id . id
r_vals [ " res_id " ] = r . moved_from_res_id
r_vals [ " model " ] = (
r . moved_from_model
and r . moved_from_model
not in [ " mail.message " , " mail.channel " , False ]
) and r . moved_from_model
r_vals [ " record_name " ] = (
r_vals [ " model " ]
and self . env [ r . moved_from_model ] . browse ( r . moved_from_res_id ) . name
)
if move_followers :
if move_followers :
r . sudo ( ) . move_followers ( r_vals . get ( ' model ' ) , r_vals . get ( ' res_id ' ) )
r . sudo ( ) . move_followers ( r_vals . get ( " model " ) , r_vals . get ( " res_id " ) )
r . sudo ( ) . write ( r_vals )
r . sudo ( ) . write ( r_vals )
r . attachment_ids . sudo ( ) . write ( {
' res_id ' : r_vals . get ( ' res_id ' ) ,
' res_model ' : r_vals . get ( ' model ' )
} )
r . attachment_ids . sudo ( ) . write (
{ " res_id " : r_vals . get ( " res_id " ) , " res_model " : r_vals . get ( " model " ) }
)
# Send notification
# Send notification
notification = {
notification = {
' id ' : self . id ,
' res_id ' : vals . get ( ' res_id ' ) ,
' model ' : vals . get ( ' model ' ) ,
' is_moved ' : vals [ ' is_moved ' ] ,
' record_name ' : ' record_name ' in vals and vals [ ' record_name ' ] ,
" id " : self . id ,
" res_id " : vals . get ( " res_id " ) ,
" model " : vals . get ( " model " ) ,
" is_moved " : vals [ " is_moved " ] ,
" record_name " : " record_name " in vals and vals [ " record_name " ] ,
}
}
self . env [ ' bus.bus ' ] . sendone ( ( self . _cr . dbname , ' mail_move_message ' ) , notification )
self . env [ " bus.bus " ] . sendone (
( self . _cr . dbname , " mail_move_message " ) , notification
)
@api.multi
@api.multi
def name_get ( self ) :
def name_get ( self ) :
context = self . env . context
context = self . env . context
if not ( context or { } ) . get ( ' extended_name ' ) :
if not ( context or { } ) . get ( " extended_name " ) :
return super ( MailMessage , self ) . name_get ( )
return super ( MailMessage , self ) . name_get ( )
reads = self . read ( [ ' record_name ' , ' model ' , ' res_id ' ] )
reads = self . read ( [ " record_name " , " model " , " res_id " ] )
res = [ ]
res = [ ]
for record in reads :
for record in reads :
name = record [ ' record_name ' ] or ' '
extended_name = ' [ %s ] ID %s ' % ( record . get ( ' model ' , ' UNDEF ' ) , record . get ( ' res_id ' , ' UNDEF ' ) )
res . append ( ( record [ ' id ' ] , name + extended_name ) )
name = record [ " record_name " ] or " "
extended_name = " [{}] ID {} " . format (
record . get ( " model " , " UNDEF " ) , record . get ( " res_id " , " UNDEF " ) ,
)
res . append ( ( record [ " id " ] , name + extended_name ) )
return res
return res
@api.multi
@api.multi
def message_format ( self ) :
def message_format ( self ) :
message_values = super ( MailMessage , self ) . message_format ( )
message_values = super ( MailMessage , self ) . message_format ( )
message_index = { message [ ' id ' ] : message for message in message_values }
message_index = { message [ " id " ] : message for message in message_values }
for item in self :
for item in self :
msg = message_index . get ( item . id )
msg = message_index . get ( item . id )
if msg :
if msg :
msg [ ' is_moved ' ] = item . is_moved
msg [ " is_moved " ] = item . is_moved
return message_values
return message_values
class MailMoveMessageConfiguration ( models . TransientModel ) :
class MailMoveMessageConfiguration ( models . TransientModel ) :
_inherit = ' res.config.settings '
_inherit = " res.config.settings "
model_ids = fields . Many2many ( comodel_name = ' ir.model ' , string = ' Models ' )
move_followers = fields . Boolean ( ' Move Followers ' )
model_ids = fields . Many2many ( comodel_name = " ir.model " , string = " Models " )
move_followers = fields . Boolean ( " Move Followers " )
@api.model
@api.model
def get_values ( self ) :
def get_values ( self ) :
res = super ( MailMoveMessageConfiguration , self ) . get_values ( )
res = super ( MailMoveMessageConfiguration , self ) . get_values ( )
config_parameters = self . env [ " ir.config_parameter " ] . sudo ( )
config_parameters = self . env [ " ir.config_parameter " ] . sudo ( )
model_names = config_parameters . sudo ( ) . get_param ( ' mail_relocation_models ' )
model_names = model_names . split ( ' , ' )
model_ids = self . env [ ' ir.model ' ] . sudo ( ) . search ( [ ( ' model ' , ' in ' , model_names ) ] )
model_names = config_parameters . sudo ( ) . get_param ( " mail_relocation_models " )
model_names = model_names . split ( " , " )
model_ids = self . env [ " ir.model " ] . sudo ( ) . search ( [ ( " model " , " in " , model_names ) ] )
res . update (
res . update (
model_ids = [ m . id for m in model_ids ] ,
model_ids = [ m . id for m in model_ids ] ,
move_followers = config_parameters . sudo ( ) . get_param ( ' mail_relocation_move_followers ' ) ,
move_followers = config_parameters . sudo ( ) . get_param (
" mail_relocation_move_followers "
) ,
)
)
return res
return res
@ -432,38 +557,50 @@ class MailMoveMessageConfiguration(models.TransientModel):
super ( MailMoveMessageConfiguration , self ) . set_values ( )
super ( MailMoveMessageConfiguration , self ) . set_values ( )
config_parameters = self . env [ " ir.config_parameter " ] . sudo ( )
config_parameters = self . env [ " ir.config_parameter " ] . sudo ( )
for record in self :
for record in self :
model_names = ' , ' . join ( [ x . model for x in record . model_ids ] )
config_parameters . set_param ( " mail_relocation_models " , model_names or ' ' )
config_parameters . set_param ( " mail_relocation_move_followers " , record . move_followers or ' ' )
model_names = " , " . join ( [ x . model for x in record . model_ids ] )
config_parameters . set_param ( " mail_relocation_models " , model_names or " " )
config_parameters . set_param (
" mail_relocation_move_followers " , record . move_followers or " "
)
class ResPartner ( models . Model ) :
class ResPartner ( models . Model ) :
_inherit = ' res.partner '
_inherit = " res.partner "
@api.model
@api.model
def create ( self , vals ) :
def create ( self , vals ) :
res = super ( ResPartner , self ) . create ( vals )
res = super ( ResPartner , self ) . create ( vals )
if ' update_message_author ' in self . env . context and ' email ' in vals :
mail_message_obj = self . env [ ' mail.message ' ]
if " update_message_author " in self . env . context and " email " in vals :
mail_message_obj = self . env [ " mail.message " ]
# Escape special SQL characters in email_address to avoid invalid matches
# Escape special SQL characters in email_address to avoid invalid matches
email_address = ( vals [ ' email ' ] . replace ( ' \\ ' , ' \\ \\ ' ) . replace ( ' % ' , ' \\ % ' ) . replace ( ' _ ' , ' \\ _ ' ) )
email_address = (
vals [ " email " ]
. replace ( " \\ " , " \\ \\ " )
. replace ( " % " , " \\ % " )
. replace ( " _ " , " \\ _ " )
)
email_brackets = " < %s > " % email_address
email_brackets = " < %s > " % email_address
messages = mail_message_obj . search ( [
' | ' ,
( ' email_from ' , ' =ilike ' , email_address ) ,
( ' email_from ' , ' ilike ' , email_brackets ) ,
( ' author_id ' , ' = ' , False )
] )
messages = mail_message_obj . search (
[
" | " ,
( " email_from " , " =ilike " , email_address ) ,
( " email_from " , " ilike " , email_brackets ) ,
( " author_id " , " = " , False ) ,
]
)
if messages :
if messages :
messages . sudo ( ) . write ( { ' author_id ' : res . id } )
messages . sudo ( ) . write ( { " author_id " : res . id } )
return res
return res
@api.model
@api.model
def default_get ( self , default_fields ) :
def default_get ( self , default_fields ) :
contextual_self = self
contextual_self = self
if ' mail_move_message ' in self . env . context and self . env . context [ ' mail_move_message ' ] :
if (
" mail_move_message " in self . env . context
and self . env . context [ " mail_move_message " ]
) :
contextual_self = self . with_context (
contextual_self = self . with_context (
default_name = self . env . context [ ' message_name_from ' ] or ' ' ,
default_email = self . env . context [ ' message_email_from ' ] or ' ' ,
default_name = self . env . context [ " message_name_from " ] or " " ,
default_email = self . env . context [ " message_email_from " ] or " " ,
)
)
return super ( ResPartner , contextual_self ) . default_get ( default_fields )
return super ( ResPartner , contextual_self ) . default_get ( default_fields )