254 lines
12 KiB
Python
254 lines
12 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
|
|
|
import werkzeug
|
|
|
|
from datetime import datetime
|
|
from dateutil import relativedelta
|
|
|
|
from flectra import http, fields, tools, _
|
|
from flectra.http import request
|
|
from flectra.addons.http_routing.models.ir_http import slug
|
|
|
|
|
|
class MailGroup(http.Controller):
|
|
_thread_per_page = 20
|
|
_replies_per_page = 10
|
|
|
|
def _get_archives(self, group_id):
|
|
MailMessage = request.env['mail.message']
|
|
groups = MailMessage._read_group_raw(
|
|
[('model', '=', 'mail.channel'), ('res_id', '=', group_id), ('message_type', '!=', 'notification')],
|
|
['subject', 'date'],
|
|
groupby=["date"], orderby="date desc")
|
|
for group in groups:
|
|
(r, label) = group['date']
|
|
start, end = r.split('/')
|
|
group['date'] = label
|
|
group['date_begin'] = self._to_date(start)
|
|
group['date_end'] = self._to_date(end)
|
|
return groups
|
|
|
|
def _to_date(self, dt):
|
|
""" date is (of course) a datetime so start and end are datetime
|
|
strings, but we just want date strings
|
|
"""
|
|
return (datetime
|
|
.strptime(dt, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
|
.date() # may be unnecessary?
|
|
.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
|
|
|
|
@http.route("/groups", type='http', auth="public", website=True)
|
|
def view(self, **post):
|
|
groups = request.env['mail.channel'].search([('alias_id.alias_name', '!=', False)])
|
|
|
|
# compute statistics
|
|
month_date = datetime.today() - relativedelta.relativedelta(months=1)
|
|
messages = request.env['mail.message'].read_group(
|
|
[('model', '=', 'mail.channel'), ('date', '>=', fields.Datetime.to_string(month_date)), ('message_type', '!=', 'notification')],
|
|
[], ['res_id'])
|
|
message_data = dict((message['res_id'], message['res_id_count']) for message in messages)
|
|
|
|
group_data = dict((group.id, {'monthly_message_nbr': message_data.get(group.id, 0)}) for group in groups)
|
|
return request.render('website_mail_channel.mail_channels', {'groups': groups, 'group_data': group_data})
|
|
|
|
@http.route(["/groups/is_member"], type='json', auth="public", website=True)
|
|
def is_member(self, channel_id=0, **kw):
|
|
""" Determine if the current user is member of the given channel_id
|
|
:param channel_id : the channel_id to check
|
|
"""
|
|
current_user = request.env.user
|
|
session_partner_id = request.session.get('partner_id')
|
|
public_user = request.website.user_id
|
|
partner = None
|
|
# find the current partner
|
|
if current_user != public_user:
|
|
partner = current_user.partner_id
|
|
elif session_partner_id:
|
|
partner = request.env['res.partner'].sudo().browse(session_partner_id)
|
|
|
|
values = {
|
|
'is_user': current_user != public_user,
|
|
'email': partner.email if partner else "",
|
|
'is_member': False,
|
|
'alias_name': False,
|
|
}
|
|
# check if the current partner is member or not
|
|
channel = request.env['mail.channel'].browse(int(channel_id))
|
|
if channel.exists() and partner is not None:
|
|
values['is_member'] = bool(partner in channel.sudo().channel_partner_ids)
|
|
return values
|
|
|
|
@http.route(["/groups/subscription"], type='json', auth="public", website=True)
|
|
def subscription(self, channel_id=0, subscription="on", email='', **kw):
|
|
""" Subscribe to a mailing list : this will create a partner with its email address (if public user not
|
|
registered yet) and add it as channel member
|
|
:param channel_id : the channel id to join/quit
|
|
:param subscription : 'on' to unsubscribe the user, 'off' to subscribe
|
|
"""
|
|
unsubscribe = subscription == 'on'
|
|
channel = request.env['mail.channel'].browse(int(channel_id))
|
|
partner_ids = []
|
|
|
|
# search partner_id
|
|
if request.env.user != request.website.user_id:
|
|
# connected users are directly (un)subscribed
|
|
partner_ids = request.env.user.partner_id.ids
|
|
|
|
# add or remove channel members
|
|
if unsubscribe:
|
|
channel.check_access_rule('read')
|
|
channel.sudo().write({'channel_partner_ids': [(3, partner_id) for partner_id in partner_ids]})
|
|
return "off"
|
|
else: # add partner to the channel
|
|
request.session['partner_id'] = partner_ids[0]
|
|
channel.check_access_rule('read')
|
|
channel.sudo().write({'channel_partner_ids': [(4, partner_id) for partner_id in partner_ids]})
|
|
return "on"
|
|
|
|
else:
|
|
# public users will recieve confirmation email
|
|
partner_ids = channel.sudo()._find_partner_from_emails([email], check_followers=True)
|
|
if not partner_ids or not partner_ids[0]:
|
|
name = email.split('@')[0]
|
|
partner_ids = [request.env['res.partner'].sudo().create({'name': name, 'email': email}).id]
|
|
|
|
channel.sudo()._send_confirmation_email(partner_ids, unsubscribe)
|
|
return "email"
|
|
|
|
@http.route([
|
|
'''/groups/<model('mail.channel', "[('channel_type', '=', 'channel')]"):group>''',
|
|
'''/groups/<model('mail.channel'):group>/page/<int:page>'''
|
|
], type='http', auth="public", website=True)
|
|
def thread_headers(self, group, page=1, mode='thread', date_begin=None, date_end=None, **post):
|
|
if group.channel_type != 'channel':
|
|
raise werkzeug.exceptions.NotFound()
|
|
|
|
Message = request.env['mail.message']
|
|
|
|
domain = [('model', '=', 'mail.channel'), ('res_id', '=', group.id), ('message_type', '!=', 'notification')]
|
|
if mode == 'thread':
|
|
domain += [('parent_id', '=', False)]
|
|
if date_begin and date_end:
|
|
domain += [('date', '>=', date_begin), ('date', '<=', date_end)]
|
|
|
|
pager = request.website.pager(
|
|
url='/groups/%s' % slug(group),
|
|
total=Message.search_count(domain),
|
|
page=page,
|
|
step=self._thread_per_page,
|
|
url_args={'mode': mode, 'date_begin': date_begin or '', 'date_end': date_end or ''},
|
|
)
|
|
messages = Message.search(domain, limit=self._thread_per_page, offset=pager['offset'])
|
|
values = {
|
|
'messages': messages,
|
|
'group': group,
|
|
'pager': pager,
|
|
'mode': mode,
|
|
'archives': self._get_archives(group.id),
|
|
'date_begin': date_begin,
|
|
'date_end': date_end,
|
|
'replies_per_page': self._replies_per_page,
|
|
}
|
|
return request.render('website_mail_channel.group_messages', values)
|
|
|
|
@http.route([
|
|
'''/groups/<model('mail.channel', "[('channel_type', '=', 'channel')]"):group>/<model('mail.message', "[('model','=','mail.channel'), ('res_id','=',group[0])]"):message>''',
|
|
], type='http', auth="public", website=True)
|
|
def thread_discussion(self, group, message, mode='thread', date_begin=None, date_end=None, **post):
|
|
if group.channel_type != 'channel':
|
|
raise werkzeug.exceptions.NotFound()
|
|
|
|
Message = request.env['mail.message']
|
|
if mode == 'thread':
|
|
base_domain = [('model', '=', 'mail.channel'), ('res_id', '=', group.id), ('parent_id', '=', message.parent_id and message.parent_id.id or False)]
|
|
else:
|
|
base_domain = [('model', '=', 'mail.channel'), ('res_id', '=', group.id)]
|
|
next_message = Message.search(base_domain + [('date', '<', message.date)], order="date DESC", limit=1) or None
|
|
prev_message = Message.search(base_domain + [('date', '>', message.date)], order="date", limit=1) or None
|
|
values = {
|
|
'message': message,
|
|
'group': group,
|
|
'mode': mode,
|
|
'archives': self._get_archives(group.id),
|
|
'date_begin': date_begin,
|
|
'date_end': date_end,
|
|
'replies_per_page': self._replies_per_page,
|
|
'next_message': next_message,
|
|
'prev_message': prev_message,
|
|
}
|
|
return request.render('website_mail_channel.group_message', values)
|
|
|
|
@http.route(
|
|
'''/groups/<model('mail.channel', "[('channel_type', '=', 'channel')]"):group>/<model('mail.message', "[('model','=','mail.channel'), ('res_id','=',group[0])]"):message>/get_replies''',
|
|
type='json', auth="public", methods=['POST'], website=True)
|
|
def render_messages(self, group, message, **post):
|
|
if group.channel_type != 'channel':
|
|
return False
|
|
|
|
last_displayed_id = post.get('last_displayed_id')
|
|
if not last_displayed_id:
|
|
return False
|
|
|
|
replies_domain = [('id', '<', int(last_displayed_id)), ('parent_id', '=', message.id)]
|
|
messages = request.env['mail.message'].search(replies_domain, limit=self._replies_per_page)
|
|
message_count = request.env['mail.message'].search_count(replies_domain)
|
|
values = {
|
|
'group': group,
|
|
'thread_header': message,
|
|
'messages': messages,
|
|
'msg_more_count': message_count - self._replies_per_page,
|
|
'replies_per_page': self._replies_per_page,
|
|
}
|
|
return request.env.ref('website_mail_channel.messages_short').render(values, engine='ir.qweb')
|
|
|
|
@http.route("/groups/<model('mail.channel'):group>/get_alias_info", type='json', auth='public', website=True)
|
|
def get_alias_info(self, group, **post):
|
|
return {
|
|
'alias_name': group.alias_id and group.alias_id.alias_name and group.alias_id.alias_domain and '%s@%s' % (group.alias_id.alias_name, group.alias_id.alias_domain) or False
|
|
}
|
|
|
|
@http.route("/groups/subscribe/<model('mail.channel'):channel>/<int:partner_id>/<string:token>", type='http', auth='public', website=True)
|
|
def confirm_subscribe(self, channel, partner_id, token, **kw):
|
|
subscriber = request.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', partner_id)])
|
|
if subscriber:
|
|
# already registered, maybe clicked twice
|
|
return request.render('website_mail_channel.invalid_token_subscription')
|
|
|
|
subscriber_token = channel._generate_action_token(partner_id, action='subscribe')
|
|
if token != subscriber_token:
|
|
return request.render('website_mail_channel.invalid_token_subscription')
|
|
|
|
# add partner
|
|
channel.sudo().write({'channel_partner_ids': [(4, partner_id)]})
|
|
|
|
return request.render("website_mail_channel.confirmation_subscription", {'subscribing': True})
|
|
|
|
@http.route("/groups/unsubscribe/<model('mail.channel'):channel>/<int:partner_id>/<string:token>", type='http', auth='public', website=True)
|
|
def confirm_unsubscribe(self, channel, partner_id, token, **kw):
|
|
subscriber = request.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', partner_id)])
|
|
if not subscriber:
|
|
partner = request.env['res.partner'].browse(partner_id).sudo().exists()
|
|
# FIXME: remove try/except in master
|
|
try:
|
|
response = request.render(
|
|
'website_mail_channel.not_subscribed',
|
|
{'partner_id': partner})
|
|
# make sure the rendering (and thus error if template is
|
|
# missing) happens inside the try block
|
|
response.flatten()
|
|
return response
|
|
except ValueError:
|
|
return _("The address %s is already unsubscribed or was never subscribed to any mailing list") % (
|
|
partner.email
|
|
)
|
|
|
|
subscriber_token = channel._generate_action_token(partner_id, action='unsubscribe')
|
|
if token != subscriber_token:
|
|
return request.render('website_mail_channel.invalid_token_subscription')
|
|
|
|
# remove partner
|
|
channel.sudo().write({'channel_partner_ids': [(3, partner_id)]})
|
|
|
|
return request.render("website_mail_channel.confirmation_subscription", {'subscribing': False})
|