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