[IMP]: code
[odoo/odoo.git] / addons / website_blog / controllers / main.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from openerp.addons.web import http
23 from openerp.addons.web.http import request
24 from openerp.tools.translate import _
25 from openerp import SUPERUSER_ID
26
27 import werkzeug
28 import random
29 import json
30 from datetime import datetime
31 import random
32
33 from openerp.tools import html2plaintext
34 import email.utils
35
36 class WebsiteBlog(http.Controller):
37     _blog_post_per_page = 20
38     _post_comment_per_page = 10
39
40     def nav_list(self):
41         blog_post_obj = request.registry['blog.post']
42         groups = blog_post_obj.read_group(request.cr, request.uid, [], ['name', 'create_date'],
43             groupby="create_date", orderby="create_date asc", context=request.context)
44         for group in groups:
45             group['date'] = "%s_%s" % (group['__domain'][0][2], group['__domain'][1][2])
46         return groups
47
48     @http.route([
49         '/blog',
50         '/blog/page/<int:page>',
51     ], type='http', auth="public", website=True, multilang=True)
52     def blogs(self, page=1):
53         BYPAGE = 60
54         cr, uid, context = request.cr, request.uid, request.context
55         blog_obj = request.registry['blog.post']
56         total = blog_obj.search(cr, uid, [], count=True, context=context)
57         pager = request.website.pager(
58             url='/blog/',
59             total=total,
60             page=page,
61             step=BYPAGE,
62         )
63         bids = blog_obj.search(cr, uid, [], offset=pager['offset'], limit=BYPAGE, context=context)
64         blogs = blog_obj.browse(cr, uid, bids, context=context)
65         return request.website.render("website_blog.latest_blogs", {
66             'blogs': blogs,
67             'pager': pager
68         })
69
70     @http.route([
71         '/blog/<model("blog.blog"):blog>',
72         '/blog/<model("blog.blog"):blog>/page/<int:page>',
73         '/blog/<model("blog.blog"):blog>/tag/<model("blog.tag"):tag>',
74         '/blog/<model("blog.blog"):blog>/tag/<model("blog.tag"):tag>/page/<int:page>',
75         '/blog/<model("blog.blog"):blog>/date/<string(length=21):date>',
76         '/blog/<model("blog.blog"):blog>/date/<string(length=21):date>/page/<int:page>',
77         '/blog/<model("blog.blog"):blog>/tag/<model("blog.tag"):tag>/date/<string(length=21):date>',
78         '/blog/<model("blog.blog"):blog>/tag/<model("blog.tag"):tag>/date/<string(length=21):date>/page/<int:page>',
79     ], type='http', auth="public", website=True, multilang=True)
80     def blog(self, blog=None, tag=None, date=None, page=1, **opt):
81         """ Prepare all values to display the blog.
82
83         :param blog: blog currently browsed.
84         :param tag: tag that is currently used to filter blog posts
85         :param integer page: current page of the pager. Can be the blog or
86                             post pager.
87         :param date: date currently used to filter blog posts (dateBegin_dateEnd)
88
89         :return dict values: values for the templates, containing
90
91          - 'blog_posts': list of browse records that are the posts to display
92                          in a given blog, if not blog_post_id
93          - 'blog': browse of the current blog, if blog_id
94          - 'blogs': list of browse records of blogs
95          - 'pager': the pager to display posts pager in a blog
96          - 'tag': current tag, if tag_idemail.utils.parseaddr
97          - 'nav_list': a dict [year][month] for archives navigation
98         """
99         cr, uid, context = request.cr, request.uid, request.context
100         blog_post_obj = request.registry['blog.post']
101
102         blog_obj = request.registry['blog.blog']
103         blog_ids = blog_obj.search(cr, uid, [], context=context)
104         blogs = blog_obj.browse(cr, uid, blog_ids, context=context)
105
106         path_filter = ""
107         domain = []
108         if blog:
109             path_filter += "%s/" % blog.id
110             domain += [("blog_id", "=", [blog.id])]
111         if tag:
112             path_filter += 'tag/%s/' % tag.id
113             domain += [("tag_ids", "in", [tag.id])]
114         if date:
115             path_filter += "date/%s/" % date
116             domain += [("create_date", ">=", date.split("_")[0]), ("create_date", "<=", date.split("_")[1])]
117
118         blog_post_count = blog_post_obj.search(cr, uid, domain, count=True, context=context)
119         pager = request.website.pager(
120             url="/blog/%s" % path_filter,
121             total=blog_post_count,
122             page=page,
123             step=self._blog_post_per_page,
124             scope=10
125         )
126         blog_post_ids = blog_post_obj.search(cr, uid, domain, context=context, limit=self._blog_post_per_page, offset=pager['offset'])
127         blog_posts = blog_post_obj.browse(cr, uid, blog_post_ids, context=context)
128
129         tag_obj = request.registry['blog.tag']
130         tag_ids = tag_obj.search(cr, uid, [], context=context)
131         tags = tag_obj.browse(cr, uid, tag_ids, context=context)
132
133         values = {
134             'blog': blog,
135             'blogs': blogs,
136             'tags': tags,
137             'tag': tag,
138             'blog_posts': blog_posts,
139             'pager': pager,
140             'nav_list': self.nav_list(),
141             'path_filter': path_filter,
142             'date': date,
143         }
144         response = request.website.render("website_blog.blog_post_short", values)
145         return response
146
147     @http.route([
148         '/blog/<model("blog.blog"):blog>/post/<model("blog.post"):blog_post>',
149     ], type='http', auth="public", website=True, multilang=True)
150     def blog_post(self, blog, blog_post, enable_editor=None, **post):
151         """ Prepare all values to display the blog.
152
153         :param blog_post: blog post currently browsed. If not set, the user is
154                           browsing the blog and a post pager is calculated.
155                           If set the user is reading the blog post and a
156                           comments pager is calculated.
157         :param blog: blog currently browsed.
158         :param tag: tag that is currently used to filter blog posts
159         :param integer page: current page of the pager. Can be the blog or
160                             post pager.
161         :param date: date currently used to filter blog posts (dateBegin_dateEnd)
162
163          - 'enable_editor': editor control
164
165         :return dict values: values for the templates, containing
166
167          - 'blog_post': browse of the current post, if blog_post_id
168          - 'blog': browse of the current blog, if blog_id
169          - 'blogs': list of browse records of blogs
170          - 'pager': the pager to display comments pager in a blog post
171          - 'tag': current tag, if tag_id
172          - 'nav_list': a dict [year][month] for archives navigation
173          - 'next_blog': next blog post , display in footer
174         """
175         cr, uid, context = request.cr, request.uid, request.context
176         if not blog_post.blog_id.id==blog.id:
177             return request.redirect("/blog/%s/post/%s" % (blog_post.blog_id.id, blog_post.id))
178         blog_post_obj = request.registry.get('blog.post')
179
180         # Find next Post
181         visited_blogs = request.httprequest.cookies.get('visited_blogs') or ''
182         visited_ids = filter(None, visited_blogs.split(','))
183         visited_ids = map(lambda x: int(x), visited_ids)
184         if blog_post.id not in visited_ids:
185             visited_ids.append(blog_post.id)
186         next_post_id = blog_post_obj.search(cr, uid, [
187             ('id', 'not in', visited_ids),
188             ], order='ranking desc', limit=1, context=context)
189         next_post = next_post_id and blog_post_obj.browse(cr, uid, next_post_id[0], context=context) or False
190
191         values = {
192             'blog': blog,
193             'blog_post': blog_post,
194             'main_object': blog_post,
195             'enable_editor': enable_editor,
196             'next_post' : next_post,
197         }
198         response = request.website.render("website_blog.blog_post_complete", values)
199         response.set_cookie('visited_blogs', ','.join(map(str, visited_ids)))
200
201         # Increase counter and ranking ratio for order
202         d = datetime.now() - datetime.strptime(blog_post.create_date, "%Y-%m-%d %H:%M:%S")
203         blog_post_obj.write(cr, SUPERUSER_ID, [blog_post.id], {
204             'visits': blog_post.visits+1,
205             'ranking': blog_post.visits * (0.5+random.random()) / max(3, d.days)
206         },context=context)
207         return response
208
209     def _blog_post_message(self, user, blog_post_id=0, **post):
210         cr, uid, context = request.cr, request.uid, request.context
211         blog_post = request.registry['blog.post']
212         message_id = blog_post.message_post(
213             cr, SUPERUSER_ID, int(blog_post_id),
214             body=post.get('comment'),
215             type='comment',
216             subtype='mt_comment',
217             email_from = "%s <%s>" % (post.get('name'), post.get('email')),
218             author_id=user.partner_id.id if request.session.uid else False,
219             discussion=post.get('discussion'),
220             context=dict(context, mail_create_nosubcribe=True))
221         return message_id
222
223     @http.route(['/blogpost/comment'], type='http', auth="public", methods=['POST'], website=True)
224     def blog_post_comment(self, blog_post_id=0, **post):
225         cr, uid, context = request.cr, request.uid, request.context
226         if post.get('comment'):
227             user = request.registry['res.users'].browse(cr, uid, uid, context=context)
228             blog_post = request.registry['blog.post']
229             blog_post.check_access_rights(cr, uid, 'read')
230             self._blog_post_message(user, blog_post_id, **post)
231         return werkzeug.utils.redirect(request.httprequest.referrer + "#comments")
232
233     def _get_discussion_detail(self, ids, publish=False, **post):
234         cr, uid, context = request.cr, request.uid, request.context
235         values = []
236         mail_obj = request.registry.get('mail.message')
237         for message in mail_obj.browse(cr, SUPERUSER_ID, ids, context=context):
238             values.append({
239                 "id": message.id,
240                 "author_name": message.author_id and message.author_id.name or email.utils.parseaddr(message.email_from)[0],
241                 "author_image": message.author_id and \
242                     ("data:image/png;base64,%s" % message.author_id.image) or \
243                     '/website_blog/static/src/img/anonymous.png',
244                 "date": message.date,
245                 'body': html2plaintext(message.body),
246                 'website_published' : message.website_published,
247                 'publish' : publish,
248             })
249         return values
250
251     @http.route(['/blogpost/post_discussion'], type='json', auth="public", website=True)
252     def post_discussion(self, blog_post_id=0, **post):
253         cr, uid, context = request.cr, request.uid, request.context
254         publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher')
255         user = request.registry['res.users'].browse(cr, uid, uid, context=context)
256         id = self._blog_post_message(user, blog_post_id, **post)
257         return self._get_discussion_detail([id], publish, **post)
258     
259     @http.route('/blogpost/new', type='http', auth="public", website=True, multilang=True)
260     def blog_post_create(self, blog_id, **post):
261         cr, uid, context = request.cr, request.uid, request.context
262         create_context = dict(context, mail_create_nosubscribe=True)
263         new_blog_post_id = request.registry['blog.post'].create(cr, uid, {
264                 'blog_id': blog_id,
265                 'name': _("Blog Post Title"),
266                 'sub_title': _("Subtitle"),
267                 'content': '',
268                 'website_published': False,
269             }, context=create_context)
270         return werkzeug.utils.redirect("/blog/%s/post/%s/?enable_editor=1" % (blog_id, new_blog_post_id))
271
272     @http.route('/blogpost/duplicate', type='http', auth="public", website=True)
273     def blog_post_copy(self, blog_post_id, **post):
274         """ Duplicate a blog.
275
276         :param blog_post_id: id of the blog post currently browsed.
277
278         :return redirect to the new blog created
279         """
280         cr, uid, context = request.cr, request.uid, request.context
281         create_context = dict(context, mail_create_nosubscribe=True)
282         nid = request.registry['blog.post'].copy(cr, uid, blog_post_id, {}, context=create_context)
283         post = request.registry['blog.post'].browse(cr, uid, nid, context)
284         return werkzeug.utils.redirect("/blog/%s/post/%s/?enable_editor=1" % (post.blog_id.id, nid))
285
286     @http.route('/blogpost/get_discussion/', type='json', auth="public", website=True)
287     def discussion(self, post_id=0, discussion=None, count=False, **post):
288         cr, uid, context = request.cr, request.uid, request.context
289         mail_obj = request.registry.get('mail.message')
290         domain = [('res_id', '=', int(post_id)) ,('model','=','blog.post'), ('discussion', '=', discussion)]
291         #check current user belongs to website publisher group
292         publish = request.registry['res.users'].has_group(cr, uid, 'base.group_website_publisher')
293         if not publish:
294             domain.append(('website_published', '=', True))
295         ids = mail_obj.search(cr, SUPERUSER_ID, domain, count=count)
296         if count:
297             return ids
298         return self._get_discussion_detail(ids, publish, **post)
299
300     @http.route('/blogpsot/change_background', type='json', auth="public", website=True)
301     def change_bg(self, post_id=0, image=None, **post):
302         post_obj = request.registry.get('blog.post')
303         values = {'content_image' : image}
304
305         ids = post_obj.write(request.cr, request.uid, [int(post_id)], values, request.context)
306         return []
307
308     @http.route('/blog/get_user/', type='json', auth="public", website=True)
309     def get_user(self, **post):
310         return [False if request.session.uid else True]
311