Merge remote-tracking branch 'gsoc2016/Subtitle-1'
[mediagoblin.git] / mediagoblin / media_types / blog / views.py
CommitLineData
cf46184a
A
1# GNU MediaGoblin -- federated, autonomous media hosting
2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
af8f995f 17import logging
af8f995f
A
18_log = logging.getLogger(__name__)
19
cf46184a
A
20from datetime import datetime
21
e49b7e02
BP
22import six
23
cf46184a 24from werkzeug.exceptions import Forbidden
125d7d1a 25from mediagoblin.tools import pluginapi
cf46184a 26
8c36ec52 27from mediagoblin import mg_globals
cf46184a
A
28
29from mediagoblin.media_types.blog import forms as blog_forms
5cb38a28 30from mediagoblin.media_types.blog.models import Blog, BlogPostData
36990574
BB
31from mediagoblin.media_types.blog.lib import (
32 may_edit_blogpost, set_blogpost_state, get_all_blogposts_of_blog,
33 get_blog_by_slug)
5cb38a28 34
cf46184a
A
35from mediagoblin.decorators import (require_active_login, active_user_from_url,
36 get_media_entry_by_id, user_may_alter_collection,
0b2ea4bb
A
37 get_user_collection, uses_pagination)
38from mediagoblin.tools.pagination import Pagination
cf46184a 39from mediagoblin.tools.response import (render_to_response,
0b2ea4bb 40 redirect, render_404)
cf46184a
A
41from mediagoblin.tools.translate import pass_to_ugettext as _
42from mediagoblin.tools.template import render_template
43from mediagoblin.tools.text import (
0b7c64c8 44 convert_to_tag_list_of_dicts, media_tags_as_string, clean_html,
3e329412 45 cleaned_markdown_conversion)
5cb38a28 46
cf46184a 47from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
d88fcb03 48from mediagoblin.db.models import User, Collection, MediaEntry, LocalUser
af8f995f 49
fa5a13f8
A
50from mediagoblin.notifications import add_comment_subscription
51
cf46184a
A
52
53@require_active_login
af8f995f 54def blog_edit(request):
cf46184a 55 """
0f3bf8d4 56 View for editing an existing blog or creating a new blog
afff1492 57 if user have not exceeded maximum allowed acount of blogs.
cf46184a 58 """
af8f995f
A
59 url_user = request.matchdict.get('user', None)
60 blog_slug = request.matchdict.get('blog_slug', None)
0b7c64c8 61
125d7d1a
AM
62 config = pluginapi.get_config('mediagoblin.media_types.blog')
63 max_blog_count = config['max_blog_count']
af8f995f 64 form = blog_forms.BlogEditForm(request.form)
afff1492 65 # creating a blog
af8f995f
A
66 if not blog_slug:
67 if Blog.query.filter_by(author=request.user.id).count()<max_blog_count:
68 if request.method=='GET':
69 return render_to_response(
70 request,
71 'mediagoblin/blog/blog_edit_create.html',
72 {'form': form,
73 'user' : request.user,
74 'app_config': mg_globals.app_config})
75
76 if request.method=='POST' and form.validate():
77 _log.info("Here")
0b2ea4bb 78 blog = request.db.Blog()
e49b7e02
BP
79 blog.title = six.text_type(form.title.data)
80 blog.description = six.text_type(cleaned_markdown_conversion((form.description.data)))
af8f995f
A
81 blog.author = request.user.id
82 blog.generate_slug()
0b7c64c8 83
af8f995f 84 blog.save()
1d9d9f1c
AM
85 return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
86 user=request.user.username
87 )
cf46184a 88 else:
5c7b2a63
AB
89 messages.add_message(
90 request,
91 messages.ERROR,
92 "Welcome! You already have created maximum number of blogs.")
1d9d9f1c
AM
93 return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
94 user=request.user.username)
cf46184a 95
cf46184a 96
bed960cb 97 #Blog already exists.
cf46184a 98 else:
36990574 99 blog = get_blog_by_slug(request, blog_slug)
afff1492
AM
100 if not blog:
101 return render_404(request)
af8f995f 102 if request.method == 'GET':
af8f995f
A
103 defaults = dict(
104 title = blog.title,
21ac4966 105 description = cleaned_markdown_conversion(blog.description),
0b7c64c8
AM
106 author = request.user.id)
107
af8f995f
A
108 form = blog_forms.BlogEditForm(**defaults)
109
110 return render_to_response(
111 request,
112 'mediagoblin/blog/blog_edit_create.html',
113 {'form': form,
114 'user': request.user,
115 'app_config': mg_globals.app_config})
116 else:
fa5a13f8 117 if request.method == 'POST' and form.validate():
e49b7e02
BP
118 blog.title = six.text_type(form.title.data)
119 blog.description = six.text_type(cleaned_markdown_conversion((form.description.data)))
145a1738
A
120 blog.author = request.user.id
121 blog.generate_slug()
0b7c64c8 122
145a1738 123 blog.save()
5c7b2a63
AB
124 messages.add_message(
125 request,
126 messages.SUCCESS,
127 "Your blog is updated.")
8f6a0bf4
A
128 return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
129 user=request.user.username,
0b7c64c8
AM
130 blog_slug=blog.slug)
131
0b2ea4bb 132
0b7c64c8 133@require_active_login
fa5a13f8 134def blogpost_create(request):
0b7c64c8 135
5cb38a28 136 form = blog_forms.BlogPostEditForm(request.form, license=request.user.license_preference)
0b7c64c8 137
145a1738 138 if request.method == 'POST' and form.validate():
5cb38a28 139 blog_slug = request.matchdict.get('blog_slug')
36990574 140 blog = get_blog_by_slug(request, blog_slug, author=request.user.id)
4cf5b010
A
141 if not blog:
142 return render_404(request)
0b7c64c8 143
5cb38a28 144 blogpost = request.db.MediaEntry()
783b5005 145 blogpost.media_type = 'mediagoblin.media_types.blogpost'
e49b7e02
BP
146 blogpost.title = six.text_type(form.title.data)
147 blogpost.description = six.text_type(cleaned_markdown_conversion((form.description.data)))
145a1738 148 blogpost.tags = convert_to_tag_list_of_dicts(form.tags.data)
e49b7e02 149 blogpost.license = six.text_type(form.license.data) or None
beb5a4a1 150 blogpost.actor = request.user.id
145a1738 151 blogpost.generate_slug()
0b7c64c8 152
4cf5b010 153 set_blogpost_state(request, blogpost)
145a1738 154 blogpost.save()
0b7c64c8 155
5cb38a28
A
156 # connect this blogpost to its blog
157 blog_post_data = request.db.BlogPostData()
158 blog_post_data.blog = blog.id
159 blog_post_data.media_entry = blogpost.id
160 blog_post_data.save()
0b7c64c8 161
5c7b2a63
AB
162 messages.add_message(
163 request,
164 messages.SUCCESS,
165 _('Woohoo! Submitted!'))
145a1738 166 add_comment_subscription(request.user, blogpost)
7b23b1e5
A
167 return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
168 user=request.user.username,
169 blog_slug=blog.slug)
0b7c64c8 170
145a1738 171 return render_to_response(
fa5a13f8
A
172 request,
173 'mediagoblin/blog/blog_post_edit_create.html',
174 {'form': form,
175 'app_config': mg_globals.app_config,
176 'user': request.user.username})
e058cdce
A
177
178
179@require_active_login
180def blogpost_edit(request):
0f3bf8d4 181
8f6a0bf4
A
182 blog_slug = request.matchdict.get('blog_slug', None)
183 blog_post_slug = request.matchdict.get('blog_post_slug', None)
0b7c64c8 184
beb5a4a1 185 blogpost = request.db.MediaEntry.query.filter_by(slug=blog_post_slug, actor=request.user.id).first()
36990574 186 blog = get_blog_by_slug(request, blog_slug, author=request.user.id)
0b7c64c8 187
b5ae9685
A
188 if not blogpost or not blog:
189 return render_404(request)
0b7c64c8 190
5cb38a28
A
191 defaults = dict(
192 title = blogpost.title,
21ac4966 193 description = cleaned_markdown_conversion(blogpost.description),
5cb38a28
A
194 tags=media_tags_as_string(blogpost.tags),
195 license=blogpost.license)
0b7c64c8 196
5cb38a28
A
197 form = blog_forms.BlogPostEditForm(request.form, **defaults)
198 if request.method == 'POST' and form.validate():
e49b7e02
BP
199 blogpost.title = six.text_type(form.title.data)
200 blogpost.description = six.text_type(cleaned_markdown_conversion((form.description.data)))
5cb38a28 201 blogpost.tags = convert_to_tag_list_of_dicts(form.tags.data)
e49b7e02 202 blogpost.license = six.text_type(form.license.data)
4cf5b010 203 set_blogpost_state(request, blogpost)
5cb38a28
A
204 blogpost.generate_slug()
205 blogpost.save()
0b7c64c8 206
5c7b2a63
AB
207 messages.add_message(
208 request,
209 messages.SUCCESS,
210 _('Woohoo! edited blogpost is submitted'))
3e329412
A
211 return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
212 user=request.user.username,
213 blog_slug=blog.slug)
0b7c64c8 214
5cb38a28 215 return render_to_response(
e058cdce
A
216 request,
217 'mediagoblin/blog/blog_post_edit_create.html',
218 {'form': form,
219 'app_config': mg_globals.app_config,
220 'user': request.user.username,
5cb38a28 221 'blog_post_slug': blog_post_slug
0b7c64c8 222 })
e058cdce 223
59614310 224
eebd8fe3 225@active_user_from_url
8762609f 226@uses_pagination
eebd8fe3 227def blog_dashboard(request, page, url_user=None):
afff1492
AM
228 """
229 Dashboard for a blog, only accessible to
230 the owner of the blog.
231 """
4aa7058e 232 blog_slug = request.matchdict.get('blog_slug', None)
eebd8fe3 233 blogs = request.db.Blog.query.filter_by(author=url_user.id)
310c3073
AM
234 config = pluginapi.get_config('mediagoblin.media_types.blog')
235 max_blog_count = config['max_blog_count']
eebd8fe3 236 if request.user and (request.user.id == url_user.id or request.user.has_privilege(u'admin')):
4aa7058e 237 if blog_slug:
36990574 238 blog = get_blog_by_slug(request, blog_slug)
4aa7058e
AM
239 if not blog:
240 return render_404(request)
241 else:
242 blog_posts_list = blog.get_all_blog_posts().order_by(MediaEntry.created.desc())
243 pagination = Pagination(page, blog_posts_list)
244 pagination.per_page = 15
245 blog_posts_on_a_page = pagination()
246 if may_edit_blogpost(request, blog):
247 return render_to_response(
248 request,
249 'mediagoblin/blog/blog_admin_dashboard.html',
250 {'blog_posts_list': blog_posts_on_a_page,
251 'blog_slug':blog_slug,
252 'blog':blog,
eebd8fe3 253 'user':url_user,
0b7c64c8
AM
254 'pagination':pagination
255 })
eebd8fe3 256 if not request.user or request.user.id != url_user.id or not blog_slug:
0b7c64c8 257 blogs = blogs.all()
4aa7058e
AM
258 return render_to_response(
259 request,
260 'mediagoblin/blog/list_of_blogs.html',
261 {
262 'blogs':blogs,
eebd8fe3 263 'user':url_user,
310c3073 264 'max_blog_count':max_blog_count
0b7c64c8
AM
265 })
266
5cb38a28 267
eebd8fe3 268@active_user_from_url
8762609f 269@uses_pagination
eebd8fe3 270def blog_post_listing(request, page, url_user=None):
afff1492
AM
271 """
272 Page, listing all the blog posts of a particular blog.
273 """
51f49118 274 blog_slug = request.matchdict['blog_slug']
b56cd89e 275 blog = get_blog_by_slug(request, blog_slug, author=url_user.id)
eebd8fe3 276 if not blog:
3e329412 277 return render_404(request)
0b7c64c8 278
fe741055 279 all_blog_posts = blog.get_all_blog_posts(u'processed').order_by(MediaEntry.created.desc())
8762609f
AM
280 pagination = Pagination(page, all_blog_posts)
281 pagination.per_page = 8
282 blog_posts_on_a_page = pagination()
0b7c64c8 283
3e329412
A
284 return render_to_response(
285 request,
286 'mediagoblin/blog/blog_post_listing.html',
8762609f
AM
287 {'blog_posts': blog_posts_on_a_page,
288 'pagination': pagination,
eebd8fe3 289 'blog_owner': url_user,
8189f6c7 290 'blog':blog
3e329412 291 })
0f3bf8d4 292
0b7c64c8
AM
293
294@require_active_login
4cf5b010 295def draft_view(request):
0b2ea4bb
A
296 blog_slug = request.matchdict.get('blog_slug', None)
297 blog_post_slug = request.matchdict.get('blog_post_slug', None)
4cf5b010 298 user = request.matchdict.get('user')
36990574 299 blog = get_blog_by_slug(request, blog_slug, author=request.user.id)
beb5a4a1 300 blogpost = request.db.MediaEntry.query.filter_by(state = u'failed', actor=request.user.id, slug=blog_post_slug).first()
0b7c64c8 301
4cf5b010
A
302 if not blog or not blogpost:
303 return render_404(request)
0b7c64c8 304
4cf5b010
A
305 return render_to_response(
306 request,
307 'mediagoblin/blog/blogpost_draft_view.html',
308 {'blogpost':blogpost,
309 'blog': blog
310 })
b4997540
JT
311
312
0b7c64c8 313@require_active_login
4aa7058e 314def blog_delete(request, **kwargs):
afff1492 315 """
b4997540 316 Deletes a blog and media entries, tags associated with it.
afff1492 317 """
4aa7058e 318 url_user = request.matchdict.get('user')
b4997540 319 owner_user = request.db.LocalUser.query.filter(
d88fcb03
JT
320 LocalUser.username==url_user
321 ).first()
0b7c64c8 322
4aa7058e 323 blog_slug = request.matchdict.get('blog_slug', None)
36990574 324 blog = get_blog_by_slug(request, blog_slug, author=owner_user.id)
4aa7058e 325 if not blog:
ee7db0a3 326 return render_404(request)
0b7c64c8 327
4aa7058e 328 form = blog_forms.ConfirmDeleteForm(request.form)
39fbb834 329 if request.user.id == blog.author or request.user.has_privilege(u'admin'):
4aa7058e 330 if request.method == 'POST' and form.validate():
4aa7058e
AM
331 if form.confirm.data is True:
332 blog.delete()
5c7b2a63
AB
333 messages.add_message(
334 request,
335 messages.SUCCESS,
336 _('You deleted the Blog.'))
4aa7058e
AM
337 return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
338 user=request.user.username)
339 else:
5c7b2a63
AB
340 messages.add_message(
341 request,
342 messages.ERROR,
343 _("The media was not deleted because you didn't check "
344 "that you were sure."))
4aa7058e
AM
345 return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
346 user=request.user.username)
347 else:
39fbb834 348 if request.user.has_privilege(u'admin'):
5c7b2a63
AB
349 messages.add_message(
350 request,
351 messages.WARNING,
4aa7058e
AM
352 _("You are about to delete another user's Blog. "
353 "Proceed with caution."))
354 return render_to_response(
355 request,
356 'mediagoblin/blog/blog_confirm_delete.html',
357 {'blog':blog,
358 'form':form
359 })
360 else:
5c7b2a63
AB
361 messages.add_message(
362 request,
363 messages.ERROR,
364 _("The blog was not deleted because you have no rights."))
4aa7058e
AM
365 return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
366 user=request.user.username)
0f3bf8d4
JT
367
368
310c3073 369def blog_about_view(request):
afff1492
AM
370 """
371 Page containing blog description and statistics
372 """
310c3073
AM
373 blog_slug = request.matchdict.get('blog_slug', None)
374 url_user = request.matchdict.get('user', None)
0f3bf8d4 375
beb5a4a1 376 user = request.db.LocalUser.query.filter(
377 LocalUser.username==url_user
0f3bf8d4 378 ).first()
588162b8
AB
379
380 if user:
381 blog = get_blog_by_slug(request, blog_slug, author=user.id)
0f3bf8d4 382
310c3073
AM
383 if not user or not blog:
384 return render_404(request)
0f3bf8d4 385
310c3073
AM
386 else:
387 blog_posts_processed = blog.get_all_blog_posts(u'processed').count()
388 return render_to_response(
389 request,
390 'mediagoblin/blog/blog_about.html',
391 {'user': user,
392 'blog': blog,
393 'blogpost_count': blog_posts_processed
394 })