1 # GNU 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
.response
import render_to_response
, render_404
, redirect
22 from mediagoblin
.tools
.translate
import pass_to_ugettext
as _
23 from mediagoblin
.tools
.pagination
import Pagination
24 from mediagoblin
.tools
.files
import delete_media_files
25 from mediagoblin
.user_pages
import forms
as user_forms
27 from mediagoblin
.decorators
import (uses_pagination
, get_user_media_entry
,
28 require_active_login
, user_may_delete_media
)
30 from werkzeug
.contrib
.atom
import AtomFeed
32 from mediagoblin
.media_types
import get_media_manager
36 def user_home(request
, page
):
37 """'Homepage' of a User()"""
38 user
= request
.db
.User
.find_one({
39 'username': request
.matchdict
['user']})
41 return render_404(request
)
42 elif user
.status
!= u
'active':
43 return render_to_response(
45 'mediagoblin/user_pages/user.html',
48 cursor
= request
.db
.MediaEntry
.find(
49 {'uploader': user
._id
,
50 'state': 'processed'}).sort('created', DESCENDING
)
52 pagination
= Pagination(page
, cursor
)
53 media_entries
= pagination()
55 #if no data is available, return NotFound
56 if media_entries
== None:
57 return render_404(request
)
59 user_gallery_url
= request
.urlgen(
60 'mediagoblin.user_pages.user_gallery',
63 return render_to_response(
65 'mediagoblin/user_pages/user.html',
67 'user_gallery_url': user_gallery_url
,
68 'media_entries': media_entries
,
69 'pagination': pagination
})
73 def user_gallery(request
, page
):
74 """'Gallery' of a User()"""
75 user
= request
.db
.User
.find_one({
76 'username': request
.matchdict
['user'],
79 return render_404(request
)
81 cursor
= request
.db
.MediaEntry
.find(
82 {'uploader': user
._id
,
83 'state': 'processed'}).sort('created', DESCENDING
)
85 pagination
= Pagination(page
, cursor
)
86 media_entries
= pagination()
88 #if no data is available, return NotFound
89 if media_entries
== None:
90 return render_404(request
)
92 return render_to_response(
94 'mediagoblin/user_pages/gallery.html',
96 'media_entries': media_entries
,
97 'pagination': pagination
})
99 MEDIA_COMMENTS_PER_PAGE
= 50
102 @get_user_media_entry
104 def media_home(request
, media
, page
, **kwargs
):
106 'Homepage' of a MediaEntry()
108 if ObjectId(request
.matchdict
.get('comment')):
109 pagination
= Pagination(
110 page
, media
.get_comments(
111 mg_globals
.app_config
['comments_ascending']),
112 MEDIA_COMMENTS_PER_PAGE
,
113 ObjectId(request
.matchdict
.get('comment')))
115 pagination
= Pagination(
116 page
, media
.get_comments(
117 mg_globals
.app_config
['comments_ascending']),
118 MEDIA_COMMENTS_PER_PAGE
)
120 comments
= pagination()
122 comment_form
= user_forms
.MediaCommentForm(request
.POST
)
124 media_template_name
= get_media_manager(media
.media_type
)['display_template']
126 return render_to_response(
130 'comments': comments
,
131 'pagination': pagination
,
132 'comment_form': comment_form
,
133 'app_config': mg_globals
.app_config
})
136 @get_user_media_entry
137 @require_active_login
138 def media_post_comment(request
, media
):
140 recieves POST from a MediaEntry() comment form, saves the comment.
142 assert request
.method
== 'POST'
144 comment
= request
.db
.MediaComment()
145 comment
.media_entry
= media
.id
146 comment
.author
= request
.user
.id
147 comment
.content
= unicode(request
.POST
['comment_content'])
149 if not comment
.content
.strip():
150 messages
.add_message(
153 _("Oops, your comment was empty."))
157 messages
.add_message(
158 request
, messages
.SUCCESS
,
159 _('Your comment has been posted!'))
161 return exc
.HTTPFound(
162 location
=media
.url_for_self(request
.urlgen
))
165 @get_user_media_entry
166 @require_active_login
167 @user_may_delete_media
168 def media_confirm_delete(request
, media
):
170 form
= user_forms
.ConfirmDeleteForm(request
.POST
)
172 if request
.method
== 'POST' and form
.validate():
173 if form
.confirm
.data
is True:
174 username
= media
.get_uploader
.username
176 # Delete all the associated comments
177 for comment
in media
.get_comments():
180 # Delete all files on the public storage
181 delete_media_files(media
)
184 messages
.add_message(
185 request
, messages
.SUCCESS
, _('You deleted the media.'))
187 return redirect(request
, "mediagoblin.user_pages.user_home",
190 messages
.add_message(
191 request
, messages
.ERROR
,
192 _("The media was not deleted because you didn't check that you were sure."))
193 return exc
.HTTPFound(
194 location
=media
.url_for_self(request
.urlgen
))
196 if ((request
.user
.is_admin
and
197 request
.user
._id
!= media
.uploader
)):
198 messages
.add_message(
199 request
, messages
.WARNING
,
200 _("You are about to delete another user's media. "
201 "Proceed with caution."))
203 return render_to_response(
205 'mediagoblin/user_pages/media_confirm_delete.html',
210 ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
= 15
213 def atom_feed(request
):
215 generates the atom feed with the newest images
218 user
= request
.db
.User
.find_one({
219 'username': request
.matchdict
['user'],
222 return render_404(request
)
224 cursor
= request
.db
.MediaEntry
.find({
225 'uploader': user
._id
,
226 'state': 'processed'}) \
227 .sort('created', DESCENDING
) \
228 .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
)
231 ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI)
234 'href': request
.urlgen(
235 'mediagoblin.user_pages.user_home',
236 qualified
=True,user
=request
.matchdict
['user']),
240 if mg_globals
.app_config
["push_urls"]:
241 for push_url
in mg_globals
.app_config
["push_urls"]:
247 "MediaGoblin: Feed for user '%s'" % request
.matchdict
['user'],
248 feed_url
=request
.url
,
249 id='tag:'+request
.host
+',2011:gallery.user-'+request
.matchdict
['user'],
254 feed
.add(entry
.get('title'),
255 entry
.description_html
,
256 id=entry
.url_for_self(request
.urlgen
,qualified
=True),
259 'name': entry
.get_uploader
.username
,
260 'uri': request
.urlgen(
261 'mediagoblin.user_pages.user_home',
262 qualified
=True, user
=entry
.get_uploader
.username
)},
263 updated
=entry
.get('created'),
265 'href': entry
.url_for_self(
269 'type': 'text/html'}])
271 return feed
.get_response()
274 @require_active_login
275 def processing_panel(request
):
277 Show to the user what media is still in conversion/processing...
278 and what failed, and why!
281 user
= request
.db
.User
.find_one(
282 {'username': request
.matchdict
['user'],
285 # Make sure the user exists and is active
287 return render_404(request
)
288 elif user
.status
!= u
'active':
289 return render_to_response(
291 'mediagoblin/user_pages/user.html',
294 # XXX: Should this be a decorator?
296 # Make sure we have permission to access this user's panel. Only
297 # admins and this user herself should be able to do so.
298 if not (user
._id
== request
.user
._id
299 or request
.user
.is_admin
):
300 # No? Let's simply redirect to this user's homepage then.
302 request
, 'mediagoblin.user_pages.user_home',
303 user
=request
.matchdict
['user'])
305 # Get media entries which are in-processing
306 processing_entries
= request
.db
.MediaEntry
.find(
307 {'uploader': user
._id
,
308 'state': 'unprocessed'}).sort('created', DESCENDING
)
310 # Get media entries which have failed to process
311 failed_entries
= request
.db
.MediaEntry
.find(
312 {'uploader': user
._id
,
313 'state': 'failed'}).sort('created', DESCENDING
)
316 return render_to_response(
318 'mediagoblin/user_pages/processing_panel.html',
320 'processing_entries': processing_entries
,
321 'failed_entries': failed_entries
})