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/>.
20 from mediagoblin
import messages
, mg_globals
21 from mediagoblin
.db
.util
import DESCENDING
, ObjectId
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
27 from mediagoblin
.user_pages
.lib
import send_comment_email
29 from mediagoblin
.decorators
import (uses_pagination
, get_user_media_entry
,
30 require_active_login
, user_may_delete_media
)
32 from werkzeug
.contrib
.atom
import AtomFeed
34 from mediagoblin
.media_types
import get_media_manager
37 _log
= logging
.getLogger(__name__
)
38 _log
.setLevel(logging
.DEBUG
)
41 def user_home(request
, page
):
42 """'Homepage' of a User()"""
43 user
= request
.db
.User
.find_one({
44 'username': request
.matchdict
['user']})
46 return render_404(request
)
47 elif user
.status
!= u
'active':
48 return render_to_response(
50 'mediagoblin/user_pages/user.html',
53 cursor
= request
.db
.MediaEntry
.find(
54 {'uploader': user
._id
,
55 'state': 'processed'}).sort('created', DESCENDING
)
57 pagination
= Pagination(page
, cursor
)
58 media_entries
= pagination()
60 #if no data is available, return NotFound
61 if media_entries
== None:
62 return render_404(request
)
64 user_gallery_url
= request
.urlgen(
65 'mediagoblin.user_pages.user_gallery',
68 return render_to_response(
70 'mediagoblin/user_pages/user.html',
72 'user_gallery_url': user_gallery_url
,
73 'media_entries': media_entries
,
74 'pagination': pagination
})
78 def user_gallery(request
, page
):
79 """'Gallery' of a User()"""
80 user
= request
.db
.User
.find_one({
81 'username': request
.matchdict
['user'],
84 return render_404(request
)
86 cursor
= request
.db
.MediaEntry
.find(
87 {'uploader': user
._id
,
88 'state': 'processed'}).sort('created', DESCENDING
)
90 pagination
= Pagination(page
, cursor
)
91 media_entries
= pagination()
93 #if no data is available, return NotFound
94 if media_entries
== None:
95 return render_404(request
)
97 return render_to_response(
99 'mediagoblin/user_pages/gallery.html',
101 'media_entries': media_entries
,
102 'pagination': pagination
})
104 MEDIA_COMMENTS_PER_PAGE
= 50
107 @get_user_media_entry
109 def media_home(request
, media
, page
, **kwargs
):
111 'Homepage' of a MediaEntry()
113 if ObjectId(request
.matchdict
.get('comment')):
114 pagination
= Pagination(
115 page
, media
.get_comments(
116 mg_globals
.app_config
['comments_ascending']),
117 MEDIA_COMMENTS_PER_PAGE
,
118 ObjectId(request
.matchdict
.get('comment')))
120 pagination
= Pagination(
121 page
, media
.get_comments(
122 mg_globals
.app_config
['comments_ascending']),
123 MEDIA_COMMENTS_PER_PAGE
)
125 comments
= pagination()
127 comment_form
= user_forms
.MediaCommentForm(request
.POST
)
129 media_template_name
= get_media_manager(media
.media_type
)['display_template']
131 return render_to_response(
135 'comments': comments
,
136 'pagination': pagination
,
137 'comment_form': comment_form
,
138 'app_config': mg_globals
.app_config
})
141 @get_user_media_entry
142 @require_active_login
143 def media_post_comment(request
, media
):
145 recieves POST from a MediaEntry() comment form, saves the comment.
147 assert request
.method
== 'POST'
149 comment
= request
.db
.MediaComment()
150 comment
.media_entry
= media
.id
151 comment
.author
= request
.user
.id
152 comment
.content
= unicode(request
.POST
['comment_content'])
154 if not comment
.content
.strip():
155 messages
.add_message(
158 _("Oops, your comment was empty."))
162 messages
.add_message(
163 request
, messages
.SUCCESS
,
164 _('Your comment has been posted!'))
166 media_uploader
= media
.get_uploader
167 #don't send email if you comment on your own post
168 if (comment
.author
!= media_uploader
and
169 media_uploader
.wants_comment_notification
):
170 send_comment_email(media_uploader
, comment
, media
, request
)
172 return exc
.HTTPFound(
173 location
=media
.url_for_self(request
.urlgen
))
176 @get_user_media_entry
177 @require_active_login
178 @user_may_delete_media
179 def media_confirm_delete(request
, media
):
181 form
= user_forms
.ConfirmDeleteForm(request
.POST
)
183 if request
.method
== 'POST' and form
.validate():
184 if form
.confirm
.data
is True:
185 username
= media
.get_uploader
.username
187 # Delete all the associated comments
188 for comment
in media
.get_comments():
191 # Delete all files on the public storage
193 delete_media_files(media
)
194 except OSError, error
:
195 _log
.error('No such files from the user "{1}"'
196 ' to delete: {0}'.format(str(error
), username
))
197 messages
.add_message(request
, messages
.ERROR
,
198 _('Some of the files with this entry seem'
199 ' to be missing. Deleting anyway.'))
202 messages
.add_message(
203 request
, messages
.SUCCESS
, _('You deleted the media.'))
205 return redirect(request
, "mediagoblin.user_pages.user_home",
208 messages
.add_message(
209 request
, messages
.ERROR
,
210 _("The media was not deleted because you didn't check that you were sure."))
211 return exc
.HTTPFound(
212 location
=media
.url_for_self(request
.urlgen
))
214 if ((request
.user
.is_admin
and
215 request
.user
._id
!= media
.uploader
)):
216 messages
.add_message(
217 request
, messages
.WARNING
,
218 _("You are about to delete another user's media. "
219 "Proceed with caution."))
221 return render_to_response(
223 'mediagoblin/user_pages/media_confirm_delete.html',
228 ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
= 15
231 def atom_feed(request
):
233 generates the atom feed with the newest images
236 user
= request
.db
.User
.find_one({
237 'username': request
.matchdict
['user'],
240 return render_404(request
)
242 cursor
= request
.db
.MediaEntry
.find({
243 'uploader': user
._id
,
244 'state': 'processed'}) \
245 .sort('created', DESCENDING
) \
246 .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
)
249 ATOM feed id is a tag URI (see http://en.wikipedia.org/wiki/Tag_URI)
252 'href': request
.urlgen(
253 'mediagoblin.user_pages.user_home',
254 qualified
=True,user
=request
.matchdict
['user']),
258 if mg_globals
.app_config
["push_urls"]:
259 for push_url
in mg_globals
.app_config
["push_urls"]:
265 "MediaGoblin: Feed for user '%s'" % request
.matchdict
['user'],
266 feed_url
=request
.url
,
267 id='tag:'+request
.host
+',2011:gallery.user-'+request
.matchdict
['user'],
272 feed
.add(entry
.get('title'),
273 entry
.description_html
,
274 id=entry
.url_for_self(request
.urlgen
,qualified
=True),
277 'name': entry
.get_uploader
.username
,
278 'uri': request
.urlgen(
279 'mediagoblin.user_pages.user_home',
280 qualified
=True, user
=entry
.get_uploader
.username
)},
281 updated
=entry
.get('created'),
283 'href': entry
.url_for_self(
287 'type': 'text/html'}])
289 return feed
.get_response()
292 @require_active_login
293 def processing_panel(request
):
295 Show to the user what media is still in conversion/processing...
296 and what failed, and why!
299 user
= request
.db
.User
.find_one(
300 {'username': request
.matchdict
['user'],
303 # Make sure the user exists and is active
305 return render_404(request
)
306 elif user
.status
!= u
'active':
307 return render_to_response(
309 'mediagoblin/user_pages/user.html',
312 # XXX: Should this be a decorator?
314 # Make sure we have permission to access this user's panel. Only
315 # admins and this user herself should be able to do so.
316 if not (user
._id
== request
.user
._id
317 or request
.user
.is_admin
):
318 # No? Let's simply redirect to this user's homepage then.
320 request
, 'mediagoblin.user_pages.user_home',
321 user
=request
.matchdict
['user'])
323 # Get media entries which are in-processing
324 processing_entries
= request
.db
.MediaEntry
.find(
325 {'uploader': user
._id
,
326 'state': 'unprocessed'}).sort('created', DESCENDING
)
328 # Get media entries which have failed to process
329 failed_entries
= request
.db
.MediaEntry
.find(
330 {'uploader': user
._id
,
331 'state': 'failed'}).sort('created', DESCENDING
)
334 return render_to_response(
336 'mediagoblin/user_pages/processing_panel.html',
338 'processing_entries': processing_entries
,
339 'failed_entries': failed_entries
})