# -*- coding: utf-8 -*- import datetime import json import werkzeug from openerp import tools from openerp.addons.web import http from openerp.addons.web.http import request from openerp.addons.website.models.website import slug, unslug from openerp.exceptions import UserError from openerp.osv.orm import browse_record from openerp.tools.translate import _ from openerp import SUPERUSER_ID from openerp.tools import html2plaintext class QueryURL(object): def __init__(self, path='', path_args=None, **args): self.path = path self.args = args self.path_args = set(path_args or []) def __call__(self, path=None, path_args=None, **kw): path = path or self.path for k, v in self.args.items(): kw.setdefault(k, v) path_args = set(path_args or []).union(self.path_args) paths, fragments = [], [] for key, value in kw.items(): if value and key in path_args: if isinstance(value, browse_record): paths.append((key, slug(value))) else: paths.append((key, value)) elif value: if isinstance(value, list) or isinstance(value, set): fragments.append(werkzeug.url_encode([(key, item) for item in value])) else: fragments.append(werkzeug.url_encode([(key, value)])) for key, value in paths: path += '/' + key + '/%s' % value if fragments: path += '?' + '&'.join(fragments) return path class WebsiteBlog(http.Controller): _blog_post_per_page = 20 _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( blog and [('blog_id', '=', blog.id)] or [], ['name', 'create_date'], groupby=["create_date"], orderby="create_date desc") for group in groups: (r, label) = group['create_date'] start, end = r.split('/') group['create_date'] = label group['date_begin'] = self._to_date(start) group['date_end'] = self._to_date(end) return groups def _to_date(self, dt): """ 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)) @http.route([ '/blog', '/blog/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) 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) blog_url = QueryURL('', ['blog', 'tag']) return request.website.render("website_blog.latest_blogs", { 'posts': posts, 'pager': pager, 'blog_url': blog_url, }) @http.route([ '/blog/', '/blog//page/', '/blog//tag/', '/blog//tag//page/', ], type='http', auth="public", website=True) def blog(self, blog=None, tag=None, page=1, **opt): """ Prepare all values to display the blog. :return dict values: values for the templates, containing - 'blog': current blog - 'blogs': all blogs for navigation - 'pager': pager of posts - 'active_tag_ids' : list of active tag ids, - 'tags_list' : function to built the comma-separated tag list ids (for the url), - 'tags': all tags, for navigation - 'state_info': state of published/unpublished filter - 'nav_list': a dict [year][month] for archives navigation - 'date': date_begin optional parameter, used in archives navigation - 'blog_url': help object to create URLs """ 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'] 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) # build the domain for blog post to display domain = [] # retrocompatibility to accept tag as slug active_tag_ids = tag and map(int, [unslug(t)[1] for t in tag.split(',')]) or [] if active_tag_ids: domain += [('tag_ids', 'in', active_tag_ids)] if blog: domain += [('blog_id', '=', blog.id)] if date_begin and date_end: 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"]): if group['website_published']: published_count = group['website_published_count'] else: unpublished_count = group['website_published_count'] if state == "published": domain += [("website_published", "=", True)] elif state == "unpublished": domain += [("website_published", "=", False)] 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) pager = request.website.pager( url=blog_url(), total=len(blog_posts), page=page, step=self._blog_post_per_page, ) pager_begin = (page - 1) * self._blog_post_per_page pager_end = page * self._blog_post_per_page blog_posts = blog_posts[pager_begin:pager_end] all_tags = blog.all_tags()[blog.id] # function to create the string list of tag ids, and toggle a given one. # used in the 'Tags Cloud' template. def tags_list(tag_ids, current_tag): tag_ids = list(tag_ids) # required to avoid using the same list if current_tag in tag_ids: 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() return ','.join(map(slug, tag_ids)) values = { 'blog': blog, 'blogs': blogs, 'main_object': blog, 'tags': all_tags, 'state_info': {"state": state, "published": published_count, "unpublished": unpublished_count}, 'active_tag_ids': active_tag_ids, 'tags_list' : tags_list, 'blog_posts': blog_posts, 'pager': pager, 'nav_list': self.nav_list(blog), 'blog_url': blog_url, 'date': date_begin, } response = request.website.render("website_blog.blog_post_short", values) return response @http.route(['/blog//feed'], type='http', auth="public") def blog_feed(self, blog, limit='15'): v = {} v['blog'] = blog v['base_url'] = request.env['ir.config_parameter'].get_param('web.base.url') v['posts'] = request.env['blog.post'].search([('blog_id','=', blog.id)], limit=min(int(limit), 50)) r = request.render("website_blog.blog_feed", v, headers=[('Content-Type', 'application/atom+xml')]) return r @http.route([ '''/blog//post//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, { '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']) def blog_post_copy(self, blog_post_id, **post): """ Duplicate a blog. :param blog_post_id: id of the blog post currently browsed. :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))) @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') if not publish: domain.append(('website_published', '=', True)) ids = mail_obj.search(cr, SUPERUSER_ID, domain, count=count) if count: return ids return self._get_discussion_detail(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): ret = [] for path in paths: result = self.discussion(post_id=post_id, path=path, count=count, **post) ret.append({"path": path, "val": result}) return ret @http.route('/blog/post_change_background', type='json', auth="public", website=True) 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) @http.route('/blog/get_user/', type='json', auth="public", website=True) def get_user(self, **post): return [False if request.session.uid else True]