[MIG] website_blog: migrate py files

This commit is contained in:
fwi-odoo
2016-08-10 17:53:49 +02:00
committed by Jeremy Kersten
parent 3b39e7066a
commit 86793a7565
5 changed files with 144 additions and 196 deletions
@@ -1 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import main
+38 -64
View File
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
import json
import werkzeug
from odoo import http, tools, SUPERUSER_ID, _
from odoo import http, fields, _
from odoo.addons.website.controllers.main import QueryURL
from odoo.addons.website.models.website import slug, unslug
from odoo.exceptions import UserError
@@ -18,8 +17,7 @@ class WebsiteBlog(http.Controller):
_post_comment_per_page = 10
def nav_list(self, blog=None):
blog_post_obj = request.env['blog.post']
groups = blog_post_obj._read_group_raw(
groups = request.env['blog.post']._read_group_raw(
blog and [('blog_id', '=', blog.id)] or [],
['name', 'create_date'],
groupby=["create_date"], orderby="create_date desc")
@@ -35,27 +33,22 @@ class WebsiteBlog(http.Controller):
""" create_date is a datetime so start and end are datetime strings,
but we just want date strings
"""
return (datetime.datetime
.strptime(dt, tools.DEFAULT_SERVER_DATETIME_FORMAT)
.date() # may be unnecessary?
.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
return fields.Date.from_string(dt)
@http.route([
'/blog',
'/blog/page/<int:page>',
], type='http', auth="public", website=True)
def blogs(self, page=1, **post):
cr, uid, context = request.cr, request.uid, request.context
blog_obj = request.registry['blog.post']
total = blog_obj.search(cr, uid, [], count=True, context=context)
BlogPost = request.env['blog.post']
total = BlogPost.search([], count=True)
pager = request.website.pager(
url='/blog',
total=total,
page=page,
step=self._blog_post_per_page,
)
post_ids = blog_obj.search(cr, uid, [], offset=(page-1)*self._blog_post_per_page, limit=self._blog_post_per_page, context=context)
posts = blog_obj.browse(cr, uid, post_ids, context=context)
posts = BlogPost.search([], offset=(page-1)*self._blog_post_per_page, limit=self._blog_post_per_page)
blog_url = QueryURL('', ['blog', 'tag'])
return request.render("website_blog.latest_blogs", {
'posts': posts,
@@ -88,12 +81,10 @@ class WebsiteBlog(http.Controller):
date_begin, date_end, state = opt.get('date_begin'), opt.get('date_end'), opt.get('state')
published_count, unpublished_count = 0, 0
cr, uid, context = request.cr, request.uid, request.context
blog_post_obj = request.registry['blog.post']
BlogPost = request.env['blog.post']
blog_obj = request.registry['blog.blog']
blog_ids = blog_obj.search(cr, uid, [], order="create_date asc", context=context)
blogs = blog_obj.browse(cr, uid, blog_ids, context=context)
Blog = request.env['blog.blog']
blogs = Blog.search([], order="create_date asc")
# build the domain for blog post to display
domain = []
@@ -107,7 +98,7 @@ class WebsiteBlog(http.Controller):
domain += [("create_date", ">=", date_begin), ("create_date", "<=", date_end)]
if request.env.user.has_group('base.group_website_designer'):
for group in request.env['blog.post'].read_group(domain, ['website_published'], groupby=["website_published"]):
for group in BlogPost.read_group(domain, ['website_published'], groupby=["website_published"]):
if group['website_published']:
published_count = group['website_published_count']
else:
@@ -119,8 +110,7 @@ class WebsiteBlog(http.Controller):
blog_url = QueryURL('', ['blog', 'tag'], blog=blog, tag=tag, date_begin=date_begin, date_end=date_end)
blog_post_ids = blog_post_obj.search(cr, uid, domain, order="published_date desc, create_date desc", context=context)
blog_posts = blog_post_obj.browse(cr, uid, blog_post_ids, context=context)
blog_posts = BlogPost.search(domain, order="published_date desc, create_date desc")
pager = request.website.pager(
url=blog_url(),
total=len(blog_posts),
@@ -141,7 +131,7 @@ class WebsiteBlog(http.Controller):
tag_ids.remove(current_tag)
else:
tag_ids.append(current_tag)
tag_ids = request.registry['blog.tag'].browse(cr, uid, tag_ids, context=context).exists()
tag_ids = request.env['blog.tag'].browse(tag_ids).exists()
return ','.join(map(slug, tag_ids))
values = {
@@ -187,9 +177,7 @@ class WebsiteBlog(http.Controller):
- 'nav_list': a dict [year][month] for archives navigation
- 'next_post': next blog post, to direct the user towards the next interesting post
"""
cr, uid, context = request.cr, request.uid, request.context
tag_obj = request.registry['blog.tag']
blog_post_obj = request.registry['blog.post']
BlogPost = request.env['blog.post']
date_begin, date_end = post.get('date_begin'), post.get('date_end')
pager_url = "/blogpost/%s" % blog_post.id
@@ -213,15 +201,15 @@ class WebsiteBlog(http.Controller):
if not blog_post.blog_id.id == blog.id:
return request.redirect("/blog/%s/post/%s" % (slug(blog_post.blog_id), slug(blog_post)))
tags = tag_obj.browse(cr, uid, tag_obj.search(cr, uid, [], context=context), context=context)
tags = request.env['blog.tag'].search([])
# Find next Post
all_post_ids = blog_post_obj.search(cr, uid, [('blog_id', '=', blog.id)], context=context)
all_post_ids = BlogPost.search([('blog_id', '=', blog.id)]).ids
# should always return at least the current post
current_blog_post_index = all_post_ids.index(blog_post.id)
next_post_id = all_post_ids[0 if current_blog_post_index == len(all_post_ids) - 1 \
else current_blog_post_index + 1]
next_post = next_post_id and blog_post_obj.browse(cr, uid, next_post_id, context=context) or False
next_post = next_post_id and BlogPost.browse(next_post_id) or False
values = {
'tags': tags,
@@ -245,37 +233,32 @@ class WebsiteBlog(http.Controller):
if not (blog_post.id in request.session[request.session_id]):
request.session[request.session_id].append(blog_post.id)
# Increase counter
blog_post_obj.write(cr, SUPERUSER_ID, [blog_post.id], {
blog_post.sudo().write({
'visits': blog_post.visits+1,
},context=context)
})
return response
def _blog_post_message(self, blog_post_id, message_content, **post):
cr, uid, context = request.cr, request.uid, request.context
BlogPost = request.registry['blog.post']
User = request.registry['res.users']
BlogPost = request.env['blog.post']
# for now, only portal and user can post comment on blog post.
if uid == request.website.user_id.id:
if request.env.user.id == request.website.user_id.id:
raise UserError(_('Public user cannot post comments on blog post.'))
# get the partner of the current user
user = User.browse(cr, uid, uid, context=context)
partner_id = user.partner_id.id
partner_id = request.env.user.partner_id.id
message_id = BlogPost.message_post(
cr, uid, int(blog_post_id),
message = BlogPost.message_post(
int(blog_post_id),
body=message_content,
message_type='comment',
subtype='mt_comment',
author_id=partner_id,
path=post.get('path', False),
context=context)
return message_id
)
return message.id
def _get_discussion_detail(self, ids, publish=False, **post):
cr, uid, context = request.cr, request.uid, request.context
values = []
mail_obj = request.registry.get('mail.message')
for message in mail_obj.browse(cr, SUPERUSER_ID, ids, context=context):
for message in request.env['mail.message'].sudo().browse(ids):
values.append({
"id": message.id,
"author_name": message.author_id.name,
@@ -291,19 +274,16 @@ class WebsiteBlog(http.Controller):
@http.route(['/blog/post_discussion'], type='json', auth="public", website=True)
def post_discussion(self, blog_post_id, **post):
cr, uid = request.cr, request.uid
publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher')
id = self._blog_post_message(blog_post_id, post.get('comment'), **post)
return self._get_discussion_detail([id], publish, **post)
publish = request.env.user.has_group('base.group_website_publisher')
message_id = self._blog_post_message(blog_post_id, post.get('comment'), **post)
return self._get_discussion_detail([message_id], publish, **post)
@http.route('/blog/<int:blog_id>/post/new', type='http', auth="public", website=True)
def blog_post_create(self, blog_id, **post):
cr, uid, context = request.cr, request.uid, request.context
new_blog_post_id = request.registry['blog.post'].create(cr, uid, {
new_blog_post = request.env['blog.post'].create({
'blog_id': blog_id,
'website_published': False,
}, context=context)
new_blog_post = request.registry['blog.post'].browse(cr, uid, new_blog_post_id, context=context)
})
return werkzeug.utils.redirect("/blog/%s/post/%s?enable_editor=1" % (slug(new_blog_post.blog_id), slug(new_blog_post)))
@http.route('/blog/post_duplicate', type='http', auth="public", website=True, methods=['POST'])
@@ -314,26 +294,20 @@ class WebsiteBlog(http.Controller):
:return redirect to the new blog created
"""
cr, uid, context = request.cr, request.uid, request.context
create_context = dict(context, mail_create_nosubscribe=True)
nid = request.registry['blog.post'].copy(cr, uid, int(blog_post_id), {}, context=create_context)
new_blog_post = request.registry['blog.post'].browse(cr, uid, nid, context=context)
post = request.registry['blog.post'].browse(cr, uid, nid, context)
return werkzeug.utils.redirect("/blog/%s/post/%s?enable_editor=1" % (slug(post.blog_id), slug(new_blog_post)))
new_blog_post = request.env['blog.post'].with_context(mail_create_nosubscribe=True).copy(int(blog_post_id), {})
return werkzeug.utils.redirect("/blog/%s/post/%s?enable_editor=1" % (slug(new_blog_post.blog_id), slug(new_blog_post)))
@http.route('/blog/post_get_discussion/', type='json', auth="public", website=True)
def discussion(self, post_id=0, path=None, count=False, **post):
cr, uid, context = request.cr, request.uid, request.context
mail_obj = request.registry.get('mail.message')
domain = [('res_id', '=', int(post_id)), ('model', '=', 'blog.post'), ('path', '=', path)]
#check current user belongs to website publisher group
publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher')
publish = request.env.user.has_group('base.group_website_publisher')
if not publish:
domain.append(('website_published', '=', True))
ids = mail_obj.search(cr, SUPERUSER_ID, domain, count=count)
messages = request.env['mail.message'].sudo().search(domain, count=count)
if count:
return ids
return self._get_discussion_detail(ids, publish, **post)
return messages.ids
return self._get_discussion_detail(messages.ids, publish, **post)
@http.route('/blog/post_get_discussions/', type='json', auth="public", website=True)
def discussions(self, post_id=0, paths=None, count=False, **post):
@@ -347,7 +321,7 @@ class WebsiteBlog(http.Controller):
def change_bg(self, post_id=0, cover_properties={}, **post):
if not post_id:
return False
return request.registry['blog.post'].write(request.cr, request.uid, [int(post_id)], {'cover_properties': json.dumps(cover_properties)}, request.context)
return request.env['blog.post'].browse(int(post_id)).write({'cover_properties': json.dumps(cover_properties)})
@http.route('/blog/get_user/', type='json', auth="public", website=True)
def get_user(self, **post):
+3
View File
@@ -1,3 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import mail_message
import website
import website_blog
+5 -7
View File
@@ -1,14 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.osv import osv, fields
from odoo import fields, models
class MailMessage(osv.Model):
class MailMessage(models.Model):
_inherit = 'mail.message'
_columns = {
'path': fields.char(
'Discussion Path', select=1,
help='Used to display messages in a paragraph-based chatter using a unique path;'),
}
path = fields.Char(
'Discussion Path', index=True,
help='Used to display messages in a paragraph-based chatter using a unique path;')
+95 -125
View File
@@ -5,39 +5,35 @@ import lxml
import random
from datetime import datetime
from odoo import api, tools, SUPERUSER_ID
from odoo import api, models, fields, _
from odoo.addons.website.models.website import slug
from odoo.osv import osv, fields
from odoo.tools.translate import _, html_translate
from odoo.tools.translate import html_translate
class Blog(osv.Model):
class Blog(models.Model):
_name = 'blog.blog'
_description = 'Blogs'
_inherit = ['mail.thread', 'website.seo.metadata']
_order = 'name'
_columns = {
'name': fields.char('Blog Name', required=True, translate=True),
'subtitle': fields.char('Blog Subtitle', translate=True),
'active': fields.boolean('Active'),
}
_defaults = {
'active': True,
}
name = fields.Char('Blog Name', required=True, translate=True)
subtitle = fields.Char('Blog Subtitle', translate=True)
active = fields.Boolean('Active', default=True)
def write(self, cr, uid, ids, vals, context=None):
res = super(Blog, self).write(cr, uid, ids, vals, context=context)
@api.multi
def write(self, vals):
res = super(Blog, self).write(vals)
if 'active' in vals:
# archiving/unarchiving a blog does it on its posts, too
BlogPost = self.pool['blog.post']
ctx = dict(context or {}, active_test=False)
post_ids = BlogPost.search(cr, uid, [('blog_id', 'in', ids)], context=ctx)
BlogPost.write(cr, uid, post_ids, {'active': vals['active']}, context=context)
post_ids = self.env['blog.post'].with_context(active_test=False).search([
('blog_id', 'in', self)
])
post_ids.write({'active': vals['active']})
return res
def all_tags(self, cr, uid, ids, min_limit=1, context=None):
@api.model_cr
@api.multi
def all_tags(self, min_limit=1):
req = """
SELECT
p.blog_id, count(*), r.blog_tag_id
@@ -52,35 +48,33 @@ class Blog(osv.Model):
ORDER BY
count(*) DESC
"""
cr.execute(req, [tuple(ids)])
tag_by_blog = {i: [] for i in ids}
for blog_id, freq, tag_id in cr.fetchall():
self._cr.execute(req, [tuple(self.ids)])
tag_by_blog = {i.id: [] for i in self}
for blog_id, freq, tag_id in self._cr.fetchall():
if freq >= min_limit:
tag_by_blog[blog_id].append(tag_id)
tag_obj = self.pool['blog.tag']
BlogTag = self.env['blog.tag']
for blog_id in tag_by_blog:
tag_by_blog[blog_id] = tag_obj.browse(cr, uid, tag_by_blog[blog_id], context=context)
tag_by_blog[blog_id] = BlogTag.browse(tag_by_blog[blog_id])
return tag_by_blog
class BlogTag(osv.Model):
class BlogTag(models.Model):
_name = 'blog.tag'
_description = 'Blog Tag'
_inherit = ['website.seo.metadata']
_order = 'name'
_columns = {
'name': fields.char('Name', required=True),
'post_ids': fields.many2many(
'blog.post', string='Posts',
),
}
name = fields.Char('Name', required=True)
post_ids = fields.Many2many('blog.post', string='Posts')
_sql_constraints = [
('name_uniq', 'unique (name)', "Tag name already exists !"),
('name_uniq', 'unique (name)', "Tag name already exists !"),
]
class BlogPost(osv.Model):
class BlogPost(models.Model):
_name = "blog.post"
_description = "Blog Post"
_inherit = ['mail.thread', 'website.seo.metadata', 'website.published.mixin']
@@ -93,76 +87,50 @@ class BlogPost(osv.Model):
for blog_post in self:
blog_post.website_url = "/blog/%s/post/%s" % (slug(blog_post.blog_id), slug(blog_post))
def _compute_ranking(self, cr, uid, ids, name, arg, context=None):
@api.multi
def _compute_ranking(self):
res = {}
for blog_post in self.browse(cr, uid, ids, context=context):
age = datetime.now() - datetime.strptime(blog_post.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
res[blog_post.id] = blog_post.visits * (0.5+random.random()) / max(3, age.days)
for blog_post in self:
age = datetime.now() - fields.Datetime.from_string(blog_post.create_date)
res[blog_post.id] = blog_post.visits * (0.5 + random.random()) / max(3, age.days)
return res
def _default_content(self, cr, uid, context=None):
def _default_content(self):
return ''' <div class="container">
<section class="mt16 mb16">
<p class="o_default_snippet_text">''' + _("Start writing here...") + '''</p>
</section>
</div> '''
_columns = {
'name': fields.char('Title', required=True, translate=True),
'subtitle': fields.char('Sub Title', translate=True),
'author_id': fields.many2one('res.partner', 'Author'),
'active': fields.boolean('Active'),
'cover_properties': fields.text('Cover Properties'),
'blog_id': fields.many2one(
'blog.blog', 'Blog',
required=True, ondelete='cascade',
),
'tag_ids': fields.many2many(
'blog.tag', string='Tags',
),
'content': fields.html('Content', translate=html_translate, sanitize=False),
'website_message_ids': fields.one2many(
'mail.message', 'res_id',
domain=lambda self: [
'&', '&', ('model', '=', self._name), ('message_type', '=', 'comment'), ('path', '=', False)
],
string='Website Messages',
help="Website communication history",
),
# creation / update stuff
'create_date': fields.datetime(
'Created on',
select=True, readonly=True,
),
'create_uid': fields.many2one(
'res.users', 'Created by',
select=True, readonly=True,
),
'write_date': fields.datetime(
'Last Modified on',
select=True, readonly=True,
),
'write_uid': fields.many2one(
'res.users', 'Last Contributor',
select=True, readonly=True,
),
'published_date': fields.datetime('Published Date'),
'author_avatar': fields.related(
'author_id', 'image_small',
string="Avatar", type="binary"),
'visits': fields.integer('No of Views'),
'ranking': fields.function(_compute_ranking, string='Ranking', type='float'),
}
name = fields.Char('Title', required=True, translate=True, default='')
subtitle = fields.Char('Sub Title', translate=True)
author_id = fields.Many2one('res.partner', 'Author', default=lambda self: self.env.user.partner_id)
active = fields.Boolean('Active', default=True)
cover_properties = fields.Text(
'Cover Properties',
default='{"background-image": "none", "background-color": "oe_none", "opacity": "0.6", "resize_class": ""}')
blog_id = fields.Many2one('blog.blog', 'Blog', required=True, ondelete='cascade')
tag_ids = fields.Many2many('blog.tag', string='Tags')
content = fields.Html('Content', default=_default_content, translate=html_translate, sanitize=False)
website_message_ids = fields.One2many(
'mail.message', 'res_id',
domain=lambda self: [
'&', '&', ('model', '=', self._name), ('message_type', '=', 'comment'), ('path', '=', False)
],
string='Website Messages',
help="Website communication history",
)
# creation / update stuff
create_date = fields.Datetime('Created on', index=True, readonly=True)
create_uid = fields.Many2one('res.users', 'Created by', index=True, readonly=True)
write_date = fields.Datetime('Last Modified on', index=True, readonly=True)
write_uid = fields.Many2one('res.users', 'Last Contributor', index=True, readonly=True)
published_date = fields.Datetime('Published Date')
author_avatar = fields.Binary(related='author_id.image_small', string="Avatar")
visits = fields.Integer('No of Views')
ranking = fields.Float(compute='_compute_ranking', string='Ranking')
_defaults = {
'name': '',
'active': True,
'content': _default_content,
'cover_properties': '{"background-image": "none", "background-color": "oe_none", "opacity": "0.6", "resize_class": ""}',
'author_id': lambda self, cr, uid, ctx=None: self.pool['res.users'].browse(cr, uid, uid, context=ctx).partner_id.id,
}
def html_tag_nodes(self, html, attribute=None, tags=None, context=None):
def html_tag_nodes(self, html, attribute=None, tags=None):
""" Processing of html content to tag paragraphs and set them an unique
ID.
:return result: (html, mappin), where html is the updated html with ID
@@ -210,74 +178,76 @@ class BlogPost(osv.Model):
html = html[5:-6]
return html, mapping
def _postproces_content(self, cr, uid, id, content=None, context=None):
# noguess used to be able to call the method with record = None in the create method
@api.noguess
def _postproces_content(self, record, content=None):
if content is None:
content = self.browse(cr, uid, id, context=context).content
content = self.content
if content is False:
return content
content, mapping = self.html_tag_nodes(content, attribute='data-chatter-id', tags=['p'], context=context)
if id: # not creating
content, mapping = self.html_tag_nodes(content, attribute='data-chatter-id', tags=['p'])
if record: # not creating
existing = [x[0] for x in mapping if x[0]]
msg_ids = self.pool['mail.message'].search(cr, SUPERUSER_ID, [
('res_id', '=', id),
self.env['mail.message'].sudo().search([
('res_id', '=', record.id),
('model', '=', self._name),
('path', 'not in', existing),
('path', '!=', False)
], context=context)
self.pool['mail.message'].unlink(cr, SUPERUSER_ID, msg_ids, context=context)
]).sudo().unlink()
return content
def _check_for_publication(self, cr, uid, ids, vals, context=None):
@api.multi
def _check_for_publication(self, vals):
if vals.get('website_published'):
for post in self.browse(cr, uid, ids, context=context):
for post in self:
post.blog_id.message_post_with_view(
'website_blog.blog_post_template_new_post',
subject=post.name,
values={'post': post},
subtype_id=self.pool['ir.model.data'].xmlid_to_res_id(cr, SUPERUSER_ID, 'website_blog.mt_blog_blog_published'))
subtype_id=self.env['ir.model.data'].sudo().xmlid_to_res_id('website_blog.mt_blog_blog_published'))
return True
return False
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
@api.model
def create(self, vals):
if 'content' in vals:
vals['content'] = self._postproces_content(cr, uid, None, vals['content'], context=context)
create_context = dict(context, mail_create_nolog=True)
post_id = super(BlogPost, self).create(cr, uid, vals, context=create_context)
self._check_for_publication(cr, uid, [post_id], vals, context=context)
vals['content'] = self._postproces_content(None, vals['content'])
post_id = super(BlogPost, self.with_context(mail_create_nolog=True)).create(vals)
post_id._check_for_publication(vals)
return post_id
def write(self, cr, uid, ids, vals, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
@api.multi
def write(self, vals):
self.ensure_one()
if 'content' in vals:
vals['content'] = self._postproces_content(cr, uid, ids[0], vals['content'], context=context)
vals['content'] = self._postproces_content(self, vals['content'])
if 'website_published' in vals:
vals['published_date'] = fields.datetime.now() if vals['website_published'] else False
result = super(BlogPost, self).write(cr, uid, ids, vals, context)
self._check_for_publication(cr, uid, ids, vals, context=context)
vals['published_date'] = fields.Datetime.now() if vals['website_published'] else False
result = super(BlogPost, self).write(vals)
self._check_for_publication(vals)
return result
def get_access_action(self, cr, uid, ids, context=None):
@api.multi
def get_access_action(self):
""" Override method that generated the link to access the document. Instead
of the classic form view, redirect to the post on the website directly """
post = self.browse(cr, uid, ids[0], context=context)
self.ensure_one()
return {
'type': 'ir.actions.act_url',
'url': '/blog/%s/post/%s' % (post.blog_id.id, post.id),
'url': '/blog/%s/post/%s' % (self.blog_id.id, self.id),
'target': 'self',
'res_id': self.id,
}
def _notification_get_recipient_groups(self, cr, uid, ids, message, recipients, context=None):
@api.multi
def _notification_get_recipient_groups(self, message, recipients):
""" Override to set the access button: everyone can see an access button
on their notification email. It will lead on the website view of the
post. """
res = super(BlogPost, self)._notification_get_recipient_groups(cr, uid, ids, message, recipients, context=context)
access_action = self._notification_link_helper(cr, uid, ids, 'view', model=message.model, res_id=message.res_id)
res = super(BlogPost, self)._notification_get_recipient_groups(message, recipients)
access_action = self._notification_link_helper('view', model=message.model, res_id=message.res_id)
for category, data in res.iteritems():
res[category]['button_access'] = {'url': access_action, 'title': _('View Blog Post')}
return res