1 # MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
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.
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.
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/>.
19 from mediagoblin
import messages
, mg_globals
20 from mediagoblin
.db
.util
import DESCENDING
, ObjectId
21 from mediagoblin
.tools
.text
import cleaned_markdown_conversion
22 from mediagoblin
.tools
.response
import render_to_response
, render_404
, redirect
23 from mediagoblin
.tools
.translate
import pass_to_ugettext
as _
24 from mediagoblin
.tools
.pagination
import Pagination
25 from mediagoblin
.tools
.files
import delete_media_files
26 from mediagoblin
.user_pages
import forms
as user_forms
28 from mediagoblin
.decorators
import (uses_pagination
, get_user_media_entry
,
29 require_active_login
, user_may_delete_media
)
31 from werkzeug
.contrib
.atom
import AtomFeed
33 from mediagoblin
.media_types
import get_media_manager
37 def user_home(request
, page
):
38 """'Homepage' of a User()"""
39 user
= request
.db
.User
.find_one({
40 'username': request
.matchdict
['user']})
42 return render_404(request
)
43 elif user
.status
!= u
'active':
44 return render_to_response(
46 'mediagoblin/user_pages/user.html',
49 cursor
= request
.db
.MediaEntry
.find(
50 {'uploader': user
._id
,
51 'state': 'processed'}).sort('created', DESCENDING
)
53 pagination
= Pagination(page
, cursor
)
54 media_entries
= pagination()
56 #if no data is available, return NotFound
57 if media_entries
== None:
58 return render_404(request
)
60 user_gallery_url
= request
.urlgen(
61 'mediagoblin.user_pages.user_gallery',
64 return render_to_response(
66 'mediagoblin/user_pages/user.html',
68 'user_gallery_url': user_gallery_url
,
69 'media_entries': media_entries
,
70 'pagination': pagination
})
74 def user_gallery(request
, page
):
75 """'Gallery' of a User()"""
76 user
= request
.db
.User
.find_one({
77 'username': request
.matchdict
['user'],
80 return render_404(request
)
82 cursor
= request
.db
.MediaEntry
.find(
83 {'uploader': user
._id
,
84 'state': 'processed'}).sort('created', DESCENDING
)
86 pagination
= Pagination(page
, cursor
)
87 media_entries
= pagination()
89 #if no data is available, return NotFound
90 if media_entries
== None:
91 return render_404(request
)
93 return render_to_response(
95 'mediagoblin/user_pages/gallery.html',
97 'media_entries': media_entries
,
98 'pagination': pagination
})
100 MEDIA_COMMENTS_PER_PAGE
= 50
103 @get_user_media_entry
105 def media_home(request
, media
, page
, **kwargs
):
107 'Homepage' of a MediaEntry()
109 if ObjectId(request
.matchdict
.get('comment')):
110 pagination
= Pagination(
111 page
, media
.get_comments(
112 mg_globals
.app_config
['comments_ascending']),
113 MEDIA_COMMENTS_PER_PAGE
,
114 ObjectId(request
.matchdict
.get('comment')))
116 pagination
= Pagination(
117 page
, media
.get_comments(
118 mg_globals
.app_config
['comments_ascending']),
119 MEDIA_COMMENTS_PER_PAGE
)
121 comments
= pagination()
123 comment_form
= user_forms
.MediaCommentForm(request
.POST
)
125 media_template_name
= get_media_manager(media
.media_type
)['display_template']
127 return render_to_response(
131 'comments': comments
,
132 'pagination': pagination
,
133 'comment_form': comment_form
,
134 'app_config': mg_globals
.app_config
})
137 @get_user_media_entry
138 @require_active_login
139 def media_post_comment(request
, media
):
141 recieves POST from a MediaEntry() comment form, saves the comment.
143 assert request
.method
== 'POST'
145 comment
= request
.db
.MediaComment()
146 comment
['media_entry'] = media
._id
147 comment
['author'] = request
.user
._id
148 comment
['content'] = unicode(request
.POST
['comment_content'])
149 comment
['content_html'] = cleaned_markdown_conversion(comment
['content'])
151 if not comment
['content'].strip():
152 messages
.add_message(
155 _("Oops, your comment was empty."))
159 messages
.add_message(
160 request
, messages
.SUCCESS
,
161 _('Your comment has been posted!'))
163 return exc
.HTTPFound(
164 location
=media
.url_for_self(request
.urlgen
))
167 @get_user_media_entry
168 @require_active_login
169 @user_may_delete_media
170 def media_confirm_delete(request
, media
):
172 form
= user_forms
.ConfirmDeleteForm(request
.POST
)
174 if request
.method
== 'POST' and form
.validate():
175 if form
.confirm
.data
is True:
176 username
= media
.get_uploader
.username
178 # Delete all files on the public storage
179 delete_media_files(media
)
182 messages
.add_message(
183 request
, messages
.SUCCESS
, _('You deleted the media.'))
185 return redirect(request
, "mediagoblin.user_pages.user_home",
188 messages
.add_message(
189 request
, messages
.ERROR
,
190 _("The media was not deleted because you didn't check that you were sure."))
191 return exc
.HTTPFound(
192 location
=media
.url_for_self(request
.urlgen
))
194 if ((request
.user
.is_admin
and
195 request
.user
._id
!= media
.uploader
)):
196 messages
.add_message(
197 request
, messages
.WARNING
,
198 _("You are about to delete another user's media. "
199 "Proceed with caution."))
201 return render_to_response(
203 'mediagoblin/user_pages/media_confirm_delete.html',
208 ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
= 15
211 def atom_feed(request
):
213 generates the atom feed with the newest images
216 user
= request
.db
.User
.find_one({
217 'username': request
.matchdict
['user'],
220 return render_404(request
)
222 cursor
= request
.db
.MediaEntry
.find({
223 'uploader': user
._id
,
224 'state': 'processed'}) \
225 .sort('created', DESCENDING
) \
226 .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
)
229 ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI)
232 'href': request
.urlgen(
233 'mediagoblin.user_pages.user_home',
234 qualified
=True,user
=request
.matchdict
['user']),
238 if mg_globals
.app_config
["push_urls"]:
239 for push_url
in mg_globals
.app_config
["push_urls"]:
245 "MediaGoblin: Feed for user '%s'" % request
.matchdict
['user'],
246 feed_url
=request
.url
,
247 id='tag:'+request
.host
+',2011:gallery.user-'+request
.matchdict
['user'],
252 feed
.add(entry
.get('title'),
253 entry
.get('description_html'),
254 id=entry
.url_for_self(request
.urlgen
,qualified
=True),
257 'name': entry
.get_uploader
.username
,
258 'uri': request
.urlgen(
259 'mediagoblin.user_pages.user_home',
260 qualified
=True, user
=entry
.get_uploader
.username
)},
261 updated
=entry
.get('created'),
263 'href': entry
.url_for_self(
267 'type': 'text/html'}])
269 return feed
.get_response()
272 @require_active_login
273 def processing_panel(request
):
275 Show to the user what media is still in conversion/processing...
276 and what failed, and why!
279 user
= request
.db
.User
.find_one(
280 {'username': request
.matchdict
['user'],
283 # Make sure the user exists and is active
285 return render_404(request
)
286 elif user
.status
!= u
'active':
287 return render_to_response(
289 'mediagoblin/user_pages/user.html',
292 # XXX: Should this be a decorator?
294 # Make sure we have permission to access this user's panel. Only
295 # admins and this user herself should be able to do so.
296 if not (user
._id
== request
.user
._id
297 or request
.user
.is_admin
):
298 # No? Let's simply redirect to this user's homepage then.
300 request
, 'mediagoblin.user_pages.user_home',
301 user
=request
.matchdict
['user'])
303 # Get media entries which are in-processing
304 processing_entries
= request
.db
.MediaEntry
.find(
305 {'uploader': user
._id
,
306 'state': 'processing'}).sort('created', DESCENDING
)
308 # Get media entries which have failed to process
309 failed_entries
= request
.db
.MediaEntry
.find(
310 {'uploader': user
._id
,
311 'state': 'failed'}).sort('created', DESCENDING
)
314 return render_to_response(
316 'mediagoblin/user_pages/processing_panel.html',
318 'processing_entries': processing_entries
,
319 'failed_entries': failed_entries
})