1 # MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011 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
35 def user_home(request
, page
):
36 """'Homepage' of a User()"""
37 user
= request
.db
.User
.find_one({
38 'username': request
.matchdict
['user']})
40 return render_404(request
)
41 elif user
['status'] != u
'active':
42 return render_to_response(
44 'mediagoblin/user_pages/user.html',
47 cursor
= request
.db
.MediaEntry
.find(
48 {'uploader': user
._id
,
49 'state': 'processed'}).sort('created', DESCENDING
)
51 pagination
= Pagination(page
, cursor
)
52 media_entries
= pagination()
54 #if no data is available, return NotFound
55 if media_entries
== None:
56 return render_404(request
)
58 user_gallery_url
= request
.urlgen(
59 'mediagoblin.user_pages.user_gallery',
60 user
=user
['username'])
62 return render_to_response(
64 'mediagoblin/user_pages/user.html',
66 'user_gallery_url': user_gallery_url
,
67 'media_entries': media_entries
,
68 'pagination': pagination
})
72 def user_gallery(request
, page
):
73 """'Gallery' of a User()"""
74 user
= request
.db
.User
.find_one({
75 'username': request
.matchdict
['user'],
78 return render_404(request
)
80 cursor
= request
.db
.MediaEntry
.find(
81 {'uploader': user
._id
,
82 'state': 'processed'}).sort('created', DESCENDING
)
84 pagination
= Pagination(page
, cursor
)
85 media_entries
= pagination()
87 #if no data is available, return NotFound
88 if media_entries
== None:
89 return render_404(request
)
91 return render_to_response(
93 'mediagoblin/user_pages/gallery.html',
95 'media_entries': media_entries
,
96 'pagination': pagination
})
98 MEDIA_COMMENTS_PER_PAGE
= 50
101 @get_user_media_entry
103 def media_home(request
, media
, page
, **kwargs
):
105 'Homepage' of a MediaEntry()
107 if ObjectId(request
.matchdict
.get('comment')):
108 pagination
= Pagination(
109 page
, media
.get_comments(
110 mg_globals
.app_config
['comments_ascending']),
111 MEDIA_COMMENTS_PER_PAGE
,
112 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
)
119 comments
= pagination()
121 comment_form
= user_forms
.MediaCommentForm(request
.POST
)
123 return render_to_response(
125 'mediagoblin/user_pages/media.html',
127 'comments': comments
,
128 'pagination': pagination
,
129 'comment_form': comment_form
,
130 'app_config': mg_globals
.app_config
})
133 @get_user_media_entry
134 @require_active_login
135 def media_post_comment(request
, media
):
137 recieves POST from a MediaEntry() comment form, saves the comment.
139 assert request
.method
== 'POST'
141 comment
= request
.db
.MediaComment()
142 comment
['media_entry'] = media
._id
143 comment
['author'] = request
.user
._id
144 comment
['content'] = unicode(request
.POST
['comment_content'])
145 comment
['content_html'] = cleaned_markdown_conversion(comment
['content'])
147 if not comment
['content'].strip():
148 messages
.add_message(
151 _("Empty comments are not allowed."))
155 messages
.add_message(
156 request
, messages
.SUCCESS
,
157 _('Comment posted!'))
159 return exc
.HTTPFound(
160 location
=media
.url_for_self(request
.urlgen
))
163 @get_user_media_entry
164 @require_active_login
165 @user_may_delete_media
166 def media_confirm_delete(request
, media
):
168 form
= user_forms
.ConfirmDeleteForm(request
.POST
)
170 if request
.method
== 'POST' and form
.validate():
171 if form
.confirm
.data
is True:
172 username
= media
.uploader()['username']
174 # Delete all files on the public storage
175 delete_media_files(media
)
178 messages
.add_message(request
, messages
.SUCCESS
, _('You deleted the media.'))
180 return redirect(request
, "mediagoblin.user_pages.user_home",
183 messages
.add_message(
184 request
, messages
.ERROR
,
185 _("The media was not deleted because you didn't check that you were sure."))
186 return exc
.HTTPFound(
187 location
=media
.url_for_self(request
.urlgen
))
189 if ((request
.user
[u
'is_admin'] and
190 request
.user
._id
!= media
.uploader()._id
)):
191 messages
.add_message(
192 request
, messages
.WARNING
,
193 _("You are about to delete another user's media. "
194 "Proceed with caution."))
196 return render_to_response(
198 'mediagoblin/user_pages/media_confirm_delete.html',
203 ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
= 15
206 def atom_feed(request
):
208 generates the atom feed with the newest images
211 user
= request
.db
.User
.find_one({
212 'username': request
.matchdict
['user'],
215 return render_404(request
)
217 cursor
= request
.db
.MediaEntry
.find({
218 'uploader': user
._id
,
219 'state': 'processed'}) \
220 .sort('created', DESCENDING
) \
221 .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS
)
223 feed
= AtomFeed(request
.matchdict
['user'],
224 feed_url
=request
.url
,
225 url
=request
.host_url
)
228 feed
.add(entry
.get('title'),
229 entry
.get('description_html'),
231 author
=request
.matchdict
['user'],
232 updated
=entry
.get('created'),
233 url
=entry
.url_for_self(request
.urlgen
))
235 return feed
.get_response()
238 @require_active_login
239 def processing_panel(request
):
241 Show to the user what media is still in conversion/processing...
242 and what failed, and why!
245 user
= request
.db
.User
.find_one(
246 {'username': request
.matchdict
['user'],
249 # Make sure the user exists and is active
251 return render_404(request
)
252 elif user
['status'] != u
'active':
253 return render_to_response(
255 'mediagoblin/user_pages/user.html',
258 # XXX: Should this be a decorator?
260 # Make sure we have permission to access this user's panel. Only
261 # admins and this user herself should be able to do so.
262 if not (user
._id
== request
.user
._id
263 or request
.user
.is_admin
):
264 # No? Let's simply redirect to this user's homepage then.
266 request
, 'mediagoblin.user_pages.user_home',
267 user
=request
.matchdict
['user'])
269 # Get media entries which are in-processing
270 processing_entries
= request
.db
.MediaEntry
.find(
271 {'uploader': user
._id
,
272 'state': 'processing'}).sort('created', DESCENDING
)
274 # Get media entries which have failed to process
275 failed_entries
= request
.db
.MediaEntry
.find(
276 {'uploader': user
._id
,
277 'state': 'failed'}).sort('created', DESCENDING
)
280 return render_to_response(
282 'mediagoblin/user_pages/processing_panel.html',
284 'processing_entries': processing_entries
,
285 'failed_entries': failed_entries
})