Permalink
Browse files

Added filters for plugin views, added stars in listing

  • Loading branch information...
1 parent 239535a commit 2419a0284a679ce3a0f0657f1a5bc1d7c7113748 @elpaso elpaso committed Oct 11, 2012
@@ -1,3 +1,7 @@
+"""
+XML-RPC webservices for the plugin web application
+"""
+
from rpc4django import rpcmethod
from xmlrpclib import Fault
from plugins.models import *
@@ -103,15 +107,14 @@ def plugin_upload(package, **kwargs):
def plugin_tags(**kwargs):
"""
Returns a list of current tags, in alphabetical order
-
"""
return [t.name for t in Tag.objects.all().order_by('name')]
@rpcmethod(name='plugin.vote', signature=['array', 'integer', 'integer'], login_required=False)
def plugin_tags(plugin_id, vote, **kwargs):
"""
- Vote a plugin
+ Vote a plugin, valid values are 1-5
"""
try:
request = kwargs.get('request')
@@ -121,11 +124,10 @@ def plugin_tags(plugin_id, vote, **kwargs):
try:
plugin = Plugin.objects.get(pk=plugin_id)
except Plugin.DoesNotExist:
- msg = unicode(_('Plugin with id %s does not exists') % plugin_id)
+ msg = unicode(_('Plugin with id %s does not exists.') % plugin_id)
raise ValidationError(msg)
if not int(vote) in range(1, 6):
- msg = unicode(_('%s is not a valid vote (1-5)') % vote)
+ msg = unicode(_('%s is not a valid vote (1-5).') % vote)
raise ValidationError(msg)
return [plugin.rating.add(score=int(vote), user=request.user, ip_address=request.META['REMOTE_ADDR'])]
-
@@ -16,7 +16,17 @@
PLUGINS_STORAGE_PATH = getattr(settings, 'PLUGINS_STORAGE_PATH', 'packages')
PLUGINS_FRESH_DAYS = getattr(settings, 'PLUGINS_FRESH_DAYS', 30)
-class ApprovedPlugins(models.Manager):
+class BasePluginManager(models.Manager):
+ """
+ Adds a score
+ """
+ def get_query_set(self):
+ return super(BasePluginManager, self).get_query_set().extra(
+ select={
+ 'average_vote': 'rating_score/(rating_votes+0.001)'
+ })
+
+class ApprovedPlugins(BasePluginManager):
"""
Shows only public plugins: i.e. those with
and with at least one approved version ("stable" or "experimental")
@@ -25,7 +35,7 @@ def get_query_set(self):
return super(ApprovedPlugins, self).get_query_set().filter(pluginversion__approved=True).distinct()
-class StablePlugins(models.Manager):
+class StablePlugins(BasePluginManager):
"""
Shows only public plugins: i.e. those with "approved" flag set
and with one "stable" version
@@ -34,7 +44,7 @@ def get_query_set(self):
return super(StablePlugins, self).get_query_set().filter(pluginversion__approved=True, pluginversion__experimental=False).distinct()
-class ExperimentalPlugins(models.Manager):
+class ExperimentalPlugins(BasePluginManager):
"""
Shows only public plugins: i.e. those with "approved" flag set
and with one "experimental" version
@@ -43,7 +53,7 @@ def get_query_set(self):
return super(ExperimentalPlugins, self).get_query_set().filter(pluginversion__approved=True, pluginversion__experimental=True).distinct()
-class FeaturedPlugins(models.Manager):
+class FeaturedPlugins(BasePluginManager):
"""
Shows only public featured stable plugins: i.e. those with "approved" flag set
and "featured" flag set
@@ -52,7 +62,7 @@ def get_query_set(self):
return super(FeaturedPlugins, self).get_query_set().filter(pluginversion__approved=True, featured=True).order_by('-created_on').distinct()
-class FreshPlugins(models.Manager):
+class FreshPlugins(BasePluginManager):
"""
Shows only approved plugins: i.e. those with "approved" version flag set
and modified less than "days" ago.
@@ -66,35 +76,60 @@ def get_query_set(self):
return super(FreshPlugins, self).get_query_set().filter(pluginversion__approved=True, modified_on__gte = datetime.datetime.now()- datetime.timedelta(days = self.days)).order_by('-created_on').distinct()
-class UnapprovedPlugins(models.Manager):
+class UnapprovedPlugins(BasePluginManager):
"""
Shows only unapproved plugins
"""
def get_query_set(self):
return super(UnapprovedPlugins, self).get_query_set().filter(pluginversion__approved=False).distinct()
-class DeprecatedPlugins(models.Manager):
+class DeprecatedPlugins(BasePluginManager):
"""
Shows only deprecated plugins
"""
def get_query_set(self):
return super(DeprecatedPlugins, self).get_query_set().filter(deprecated=True).distinct()
+
class PopularPlugins(ApprovedPlugins):
"""
- Shows only unapproved plugins, sort by downloads
+ Shows only approved plugins, sort by popularity algorithm
"""
def get_query_set(self):
return super(PopularPlugins, self).get_query_set().filter(deprecated=False).extra(
select={
- 'popularity': 'SELECT downloads * (1 + (rating_score/(rating_votes+0.01)/3)) FROM plugins_plugin AS pp WHERE pp.id = plugins_plugin.id'
+ 'popularity': 'plugins_plugin.downloads * (1 + (rating_score/(rating_votes+0.01)/3))'
}
).order_by('-popularity').distinct()
-class TaggablePlugins (TaggableManager):
+class MostDownloadedPlugins(ApprovedPlugins):
+ """
+ Shows only approved plugins, sort by downloads
+ """
+ def get_query_set(self):
+ return super(MostDownloadedPlugins, self).get_query_set().filter(deprecated=False).order_by('-downloads').distinct()
+
+
+class MostVotedPlugins(ApprovedPlugins):
+ """
+ Shows only approved plugins, sort by vote number
+ """
+ def get_query_set(self):
+ return super(MostVotedPlugins, self).get_query_set().filter(deprecated=False).order_by('-rating_votes').distinct()
+
+
+class MostRatedPlugins(ApprovedPlugins):
+ """
+ Shows only approved plugins, sort by vote/number of votes number
+ """
+ def get_query_set(self):
+ return super(ApprovedPlugins, self).get_query_set().filter(deprecated=False).order_by('-average_vote').distinct()
+
+
+class TaggablePlugins(TaggableManager):
"""
Shows only public plugins: i.e. those with "approved" flag set
"""
@@ -146,6 +181,9 @@ class Plugin (models.Model):
unapproved_objects = UnapprovedPlugins()
deprecated_objects = DeprecatedPlugins()
popular_objects = PopularPlugins()
+ most_downloaded_objects = MostDownloadedPlugins()
+ most_voted_objects = MostVotedPlugins()
+ most_rated_objects = MostRatedPlugins()
rating = AnonymousRatingField(range=5, use_cookies=True, can_change_vote=True, allow_delete=True)
@@ -28,6 +28,9 @@
<li><a href="{% url stable_plugins %}">{% trans "Stable"%}</a></li>
<li><a href="{% url experimental_plugins %}">{% trans "Experimental"%}</a></li>
<li><a href="{% url popular_plugins %}">{% trans "Popular" %}</a></li>
+ <li><a href="{% url most_voted_plugins %}">{% trans "Most voted" %}</a></li>
+ <li><a href="{% url most_downloaded_plugins %}">{% trans "Top downloads" %}</a></li>
+ <li><a href="{% url most_rated_plugins %}">{% trans "Most rated" %}</a></li>
</ul>
</div>
<div class="module_menu">
@@ -10,6 +10,12 @@
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
+
+ jQuery(document).ajaxStart(function () {
+ jQuery('#loading').show();
+ }).ajaxStop(function () {
+ jQuery('#loading').hide();
+ });
// Rating
jQuery(function(){
@@ -44,7 +50,7 @@
<h2>{% trans "Plugin" %}: {{ object.name }}{% if object.icon %}<img class="plugin-icon" src="{{ object.icon.url }}" alt="{% trans "Plugin icon" %}" />{% endif %}</h2>
<div class="plugin-details">
{% if object.deprecated %}<p class="error"><strong>{% trans "This plugin is deprecated!" %}</strong></p>{% endif %}
- <div id="rating"> (<span id="votes">{% firstof votes '0' %}</span>) {% trans "votes" %}&nbsp;<span id="vote-message" style="display:none"></span></div>
+ <div id="rating"> (<span id="votes">{% firstof votes '0' %}</span>) {% trans "votes" %}&nbsp;<span id="loading" style="display:none">Loading...</span><span id="vote-message" style="display:none"></span></div>
<p class="plugin-details-description">{{ object.description }}</p>
{% if object.author %}
<p><strong>{% trans "Author"%}:</strong> <a title="{% trans "Plugins by"%} {{ object.author }}" href="{% url author_plugins object.author|urlencode %}">{{ object.author }}</a></p>
@@ -1,4 +1,4 @@
-{% extends 'plugins/plugin_base.html' %}{% load i18n sorting_tags pagination_tags humanize smart_paginate %}
+{% extends 'plugins/plugin_base.html' %}{% load i18n sorting_tags pagination_tags humanize smart_paginate range_filter %}
{% block extrajs %}
<script type="text/javascript" src="/static/js/jquery-1.5.1.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.cookie.js"></script>
@@ -60,7 +60,10 @@
<th>{% anchor featured %}</th>
<th>{% anchor downloads %}</th>
<th>{% anchor author "Author" %}</th>
+<!--
<th>{% anchor modified_on "Last modified" %}</th>
+-->
+ <th>{% anchor average_vote "Stars (votes)" %}</th>
<th>{% trans "Stable" %}</th>
<th>{% trans "Exp." %}</th>
{% if user.is_authenticated %}<th colspan="2">{% trans "Manage" %}</th>{% endif %}
@@ -77,7 +80,10 @@
<td>{% if object.featured%}<img src="/static/images/tick_16.png" />{% else %}&mdash;{% endif %}</td>
<td>{{ object.downloads }}</td>
<td><a title="{% trans "Plugins by"%} {{ object.author }}" href="{% url author_plugins object.author|urlencode %}">{{ object.author }}</a></td>
+<!--
<td>{{ object.modified_on|naturalday }}</td>
+-->
+ <td>{% for i in object.average_vote|add:"0"|get_range %}<span class="small-star"></span>{% endfor %} ({{ object.rating_votes }})</td>
<td>{% if object.stable %}<a href="{% url version_download object.package_name object.stable.version %}" title="{% trans "Download the stable version" %}" >{{ object.stable.version }}</a>{% else %}&mdash;{% endif %}</td>
<td>{% if object.experimental %}<a href="{% url version_download object.package_name object.experimental.version %}" title="{% trans "Download the experimental version" %}" >{{ object.experimental.version }}</a>{% else %}&mdash;{% endif %}</td>
{% if user.is_authenticated %}{% if user in object.editors or user.is_staff %}<td><a href="{% url plugin_update object.package_name %}">{% trans "Edit" %}</a></td>
@@ -0,0 +1,24 @@
+from django.template import Library
+
+register = Library()
+
+@register.filter
+def get_range( value ):
+ """
+ Filter - returns a list containing range made from given value
+ Usage (in template):
+
+ <ul>{% for i in 3|get_range %}
+ <li>{{ i }}. Do something</li>
+ {% endfor %}</ul>
+
+ Results with the HTML:
+ <ul>
+ <li>0. Do something</li>
+ <li>1. Do something</li>
+ <li>2. Do something</li>
+ </ul>
+
+ Instead of 3 one may use the variable set in the views
+ """
+ return range( value )
@@ -31,6 +31,10 @@
url(r'^stable/$', 'plugins_list', {'queryset' : Plugin.stable_objects.all(), 'extra_context' : {'title' : _('Stable plugins')}}, name='stable_plugins'),
url(r'^experimental/$', 'plugins_list', {'queryset' : Plugin.experimental_objects.all(), 'extra_context' : {'title' : _('Experimental plugins')}}, name='experimental_plugins'),
url(r'^popular/$', 'plugins_list', {'queryset' : Plugin.popular_objects.all(), 'extra_context' : {'title' : _('Popular plugins')}}, name='popular_plugins'),
+ url(r'^most_voted/$', 'plugins_list', {'queryset' : Plugin.most_voted_objects.all(), 'extra_context' : {'title' : _('Most voted plugins')}}, name='most_voted_plugins'),
+ url(r'^most_downloaded/$', 'plugins_list', {'queryset' : Plugin.most_downloaded_objects.all(), 'extra_context' : {'title' : _('Most downloaded plugins')}}, name='most_downloaded_plugins'),
+ url(r'^most_voted/$', 'plugins_list', {'queryset' : Plugin.most_voted_objects.all(), 'extra_context' : {'title' : _('Most voted plugins')}}, name='most_voted_plugins'),
+ url(r'^most_rated/$', 'plugins_list', {'queryset' : Plugin.most_rated_objects.all(), 'extra_context' : {'title' : _('Most rated plugins')}}, name='most_rated_plugins'),
url(r'^author/(?P<author>[^/]+)/$', 'author_plugins', {}, name='author_plugins'),
@@ -14,7 +14,7 @@
from django.conf import settings
from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType
-
+from django.utils.encoding import DjangoUnicodeDecodeError
from plugins.models import Plugin, PluginVersion
from plugins.forms import *
@@ -238,6 +238,7 @@ def plugin_upload(request):
elif not plugin.repository:
warnings.append(_('<strong>repository</strong> field is empty, this field is not required but is recommended, please consider adding it to metadata.'))
+
plugin.save()
if is_new:
@@ -274,7 +275,7 @@ def plugin_upload(request):
messages.warning(request, _('<p><strong>Warnings:</strong></p>') + '\n'.join(["<p>%s</p>" % unicode(w) for w in warnings]), fail_silently=True)
- except (IntegrityError, ValidationError), e:
+ except (IntegrityError, ValidationError, DjangoUnicodeDecodeError), e:
connection.close()
messages.error(request, e, fail_silently=True)
if not plugin.pk:
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -114,6 +114,7 @@ pre, .wp-caption-text {
width: 100%;
}
+/* plugins */
div.plugin-details {
clear: both;
@@ -136,3 +137,15 @@ div.plugin-details .plugin-details-description{
-moz-border-radius: 10px;
border-radius: 10px;
}
+
+#loading {
+ background: url(../images/loading.gif) top left no-repeat;
+ padding-left: 20px;
+}
+
+span.small-star {
+ background: url(../images/star_16.png) center bottom no-repeat;
+ width: 17px;
+ height: 17px;
+ display: inline-block;
+}

0 comments on commit 2419a02

Please sign in to comment.