Commit | Line | Data |
---|---|---|
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 | 17 | import logging |
af8f995f A |
18 | _log = logging.getLogger(__name__) |
19 | ||
cf46184a A |
20 | from datetime import datetime |
21 | ||
e49b7e02 BP |
22 | import six |
23 | ||
cf46184a | 24 | from werkzeug.exceptions import Forbidden |
125d7d1a | 25 | from mediagoblin.tools import pluginapi |
cf46184a | 26 | |
8c36ec52 | 27 | from mediagoblin import mg_globals |
cf46184a A |
28 | |
29 | from mediagoblin.media_types.blog import forms as blog_forms | |
5cb38a28 | 30 | from mediagoblin.media_types.blog.models import Blog, BlogPostData |
36990574 BB |
31 | from 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 |
35 | from 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) |
38 | from mediagoblin.tools.pagination import Pagination | |
cf46184a | 39 | from mediagoblin.tools.response import (render_to_response, |
0b2ea4bb | 40 | redirect, render_404) |
cf46184a A |
41 | from mediagoblin.tools.translate import pass_to_ugettext as _ |
42 | from mediagoblin.tools.template import render_template | |
43 | from 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 | 47 | from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used |
d88fcb03 | 48 | from mediagoblin.db.models import User, Collection, MediaEntry, LocalUser |
af8f995f | 49 | |
fa5a13f8 A |
50 | from mediagoblin.notifications import add_comment_subscription |
51 | ||
cf46184a A |
52 | |
53 | @require_active_login | |
af8f995f | 54 | def 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 | 134 | def 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 | |
180 | def 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 | 227 | def 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 | 270 | def 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 | 295 | def 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 | 314 | def 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 | 369 | def 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 | }) |