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/>.
16 from mediagoblin
.db
.models
import MediaEntry
, User
17 from mediagoblin
.plugins
.archivalook
.models
import FeaturedMedia
18 from mediagoblin
.tools
.translate
import lazy_pass_to_ugettext
as _
19 from mediagoblin
.plugins
.archivalook
.models
import FeaturedMedia
21 def get_media_entry_from_uploader_slug(uploader_username
, slug
):
23 Accepts two strings and searches to see if those strings identify a
26 :param uploader_username A string representing the User.username
27 of the user who uploaded a piece of
29 :param slug A string representing the slug of a
32 :returns media A MediaEntry object or None if no entry
33 matches the specifications.
35 uploader
= User
.query
.filter(
36 User
.username
== uploader_username
).first()
37 media
= MediaEntry
.query
.filter(
38 MediaEntry
.get_uploader
== uploader
).filter(
39 MediaEntry
.slug
== slug
).first()
45 A simple helper function that extracts the uploader and slug from a full url
47 :param url A string containing the url for a piece
48 of media. This should be in the format
49 of "/u/{user}/m/{media}/"
51 :returns (uploader_username, slug) Uploader_username is a unicode string
52 representing the username of the user
53 who uploaded the piece of media, slug is
54 the media entry's url slug.
57 u_end
, m_start
, m_end
, end
= (url
.find('/u/') + 3,
62 uploader_username
= url
[u_end
:m_start
].strip()
63 slug
= url
[m_end
:end
].strip()
65 return uploader_username
, slug
68 def split_featured_media_list(featured_media
):
70 This script is part of processing post request on the /mod/feature-media/
71 page. Post requests on these pages will only include the textbox, so this
72 script accepts the textbox's contents as its parameter.
74 :parameter featured_media A string from a submitted
75 textarea within the post request
76 on /mod/feature-media/
78 :returns all_featured_media A dictionary of the format
80 where MediaEntry is a featured
81 piece of media and 'string' is
82 a string representation of its
83 display type (primary, secondary
87 featured_media
= unicode(featured_media
)
88 featured_media_list
= featured_media
.split("\n")
90 media_already_featured
= []
91 all_featured_media
= []
92 for line
in featured_media_list
:
93 if line
== '' or line
.isspace(): continue
94 elif line
.startswith(u
'-'):
96 elif display_type
<= 0 or display_type
> 3: continue
98 uploader
, slug
= parse_url(line
)
99 media
= get_media_entry_from_uploader_slug(uploader
, slug
)
100 # Make sure the media entry referenced exists, and has not already
101 # been featured higher up the list
102 if media
== None or media
in media_already_featured
: continue
103 media_already_featured
.append(media
)
104 all_featured_media
.append((media
,
108 u
'tertiary'][display_type
]))
110 return all_featured_media
113 def create_featured_media_textbox():
115 This script searches through the database of which media is featured and
116 returns a string of each entry in the proper format for use in the
117 /mod/feature-media/ page. This string will be used as the default text in
118 the textbox on that page.
121 primaries
= FeaturedMedia
.query
.order_by(
122 FeaturedMedia
.order
.asc()).filter(
123 FeaturedMedia
.display_type
== u
'primary').all()
124 secondaries
= FeaturedMedia
.query
.order_by(
125 FeaturedMedia
.order
.asc()).filter(
126 FeaturedMedia
.display_type
== u
'secondary').all()
127 tertiaries
= FeaturedMedia
.query
.order_by(
128 FeaturedMedia
.order
.asc()).filter(
129 FeaturedMedia
.display_type
== u
'tertiary').all()
131 for display_type
, feature_list
in [
132 (_(u
'Primary'),primaries
),
133 (_(u
'Secondary'),secondaries
),
134 (_(u
'Tertiary'),tertiaries
)]:
136 u
"""-----------{display_type}-Features---------------------------
137 """).format(display_type
=display_type
)
138 for feature
in feature_list
:
139 media_entry
= feature
.media_entry
140 output_text
+= u
'/u/{uploader_username}/m/{media_slug}/\n'.format(
141 uploader_username
= media_entry
.get_uploader
.username
,
142 media_slug
= media_entry
.slug
)
147 def automatically_add_new_feature(media_entry
):
149 This function automates the addition of a new feature. New features will be
150 placed at the top of the feature stack as 'primary' features. All of the
151 current features are demoted one step to make room.
153 :param media_entry :type mediagoblin.db.MediaEntry
154 The media entry that will been
155 featured which this function
158 # Set variables to determine which media entries should be pushed down to
159 # maintain the correct number of primary & secondary featured media. At this
160 # point the program assumes that there should be 1 primary feature and 2
161 # secondary features, but in the future this should be a variable editable
163 too_many_primaries
= FeaturedMedia
.query
.filter(
164 FeaturedMedia
.display_type
==u
'primary').count() >= 1
165 too_many_secondaries
= FeaturedMedia
.query
.filter(
166 FeaturedMedia
.display_type
==u
'secondary').count() >= 2
167 featured_first_to_last
= FeaturedMedia
.query
.order_by(
168 FeaturedMedia
.order
.asc()).all()
170 for feature
in featured_first_to_last
:
171 # Some features have the option to demote or promote themselves to a
172 # different display_type, based on their position. But all features move
173 # up and down one step in the stack.
174 if (feature
.is_last_of_type() and feature
.display_type
== u
'primary'
175 and too_many_primaries
):
177 too_many_primaries
= False
178 elif (feature
.is_last_of_type() and feature
.display_type
== u
'secondary'
179 and too_many_secondaries
):
181 too_many_secondaries
= False
185 # Create the new feature at the top of the stack.
186 new_feature
= FeaturedMedia(
187 media_entry
=media_entry
,
188 display_type
=u
"primary",
193 def automatically_remove_feature(media_entry
):
195 This function automates the removal of a feature. All of the features below
196 them are promoted one step to close the gap.
198 :param media_entry :type mediagoblin.db.MediaEntry
199 The media entry that will been
200 removed which this function
203 # Get the feature which will be deleted
204 target_feature
= FeaturedMedia
.query
.filter(
205 FeaturedMedia
.media_entry_id
== media_entry
.id).first()
206 # Find out which continuing features will have to be adjusted
207 featured_last_to_first
= FeaturedMedia
.query
.filter(
208 FeaturedMedia
.order
>target_feature
.order
).order_by(
209 FeaturedMedia
.order
.desc()).all()
211 for feature
in featured_last_to_first
:
212 # Maintain the current arrangement of primary/secondary/tertiary
213 # features by moving all the features below the deleted one up on slot
214 # and promoting any features in the proper position.
215 if feature
.is_first_of_type():
220 # Delete the feature, now that it's space has been closed
221 target_feature
.delete()
223 def promote_feature(media_entry
):
225 This function takes a current feature and moves it up the stack so that it
226 will be displayed higher up. It swaps the place of the selected feature for
227 the one above it, or if relevant raises the display_type of the feature up
228 one rung (ie. from 'tertiary' to 'secondary')
230 :param media_entry :type mediagoblin.db.MediaEntry
231 The media entry that has been
232 featured which this function
235 # Get the FeaturedMedia object
236 target_feature
= FeaturedMedia
.query
.filter(
237 FeaturedMedia
.media_entry_id
== media_entry
.id).first()
238 # Get the first Feature with a lower order than the target
239 above_feature
= FeaturedMedia
.query
.filter(
240 FeaturedMedia
.order
< target_feature
.order
).order_by(
241 FeaturedMedia
.order
.desc()).first()
242 # If the feature is not the uppermost one
243 if above_feature
is not None:
244 # Swap the positions of the target feature with the one before it
245 (target_feature
.order
,
246 above_feature
.order
) = above_feature
.order
, target_feature
.order
247 (target_feature
.display_type
,
248 above_feature
.display_type
) = (above_feature
.display_type
,
249 target_feature
.display_type
)
251 # Change the feature's display type to a more prominent one
252 elif target_feature
.display_type
== u
'secondary':
253 target_feature
.display_type
= u
'primary'
254 elif target_feature
.display_type
== u
'tertiary':
255 target_feature
.display_type
= u
'secondary'
256 target_feature
.save()
258 def demote_feature(media_entry
):
260 This function takes a current feature and moves it down the stack so that it
261 will be displayed lower down. It swaps the place of the selected feature for
262 the one below it, or if relevant lowers the display_type of the feature down
263 one rung (ie. from 'secondary' to 'tertiary')
265 :param media_entry :type mediagoblin.db.MediaEntry
266 The media entry that has been
267 featured which this function
270 # Get the FeaturedMedia object
271 target_feature
= FeaturedMedia
.query
.filter(
272 FeaturedMedia
.media_entry_id
== media_entry
.id).first()
273 # Get the first Feature with a higher order than the target
274 below_feature
= FeaturedMedia
.query
.filter(
275 FeaturedMedia
.order
> target_feature
.order
).order_by(
276 FeaturedMedia
.order
.asc()).first()
277 # If the feature is not the lowest one
278 if below_feature
!= None:
279 # Swap the positions of the target feature with the one after it
280 (target_feature
.order
,
281 below_feature
.order
) = below_feature
.order
, target_feature
.order
282 (target_feature
.display_type
,
283 below_feature
.display_type
) = (below_feature
.display_type
,
284 target_feature
.display_type
)
286 # Change the feature's display type to a less prominent one
287 elif target_feature
.display_type
== u
'secondary':
288 target_feature
.display_type
= u
'tertiary'
289 elif target_feature
.display_type
== u
'primary':
290 target_feature
.display_type
= u
'secondary'
291 target_feature
.save()