Merge lp:~widelands-dev/widelands-website/remove_djangoratings into lp:widelands-website

Proposed by kaputtnik
Status: Merged
Merged at revision: 509
Proposed branch: lp:~widelands-dev/widelands-website/remove_djangoratings
Merge into: lp:widelands-website
Diff against target: 1747 lines (+40/-1472)
26 files modified
djangoratings/LICENSE (+0/-22)
djangoratings/__init__.py (+0/-50)
djangoratings/admin.py (+0/-18)
djangoratings/default_settings.py (+0/-5)
djangoratings/exceptions.py (+0/-18)
djangoratings/fields.py (+0/-434)
djangoratings/forms.py (+0/-7)
djangoratings/management/commands/update_recommendations.py (+0/-9)
djangoratings/managers.py (+0/-124)
djangoratings/migrations/0001_initial.py (+0/-90)
djangoratings/models.py (+0/-98)
djangoratings/runtests.py (+0/-31)
djangoratings/templatetags/ratings_old.py (+0/-101)
djangoratings/tests.py (+0/-184)
djangoratings/views.py (+0/-138)
media/css/base.css (+1/-1)
settings.py (+0/-1)
templates/wlmaps/base.html (+1/-2)
templates/wlmaps/index.html (+1/-3)
templates/wlmaps/map_detail.html (+3/-27)
wlmaps/migrations/0002_auto_20181119_1855.py (+33/-0)
wlmaps/models.py (+0/-3)
wlmaps/templatetags/wlmaps_extra.py (+0/-15)
wlmaps/tests/test_views.py (+0/-63)
wlmaps/urls.py (+1/-3)
wlmaps/views.py (+0/-25)
To merge this branch: bzr merge lp:~widelands-dev/widelands-website/remove_djangoratings
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+358960@code.launchpad.net

Commit message

Remove djangoratings

Description of the change

To post a comment you must log in.
Revision history for this message
GunChleoc (gunchleoc) wrote :

LGTM :)

review: Approve
510. By kaputtnik

merged trunk

511. By kaputtnik

for some reason django complains about missing migrations; Will apply other directly on the server

Revision history for this message
kaputtnik (franku) wrote :

This is merged for now, but not commited. There is a problem showing the stars for voting, which i couldn't solve so far. At home all is fine, but on the server i struggle with the served star images...

512. By kaputtnik

style fix

Revision history for this message
kaputtnik (franku) wrote :

Ok, this is merged and deployed now. I will explain in another merge request why this didn't worked right away.

What remains is the deletion of the djangoratings related tables in the mysql Database. But i saw on the server there are several old tables in the Database. No idea if having unused tables in the Database do affect the performance. I will create a new bugreport for this issue.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Cleaning up unused stuff is always a good idea :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed directory 'djangoratings'
2=== removed file 'djangoratings/LICENSE'
3--- djangoratings/LICENSE 2016-05-18 19:31:46 +0000
4+++ djangoratings/LICENSE 1970-01-01 00:00:00 +0000
5@@ -1,22 +0,0 @@
6-Copyright (c) 2009, David Cramer <dcramer@gmail.com>
7-All rights reserved.
8-
9-Redistribution and use in source and binary forms, with or without modification,
10-are permitted provided that the following conditions are met:
11-
12-* Redistributions of source code must retain the above copyright notice, this
13-list of conditions and the following disclaimer.
14-* Redistributions in binary form must reproduce the above copyright notice,
15-this list of conditions and the following disclaimer in the documentation
16-and/or other materials provided with the distribution.
17-
18-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29=== removed file 'djangoratings/__init__.py'
30--- djangoratings/__init__.py 2016-12-13 18:28:51 +0000
31+++ djangoratings/__init__.py 1970-01-01 00:00:00 +0000
32@@ -1,50 +0,0 @@
33-import os.path
34-import warnings
35-
36-__version__ = (0, 3, 7)
37-
38-
39-def _get_git_revision(path):
40- revision_file = os.path.join(path, 'refs', 'heads', 'master')
41- if not os.path.exists(revision_file):
42- return None
43- fh = open(revision_file, 'r')
44- try:
45- return fh.read()
46- finally:
47- fh.close()
48-
49-
50-def get_revision():
51- """
52- :returns: Revision number of this branch/checkout, if available. None if
53- no revision number can be determined.
54- """
55- package_dir = os.path.dirname(__file__)
56- checkout_dir = os.path.normpath(os.path.join(package_dir, '..'))
57- path = os.path.join(checkout_dir, '.git')
58- if os.path.exists(path):
59- return _get_git_revision(path)
60- return None
61-
62-__build__ = get_revision()
63-
64-
65-def lazy_object(location):
66- def inner(*args, **kwargs):
67- parts = location.rsplit('.', 1)
68- warnings.warn('`djangoratings.%s` is deprecated. Please use `%s` instead.' % (
69- parts[1], location), DeprecationWarning)
70- try:
71- imp = __import__(parts[0], globals(), locals(), [parts[1]], -1)
72- except:
73- imp = __import__(parts[0], globals(), locals(), [parts[1]])
74- func = getattr(imp, parts[1])
75- if callable(func):
76- return func(*args, **kwargs)
77- return func
78- return inner
79-
80-RatingField = lazy_object('djangoratings.fields.RatingField')
81-AnonymousRatingField = lazy_object('djangoratings.fields.AnonymousRatingField')
82-Rating = lazy_object('djangoratings.fields.Rating')
83
84=== removed file 'djangoratings/admin.py'
85--- djangoratings/admin.py 2016-12-13 18:28:51 +0000
86+++ djangoratings/admin.py 1970-01-01 00:00:00 +0000
87@@ -1,18 +0,0 @@
88-from django.contrib import admin
89-from models import Vote, Score
90-
91-
92-class VoteAdmin(admin.ModelAdmin):
93- list_display = ('content_object', 'user', 'ip_address',
94- 'cookie', 'score', 'date_changed')
95- list_filter = ('score', 'content_type', 'date_changed')
96- search_fields = ('ip_address',)
97- raw_id_fields = ('user',)
98-
99-
100-class ScoreAdmin(admin.ModelAdmin):
101- list_display = ('content_object', 'score', 'votes')
102- list_filter = ('content_type',)
103-
104-admin.site.register(Vote, VoteAdmin)
105-admin.site.register(Score, ScoreAdmin)
106
107=== removed file 'djangoratings/default_settings.py'
108--- djangoratings/default_settings.py 2016-12-13 18:28:51 +0000
109+++ djangoratings/default_settings.py 1970-01-01 00:00:00 +0000
110@@ -1,5 +0,0 @@
111-from django.conf import settings
112-
113-# Used to limit the number of unique IPs that can vote on a single object+field.
114-# useful if you're getting rating spam by users registering multiple accounts
115-RATINGS_VOTES_PER_IP = 3
116
117=== removed file 'djangoratings/exceptions.py'
118--- djangoratings/exceptions.py 2016-12-13 18:28:51 +0000
119+++ djangoratings/exceptions.py 1970-01-01 00:00:00 +0000
120@@ -1,18 +0,0 @@
121-class InvalidRating(ValueError):
122- pass
123-
124-
125-class AuthRequired(TypeError):
126- pass
127-
128-
129-class CannotChangeVote(Exception):
130- pass
131-
132-
133-class CannotDeleteVote(Exception):
134- pass
135-
136-
137-class IPLimitReached(Exception):
138- pass
139
140=== removed file 'djangoratings/fields.py'
141--- djangoratings/fields.py 2018-04-08 14:29:44 +0000
142+++ djangoratings/fields.py 1970-01-01 00:00:00 +0000
143@@ -1,434 +0,0 @@
144-from django.db.models import IntegerField, PositiveIntegerField
145-from django.conf import settings
146-
147-import forms
148-import itertools
149-from datetime import datetime
150-
151-from models import Vote, Score
152-from default_settings import RATINGS_VOTES_PER_IP
153-from exceptions import *
154-
155-if 'django.contrib.contenttypes' not in settings.INSTALLED_APPS:
156- raise ImportError(
157- 'djangoratings requires django.contrib.contenttypes in your INSTALLED_APPS')
158-
159-from django.contrib.contenttypes.models import ContentType
160-
161-__all__ = ('Rating', 'RatingField', 'AnonymousRatingField')
162-
163-try:
164- from hashlib import md5
165-except ImportError:
166- from md5 import new as md5
167-
168-try:
169- from django.utils.timezone import now
170-except ImportError:
171- now = datetime.now
172-
173-
174-def md5_hexdigest(value):
175- return md5(value).hexdigest()
176-
177-
178-class Rating(object):
179-
180- def __init__(self, score, votes):
181- self.score = score
182- self.votes = votes
183-
184-
185-class RatingManager(object):
186-
187- def __init__(self, instance, field):
188- self.content_type = None
189- self.instance = instance
190- self.field = field
191-
192- self.votes_field_name = '%s_votes' % (self.field.name,)
193- self.score_field_name = '%s_score' % (self.field.name,)
194-
195- def get_percent(self):
196- """get_percent()
197-
198- Returns the weighted percentage of the score from min-max values
199-
200- """
201- if not (self.votes and self.score):
202- return 0
203- return 100 * (self.get_rating() / self.field.range)
204-
205- def get_real_percent(self):
206- """get_real_percent()
207-
208- Returns the unmodified percentage of the score based on a 0-point scale.
209-
210- """
211- if not (self.votes and self.score):
212- return 0
213- return 100 * (self.get_real_rating() / self.field.range)
214-
215- def get_ratings(self):
216- """get_ratings()
217-
218- Returns a Vote QuerySet for this rating field.
219-
220- """
221- return Vote.objects.filter(content_type=self.get_content_type(), object_id=self.instance.pk, key=self.field.key)
222-
223- def get_rating(self):
224- """get_rating()
225-
226- Returns the weighted average rating.
227-
228- """
229- if not (self.votes and self.score):
230- return 0
231- return float(self.score) / (self.votes + self.field.weight)
232-
233- def get_opinion_percent(self):
234- """get_opinion_percent()
235-
236- Returns a neutral-based percentage.
237-
238- """
239- return (self.get_percent() + 100) / 2
240-
241- def get_real_rating(self):
242- """get_rating()
243-
244- Returns the unmodified average rating.
245-
246- """
247- if not (self.votes and self.score):
248- return 0
249- return float(self.score) / self.votes
250-
251- def get_rating_for_user(self, user, ip_address=None, cookies={}):
252- """get_rating_for_user(user, ip_address=None, cookie=None)
253-
254- Returns the rating for a user or anonymous IP."""
255- kwargs = dict(
256- content_type=self.get_content_type(),
257- object_id=self.instance.pk,
258- key=self.field.key,
259- )
260-
261- if not (user and user.is_authenticated):
262- if not ip_address:
263- raise ValueError('``user`` or ``ip_address`` must be present.')
264- kwargs['user__isnull'] = True
265- kwargs['ip_address'] = ip_address
266- else:
267- kwargs['user'] = user
268-
269- use_cookies = (self.field.allow_anonymous and self.field.use_cookies)
270- if use_cookies:
271- # TODO: move 'vote-%d.%d.%s' to settings or something
272- cookie_name = 'vote-%d.%d.%s' % (kwargs['content_type'].pk, kwargs[
273- 'object_id'], kwargs['key'][:6],) # -> md5_hexdigest?
274- cookie = cookies.get(cookie_name)
275- if cookie:
276- kwargs['cookie'] = cookie
277- else:
278- kwargs['cookie__isnull'] = True
279-
280- try:
281- rating = Vote.objects.get(**kwargs)
282- return rating.score
283- except Vote.MultipleObjectsReturned:
284- pass
285- except Vote.DoesNotExist:
286- pass
287- return
288-
289- def get_iterable_range(self):
290- # started from 1, because 0 is equal to delete
291- return range(1, self.field.range)
292-
293- def add(self, score, user, ip_address, cookies={}, commit=True):
294- """add(score, user, ip_address)
295-
296- Used to add a rating to an object.
297-
298- """
299- try:
300- score = int(score)
301- except (ValueError, TypeError):
302- raise InvalidRating('%s is not a valid choice for %s' %
303- (score, self.field.name))
304-
305- delete = (score == 0)
306- if delete and not self.field.allow_delete:
307- raise CannotDeleteVote(
308- 'you are not allowed to delete votes for %s' % (self.field.name,))
309- # ... you're also can't delete your vote if you haven't permissions to change it. I leave this case for CannotChangeVote
310-
311- if score < 0 or score > self.field.range:
312- raise InvalidRating('%s is not a valid choice for %s' %
313- (score, self.field.name))
314-
315- is_anonymous = (user is None or not user.is_authenticated)
316- if is_anonymous and not self.field.allow_anonymous:
317- raise AuthRequired("user must be a user, not '%r'" % (user,))
318-
319- if is_anonymous:
320- user = None
321-
322- defaults = dict(
323- score=score,
324- ip_address=ip_address,
325- )
326-
327- kwargs = dict(
328- content_type=self.get_content_type(),
329- object_id=self.instance.pk,
330- key=self.field.key,
331- user=user,
332- )
333- if not user:
334- kwargs['ip_address'] = ip_address
335-
336- use_cookies = (self.field.allow_anonymous and self.field.use_cookies)
337- if use_cookies:
338- defaults['cookie'] = now().strftime(
339- '%Y%m%d%H%M%S%f') # -> md5_hexdigest?
340- # TODO: move 'vote-%d.%d.%s' to settings or something
341- cookie_name = 'vote-%d.%d.%s' % (kwargs['content_type'].pk, kwargs[
342- 'object_id'], kwargs['key'][:6],) # -> md5_hexdigest?
343- # try to get existent cookie value
344- cookie = cookies.get(cookie_name)
345- if not cookie:
346- kwargs['cookie__isnull'] = True
347- kwargs['cookie'] = cookie
348-
349- try:
350- rating, created = Vote.objects.get(**kwargs), False
351- except Vote.DoesNotExist:
352- if delete:
353- raise CannotDeleteVote(
354- 'attempt to find and delete your vote for %s is failed' % (self.field.name,))
355- if getattr(settings, 'RATINGS_VOTES_PER_IP', RATINGS_VOTES_PER_IP):
356- num_votes = Vote.objects.filter(
357- content_type=kwargs['content_type'],
358- object_id=kwargs['object_id'],
359- key=kwargs['key'],
360- ip_address=ip_address,
361- ).count()
362- if num_votes >= getattr(settings, 'RATINGS_VOTES_PER_IP', RATINGS_VOTES_PER_IP):
363- raise IPLimitReached()
364- kwargs.update(defaults)
365- if use_cookies:
366- # record with specified cookie was not found ...
367- # ... thus we need to replace old cookie (if presented) with new one
368- cookie = defaults['cookie']
369- # ... and remove 'cookie__isnull' (if presented) from .create()'s **kwargs
370- kwargs.pop('cookie__isnull', '')
371- rating, created = Vote.objects.create(**kwargs), True
372-
373- has_changed = False
374- if not created:
375- if self.field.can_change_vote:
376- has_changed = True
377- self.score -= rating.score
378- # you can delete your vote only if you have permission to
379- # change your vote
380- if not delete:
381- rating.score = score
382- rating.save()
383- else:
384- self.votes -= 1
385- rating.delete()
386- else:
387- raise CannotChangeVote()
388- else:
389- has_changed = True
390- self.votes += 1
391- if has_changed:
392- if not delete:
393- self.score += rating.score
394- if commit:
395- self.instance.save()
396- #setattr(self.instance, self.field.name, Rating(score=self.score, votes=self.votes))
397-
398- defaults = dict(
399- score=self.score,
400- votes=self.votes,
401- )
402-
403- kwargs = dict(
404- content_type=self.get_content_type(),
405- object_id=self.instance.pk,
406- key=self.field.key,
407- )
408-
409- try:
410- score, created = Score.objects.get(**kwargs), False
411- except Score.DoesNotExist:
412- kwargs.update(defaults)
413- score, created = Score.objects.create(**kwargs), True
414-
415- if not created:
416- score.__dict__.update(defaults)
417- score.save()
418-
419- # return value
420- adds = {}
421- if use_cookies:
422- adds['cookie_name'] = cookie_name
423- adds['cookie'] = cookie
424- if delete:
425- adds['deleted'] = True
426- return adds
427-
428- def delete(self, user, ip_address, cookies={}, commit=True):
429- return self.add(0, user, ip_address, cookies, commit)
430-
431- def _get_votes(self, default=None):
432- return getattr(self.instance, self.votes_field_name, default)
433-
434- def _set_votes(self, value):
435- return setattr(self.instance, self.votes_field_name, value)
436-
437- votes = property(_get_votes, _set_votes)
438-
439- def _get_score(self, default=None):
440- return getattr(self.instance, self.score_field_name, default)
441-
442- def _set_score(self, value):
443- return setattr(self.instance, self.score_field_name, value)
444-
445- score = property(_get_score, _set_score)
446-
447- def get_content_type(self):
448- if self.content_type is None:
449- self.content_type = ContentType.objects.get_for_model(
450- self.instance)
451- return self.content_type
452-
453- def _update(self, commit=False):
454- """Forces an update of this rating (useful for when Vote objects are
455- removed)."""
456- votes = Vote.objects.filter(
457- content_type=self.get_content_type(),
458- object_id=self.instance.pk,
459- key=self.field.key,
460- )
461- obj_score = sum([v.score for v in votes])
462- obj_votes = len(votes)
463-
464- score, created = Score.objects.get_or_create(
465- content_type=self.get_content_type(),
466- object_id=self.instance.pk,
467- key=self.field.key,
468- defaults=dict(
469- score=obj_score,
470- votes=obj_votes,
471- )
472- )
473- if not created:
474- score.score = obj_score
475- score.votes = obj_votes
476- score.save()
477- self.score = obj_score
478- self.votes = obj_votes
479- if commit:
480- self.instance.save()
481-
482-
483-class RatingCreator(object):
484-
485- def __init__(self, field):
486- self.field = field
487- self.votes_field_name = '%s_votes' % (self.field.name,)
488- self.score_field_name = '%s_score' % (self.field.name,)
489-
490- def __get__(self, instance, type=None):
491- if instance is None:
492- return self.field
493- #raise AttributeError('Can only be accessed via an instance.')
494- return RatingManager(instance, self.field)
495-
496- def __set__(self, instance, value):
497- if isinstance(value, Rating):
498- setattr(instance, self.votes_field_name, value.votes)
499- setattr(instance, self.score_field_name, value.score)
500- else:
501- raise TypeError("%s value must be a Rating instance, not '%r'" % (
502- self.field.name, value))
503-
504-
505-class RatingField(IntegerField):
506- """A rating field contributes two columns to the model instead of the
507- standard single column."""
508-
509- def __init__(self, *args, **kwargs):
510- if 'choices' in kwargs:
511- raise TypeError("%s invalid attribute 'choices'" %
512- (self.__class__.__name__,))
513- self.can_change_vote = kwargs.pop('can_change_vote', False)
514- self.weight = kwargs.pop('weight', 0)
515- self.range = kwargs.pop('range', 2)
516- self.allow_anonymous = kwargs.pop('allow_anonymous', False)
517- self.use_cookies = kwargs.pop('use_cookies', False)
518- self.allow_delete = kwargs.pop('allow_delete', False)
519- kwargs['editable'] = False
520- kwargs['default'] = 0
521- kwargs['blank'] = True
522- super(RatingField, self).__init__(*args, **kwargs)
523-
524- def contribute_to_class(self, cls, name):
525- self.name = name
526-
527- # Votes tally field
528- self.votes_field = PositiveIntegerField(
529- editable=False, default=0, blank=True)
530- cls.add_to_class('%s_votes' % (self.name,), self.votes_field)
531-
532- # Score sum field
533- self.score_field = IntegerField(
534- editable=False, default=0, blank=True)
535- cls.add_to_class('%s_score' % (self.name,), self.score_field)
536-
537- self.key = md5_hexdigest(self.name)
538-
539- field = RatingCreator(self)
540-
541- if not hasattr(cls, '_djangoratings'):
542- cls._djangoratings = []
543- cls._djangoratings.append(self)
544-
545- setattr(cls, name, field)
546-
547- def get_db_prep_save(self, value):
548- # XXX: what happens here?
549- pass
550-
551- def get_db_prep_lookup(self, lookup_type, value):
552- # TODO: hack in support for __score and __votes
553- # TODO: order_by on this field should use the weighted algorithm
554- raise NotImplementedError(self.get_db_prep_lookup)
555- # if lookup_type in ('score', 'votes'):
556- # lookup_type =
557- # return self.score_field.get_db_prep_lookup()
558- if lookup_type == 'exact':
559- return [self.get_db_prep_save(value)]
560- elif lookup_type == 'in':
561- return [self.get_db_prep_save(v) for v in value]
562- else:
563- return super(RatingField, self).get_db_prep_lookup(lookup_type, value)
564-
565- def formfield(self, **kwargs):
566- defaults = {'form_class': forms.RatingField}
567- defaults.update(kwargs)
568- return super(RatingField, self).formfield(**defaults)
569-
570- # TODO: flatten_data method
571-
572-
573-class AnonymousRatingField(RatingField):
574-
575- def __init__(self, *args, **kwargs):
576- kwargs['allow_anonymous'] = True
577- super(AnonymousRatingField, self).__init__(*args, **kwargs)
578
579=== removed file 'djangoratings/forms.py'
580--- djangoratings/forms.py 2016-12-13 18:28:51 +0000
581+++ djangoratings/forms.py 1970-01-01 00:00:00 +0000
582@@ -1,7 +0,0 @@
583-from django import forms
584-
585-__all__ = ('RatingField',)
586-
587-
588-class RatingField(forms.ChoiceField):
589- pass
590
591=== removed directory 'djangoratings/management'
592=== removed file 'djangoratings/management/__init__.py'
593=== removed directory 'djangoratings/management/commands'
594=== removed file 'djangoratings/management/commands/__init__.py'
595=== removed file 'djangoratings/management/commands/update_recommendations.py'
596--- djangoratings/management/commands/update_recommendations.py 2018-04-05 07:30:42 +0000
597+++ djangoratings/management/commands/update_recommendations.py 1970-01-01 00:00:00 +0000
598@@ -1,9 +0,0 @@
599-from django.core.management.base import BaseCommand, CommandError
600-
601-from djangoratings.models import SimilarUser
602-
603-
604-class Command(BaseCommand):
605-
606- def handle(self, *args, **options):
607- SimilarUser.objects.update_recommendations()
608
609=== removed file 'djangoratings/managers.py'
610--- djangoratings/managers.py 2016-12-13 18:28:51 +0000
611+++ djangoratings/managers.py 1970-01-01 00:00:00 +0000
612@@ -1,124 +0,0 @@
613-from django.db.models import Manager
614-from django.db.models.query import QuerySet
615-
616-from django.contrib.contenttypes.models import ContentType
617-import itertools
618-
619-
620-class VoteQuerySet(QuerySet):
621-
622- def delete(self, *args, **kwargs):
623- """Handles updating the related `votes` and `score` fields attached to
624- the model."""
625- # XXX: circular import
626- from fields import RatingField
627-
628- qs = self.distinct().values_list(
629- 'content_type', 'object_id').order_by('content_type')
630-
631- to_update = []
632- for content_type, objects in itertools.groupby(qs, key=lambda x: x[0]):
633- model_class = ContentType.objects.get(
634- pk=content_type).model_class()
635- if model_class:
636- to_update.extend(
637- list(model_class.objects.filter(pk__in=list(objects)[0])))
638-
639- retval = super(VoteQuerySet, self).delete(*args, **kwargs)
640-
641- # TODO: this could be improved
642- for obj in to_update:
643- for field in getattr(obj, '_djangoratings', []):
644- getattr(obj, field.name)._update(commit=False)
645- obj.save()
646-
647- return retval
648-
649-
650-class VoteManager(Manager):
651-
652- def get_query_set(self):
653- return VoteQuerySet(self.model)
654-
655- def get_for_user_in_bulk(self, objects, user):
656- objects = list(objects)
657- if len(objects) > 0:
658- ctype = ContentType.objects.get_for_model(objects[0])
659- votes = list(self.filter(content_type__pk=ctype.id,
660- object_id__in=[obj._get_pk_val()
661- for obj in objects],
662- user__pk=user.id))
663- vote_dict = dict([(vote.object_id, vote) for vote in votes])
664- else:
665- vote_dict = {}
666- return vote_dict
667-
668-
669-class SimilarUserManager(Manager):
670-
671- def get_recommendations(self, user, model_class, min_score=1):
672- from djangoratings.models import Vote, IgnoredObject
673-
674- content_type = ContentType.objects.get_for_model(model_class)
675-
676- params = dict(
677- v=Vote._meta.db_table,
678- sm=self.model._meta.db_table,
679- m=model_class._meta.db_table,
680- io=IgnoredObject._meta.db_table,
681- )
682-
683- objects = model_class._default_manager.extra(
684- tables=[params['v']],
685- where=[
686- '%(v)s.object_id = %(m)s.id and %(v)s.content_type_id = %%s' % params,
687- '%(v)s.user_id IN (select to_user_id from %(sm)s where from_user_id = %%s and exclude = 0)' % params,
688- '%(v)s.score >= %%s' % params,
689- # Exclude already rated maps
690- '%(v)s.object_id NOT IN (select object_id from %(v)s where content_type_id = %(v)s.content_type_id and user_id = %%s)' % params,
691- # IgnoredObject exclusions
692- '%(v)s.object_id NOT IN (select object_id from %(io)s where content_type_id = %(v)s.content_type_id and user_id = %%s)' % params,
693- ],
694- params=[content_type.id, user.id, min_score, user.id, user.id]
695- ).distinct()
696-
697- # objects = model_class._default_manager.filter(pk__in=content_type.votes.extra(
698- # where=['user_id IN (select to_user_id from %s where from_user_id = %d and exclude = 0)' % (self.model._meta.db_table, user.pk)],
699- # ).filter(score__gte=min_score).exclude(
700- # object_id__in=IgnoredObject.objects.filter(content_type=content_type, user=user).values_list('object_id', flat=True),
701- # ).exclude(
702- # object_id__in=Vote.objects.filter(content_type=content_type, user=user).values_list('object_id', flat=True)
703- # ).distinct().values_list('object_id', flat=True))
704-
705- return objects
706-
707- def update_recommendations(self):
708- # TODO: this is mysql only atm
709- # TODO: this doesnt handle scores that have multiple values (e.g. 10 points, 5 stars)
710- # due to it calling an agreement as score = score. We need to loop each rating instance
711- # and express the condition based on the range.
712- from djangoratings.models import Vote
713- from django.db import connection
714- cursor = connection.cursor()
715- cursor.execute('begin')
716- cursor.execute('truncate table %s' % (self.model._meta.db_table,))
717- cursor.execute("""insert into %(t1)s
718- (to_user_id, from_user_id, agrees, disagrees, exclude)
719- select v1.user_id, v2.user_id,
720- sum(if(v2.score = v1.score, 1, 0)) as agrees,
721- sum(if(v2.score != v1.score, 1, 0)) as disagrees, 0
722- from %(t2)s as v1
723- inner join %(t2)s as v2
724- on v1.user_id != v2.user_id
725- and v1.object_id = v2.object_id
726- and v1.content_type_id = v2.content_type_id
727- where v1.user_id is not null
728- and v2.user_id is not null
729- group by v1.user_id, v2.user_id
730- having agrees / (disagrees + 0.0001) > 3
731- on duplicate key update agrees = values(agrees), disagrees = values(disagrees);""" % dict(
732- t1=self.model._meta.db_table,
733- t2=Vote._meta.db_table,
734- ))
735- cursor.execute('commit')
736- cursor.close()
737
738=== removed directory 'djangoratings/migrations'
739=== removed file 'djangoratings/migrations/0001_initial.py'
740--- djangoratings/migrations/0001_initial.py 2016-12-13 18:28:51 +0000
741+++ djangoratings/migrations/0001_initial.py 1970-01-01 00:00:00 +0000
742@@ -1,90 +0,0 @@
743-# -*- coding: utf-8 -*-
744-from __future__ import unicode_literals
745-
746-from django.db import models, migrations
747-import django.utils.timezone
748-from django.conf import settings
749-
750-
751-class Migration(migrations.Migration):
752-
753- dependencies = [
754- ('contenttypes', '0002_remove_content_type_name'),
755- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
756- ]
757-
758- operations = [
759- migrations.CreateModel(
760- name='IgnoredObject',
761- fields=[
762- ('id', models.AutoField(verbose_name='ID',
763- serialize=False, auto_created=True, primary_key=True)),
764- ('object_id', models.PositiveIntegerField()),
765- ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
766- ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
767- ],
768- ),
769- migrations.CreateModel(
770- name='Score',
771- fields=[
772- ('id', models.AutoField(verbose_name='ID',
773- serialize=False, auto_created=True, primary_key=True)),
774- ('object_id', models.PositiveIntegerField()),
775- ('key', models.CharField(max_length=32)),
776- ('score', models.IntegerField()),
777- ('votes', models.PositiveIntegerField()),
778- ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
779- ],
780- ),
781- migrations.CreateModel(
782- name='SimilarUser',
783- fields=[
784- ('id', models.AutoField(verbose_name='ID',
785- serialize=False, auto_created=True, primary_key=True)),
786- ('agrees', models.PositiveIntegerField(default=0)),
787- ('disagrees', models.PositiveIntegerField(default=0)),
788- ('exclude', models.BooleanField(default=False)),
789- ('from_user', models.ForeignKey(
790- related_name='similar_users', to=settings.AUTH_USER_MODEL)),
791- ('to_user', models.ForeignKey(
792- related_name='similar_users_from', to=settings.AUTH_USER_MODEL)),
793- ],
794- ),
795- migrations.CreateModel(
796- name='Vote',
797- fields=[
798- ('id', models.AutoField(verbose_name='ID',
799- serialize=False, auto_created=True, primary_key=True)),
800- ('object_id', models.PositiveIntegerField()),
801- ('key', models.CharField(max_length=32)),
802- ('score', models.IntegerField()),
803- ('ip_address', models.GenericIPAddressField()),
804- ('cookie', models.CharField(max_length=32, null=True, blank=True)),
805- ('date_added', models.DateTimeField(
806- default=django.utils.timezone.now, editable=False)),
807- ('date_changed', models.DateTimeField(
808- default=django.utils.timezone.now, editable=False)),
809- ('content_type', models.ForeignKey(
810- related_name='votes', to='contenttypes.ContentType')),
811- ('user', models.ForeignKey(related_name='votes',
812- blank=True, to=settings.AUTH_USER_MODEL, null=True)),
813- ],
814- ),
815- migrations.AlterUniqueTogether(
816- name='vote',
817- unique_together=set(
818- [('content_type', 'object_id', 'key', 'user', 'ip_address', 'cookie')]),
819- ),
820- migrations.AlterUniqueTogether(
821- name='similaruser',
822- unique_together=set([('from_user', 'to_user')]),
823- ),
824- migrations.AlterUniqueTogether(
825- name='score',
826- unique_together=set([('content_type', 'object_id', 'key')]),
827- ),
828- migrations.AlterUniqueTogether(
829- name='ignoredobject',
830- unique_together=set([('content_type', 'object_id')]),
831- ),
832- ]
833
834=== removed file 'djangoratings/migrations/__init__.py'
835=== removed file 'djangoratings/models.py'
836--- djangoratings/models.py 2016-12-13 18:28:51 +0000
837+++ djangoratings/models.py 1970-01-01 00:00:00 +0000
838@@ -1,98 +0,0 @@
839-from datetime import datetime
840-
841-from django.db import models
842-from django.contrib.contenttypes.models import ContentType
843-from django.contrib.contenttypes.fields import GenericForeignKey
844-from django.contrib.auth.models import User
845-
846-try:
847- from django.utils.timezone import now
848-except ImportError:
849- now = datetime.now
850-
851-from managers import VoteManager, SimilarUserManager
852-
853-
854-class Vote(models.Model):
855- content_type = models.ForeignKey(ContentType, related_name='votes')
856- object_id = models.PositiveIntegerField()
857- key = models.CharField(max_length=32)
858- score = models.IntegerField()
859- user = models.ForeignKey(User, blank=True, null=True, related_name='votes')
860- ip_address = models.GenericIPAddressField()
861- cookie = models.CharField(max_length=32, blank=True, null=True)
862- date_added = models.DateTimeField(default=now, editable=False)
863- date_changed = models.DateTimeField(default=now, editable=False)
864-
865- objects = VoteManager()
866-
867- content_object = GenericForeignKey()
868-
869- class Meta:
870- unique_together = (('content_type', 'object_id',
871- 'key', 'user', 'ip_address', 'cookie'))
872-
873- def __unicode__(self):
874- return u"%s voted %s on %s" % (self.user_display, self.score, self.content_object)
875-
876- def save(self, *args, **kwargs):
877- self.date_changed = now()
878- super(Vote, self).save(*args, **kwargs)
879-
880- def user_display(self):
881- if self.user:
882- return '%s (%s)' % (self.user.username, self.ip_address)
883- return self.ip_address
884- user_display = property(user_display)
885-
886- def partial_ip_address(self):
887- ip = self.ip_address.split('.')
888- ip[-1] = 'xxx'
889- return '.'.join(ip)
890- partial_ip_address = property(partial_ip_address)
891-
892-
893-class Score(models.Model):
894- content_type = models.ForeignKey(ContentType)
895- object_id = models.PositiveIntegerField()
896- key = models.CharField(max_length=32)
897- score = models.IntegerField()
898- votes = models.PositiveIntegerField()
899-
900- content_object = GenericForeignKey()
901-
902- class Meta:
903- unique_together = (('content_type', 'object_id', 'key'),)
904-
905- def __unicode__(self):
906- return u"%s scored %s with %s votes" % (self.content_object, self.score, self.votes)
907-
908-
909-class SimilarUser(models.Model):
910- from_user = models.ForeignKey(User, related_name='similar_users')
911- to_user = models.ForeignKey(User, related_name='similar_users_from')
912- agrees = models.PositiveIntegerField(default=0)
913- disagrees = models.PositiveIntegerField(default=0)
914- exclude = models.BooleanField(default=False)
915-
916- objects = SimilarUserManager()
917-
918- class Meta:
919- unique_together = (('from_user', 'to_user'),)
920-
921- def __unicode__(self):
922- print u"%s %s similar to %s" % (self.from_user, self.exclude and 'is not' or 'is', self.to_user)
923-
924-
925-class IgnoredObject(models.Model):
926- user = models.ForeignKey(User)
927- content_type = models.ForeignKey(ContentType)
928- object_id = models.PositiveIntegerField()
929-
930- content_object = GenericForeignKey()
931-
932- class Meta:
933- unique_together = (('content_type', 'object_id'),)
934-
935- def __unicode__(self):
936- return self.content_object
937
938=== removed file 'djangoratings/runtests.py'
939--- djangoratings/runtests.py 2016-12-13 18:28:51 +0000
940+++ djangoratings/runtests.py 1970-01-01 00:00:00 +0000
941@@ -1,31 +0,0 @@
942-#!/usr/bin/env python
943-import sys
944-
945-from os.path import dirname, abspath
946-
947-from django.conf import settings
948-
949-if not settings.configured:
950- settings.configure(
951- DATABASE_ENGINE='sqlite3',
952- INSTALLED_APPS=[
953- 'django.contrib.auth',
954- 'django.contrib.contenttypes',
955- 'djangoratings',
956- ]
957- )
958-
959-from django.test.simple import run_tests
960-
961-
962-def runtests(*test_args):
963- if not test_args:
964- test_args = ['djangoratings']
965- parent = dirname(abspath(__file__))
966- sys.path.insert(0, parent)
967- failures = run_tests(test_args, verbosity=1, interactive=True)
968- sys.exit(failures)
969-
970-
971-if __name__ == '__main__':
972- runtests(*sys.argv[1:])
973
974=== removed directory 'djangoratings/templatetags'
975=== removed file 'djangoratings/templatetags/__init__.py'
976=== removed file 'djangoratings/templatetags/ratings_old.py'
977--- djangoratings/templatetags/ratings_old.py 2018-11-18 16:16:04 +0000
978+++ djangoratings/templatetags/ratings_old.py 1970-01-01 00:00:00 +0000
979@@ -1,101 +0,0 @@
980-"""Template tags for Django."""
981-# TODO: add in Jinja tags if Coffin is available
982-
983-from django import template
984-from django.contrib.contenttypes.models import ContentType
985-from django.db.models import ObjectDoesNotExist
986-
987-from djangoratings.models import Vote
988-from wl_utils import get_real_ip
989-
990-register = template.Library()
991-
992-
993-class RatingByRequestNode(template.Node):
994-
995- def __init__(self, request, obj, context_var):
996- self.request = request
997- self.obj, self.field_name = obj.split('.')
998- self.context_var = context_var
999-
1000- def render(self, context):
1001- try:
1002- request = django.template.Variable(self.request).resolve(context)
1003- obj = django.template.Variable(self.obj).resolve(context)
1004- field = getattr(obj, self.field_name)
1005- except (template.VariableDoesNotExist, AttributeError):
1006- return ''
1007- try:
1008- vote = field.get_rating_for_user(
1009- request.user, get_real_ip(request), request.COOKIES)
1010- context[self.context_var] = vote
1011- except ObjectDoesNotExist:
1012- context[self.context_var] = 0
1013- return ''
1014-
1015-
1016-def do_rating_by_request(parser, token):
1017- """
1018- Retrieves the ``Vote`` cast by a user on a particular object and
1019- stores it in a context variable. If the user has not voted, the
1020- context variable will be 0.
1021-
1022- Example usage::
1023-
1024- {% rating_by_request request on instance as vote %}
1025- """
1026-
1027- bits = token.contents.split()
1028- if len(bits) != 6:
1029- raise template.TemplateSyntaxError(
1030- "'%s' tag takes exactly five arguments" % bits[0])
1031- if bits[2] != 'on':
1032- raise template.TemplateSyntaxError(
1033- "second argument to '%s' tag must be 'on'" % bits[0])
1034- if bits[4] != 'as':
1035- raise template.TemplateSyntaxError(
1036- "fourth argument to '%s' tag must be 'as'" % bits[0])
1037- return RatingByRequestNode(bits[1], bits[3], bits[5])
1038-register.tag('rating_by_request', do_rating_by_request)
1039-
1040-
1041-class RatingByUserNode(RatingByRequestNode):
1042-
1043- def render(self, context):
1044- try:
1045- user = django.template.Variable(self.request).resolve(context)
1046- obj = django.template.Variable(self.obj).resolve(context)
1047- field = getattr(obj, self.field_name)
1048- except template.VariableDoesNotExist:
1049- return ''
1050- try:
1051- vote = field.get_rating_for_user(user)
1052- context[self.context_var] = vote
1053- except ObjectDoesNotExist:
1054- context[self.context_var] = 0
1055- return ''
1056-
1057-
1058-def do_rating_by_user(parser, token):
1059- """
1060- Retrieves the ``Vote`` cast by a user on a particular object and
1061- stores it in a context variable. If the user has not voted, the
1062- context variable will be 0.
1063-
1064- Example usage::
1065-
1066- {% rating_by_user user on instance as vote %}
1067- """
1068-
1069- bits = token.contents.split()
1070- if len(bits) != 6:
1071- raise template.TemplateSyntaxError(
1072- "'%s' tag takes exactly five arguments" % bits[0])
1073- if bits[2] != 'on':
1074- raise template.TemplateSyntaxError(
1075- "second argument to '%s' tag must be 'on'" % bits[0])
1076- if bits[4] != 'as':
1077- raise template.TemplateSyntaxError(
1078- "fourth argument to '%s' tag must be 'as'" % bits[0])
1079- return RatingByUserNode(bits[1], bits[3], bits[5])
1080-register.tag('rating_by_user', do_rating_by_user)
1081
1082=== removed file 'djangoratings/tests.py'
1083--- djangoratings/tests.py 2016-12-13 18:28:51 +0000
1084+++ djangoratings/tests.py 1970-01-01 00:00:00 +0000
1085@@ -1,184 +0,0 @@
1086-import unittest
1087-import random
1088-
1089-from django.db import models
1090-from django.contrib.auth.models import User
1091-from django.contrib.contenttypes.models import ContentType
1092-from django.conf import settings
1093-
1094-from exceptions import *
1095-from models import Vote, SimilarUser, IgnoredObject
1096-from fields import AnonymousRatingField, RatingField
1097-
1098-settings.RATINGS_VOTES_PER_IP = 1
1099-
1100-
1101-class RatingTestModel(models.Model):
1102- rating = AnonymousRatingField(range=2, can_change_vote=True)
1103- rating2 = RatingField(range=2, can_change_vote=False)
1104-
1105- def __unicode__(self):
1106- return unicode(self.pk)
1107-
1108-
1109-class RatingTestCase(unittest.TestCase):
1110-
1111- def testRatings(self):
1112- instance = RatingTestModel.objects.create()
1113-
1114- # Test adding votes
1115- instance.rating.add(score=1, user=None, ip_address='127.0.0.1')
1116- self.assertEquals(instance.rating.score, 1)
1117- self.assertEquals(instance.rating.votes, 1)
1118-
1119- # Test adding votes
1120- instance.rating.add(score=2, user=None, ip_address='127.0.0.2')
1121- self.assertEquals(instance.rating.score, 3)
1122- self.assertEquals(instance.rating.votes, 2)
1123-
1124- # Test changing of votes
1125- instance.rating.add(score=2, user=None, ip_address='127.0.0.1')
1126- self.assertEquals(instance.rating.score, 4)
1127- self.assertEquals(instance.rating.votes, 2)
1128-
1129- # Test users
1130- user = User.objects.create(username=str(random.randint(0, 100000000)))
1131- user2 = User.objects.create(username=str(random.randint(0, 100000000)))
1132-
1133- instance.rating.add(score=2, user=user, ip_address='127.0.0.3')
1134- self.assertEquals(instance.rating.score, 6)
1135- self.assertEquals(instance.rating.votes, 3)
1136-
1137- instance.rating2.add(score=2, user=user, ip_address='127.0.0.3')
1138- self.assertEquals(instance.rating2.score, 2)
1139- self.assertEquals(instance.rating2.votes, 1)
1140-
1141- self.assertRaises(IPLimitReached, instance.rating2.add,
1142- score=2, user=user2, ip_address='127.0.0.3')
1143-
1144- # Test deletion hooks
1145- Vote.objects.filter(ip_address='127.0.0.3').delete()
1146-
1147- instance = RatingTestModel.objects.get(pk=instance.pk)
1148-
1149- self.assertEquals(instance.rating.score, 4)
1150- self.assertEquals(instance.rating.votes, 2)
1151- self.assertEquals(instance.rating2.score, 0)
1152- self.assertEquals(instance.rating2.votes, 0)
1153-
1154-
1155-class RecommendationsTestCase(unittest.TestCase):
1156-
1157- def setUp(self):
1158- self.instance = RatingTestModel.objects.create()
1159- self.instance2 = RatingTestModel.objects.create()
1160- self.instance3 = RatingTestModel.objects.create()
1161- self.instance4 = RatingTestModel.objects.create()
1162- self.instance5 = RatingTestModel.objects.create()
1163-
1164- # Test users
1165- self.user = User.objects.create(
1166- username=str(random.randint(0, 100000000)))
1167- self.user2 = User.objects.create(
1168- username=str(random.randint(0, 100000000)))
1169-
1170- def testExclusions(self):
1171- Vote.objects.all().delete()
1172-
1173- self.instance.rating.add(
1174- score=1, user=self.user, ip_address='127.0.0.1')
1175- self.instance2.rating.add(
1176- score=1, user=self.user, ip_address='127.0.0.1')
1177- self.instance3.rating.add(
1178- score=1, user=self.user, ip_address='127.0.0.1')
1179- self.instance4.rating.add(
1180- score=1, user=self.user, ip_address='127.0.0.1')
1181- self.instance5.rating.add(
1182- score=1, user=self.user, ip_address='127.0.0.1')
1183- self.instance.rating.add(
1184- score=1, user=self.user2, ip_address='127.0.0.2')
1185-
1186- # we should only need to call this once
1187- SimilarUser.objects.update_recommendations()
1188-
1189- self.assertEquals(SimilarUser.objects.count(), 2)
1190-
1191- recs = list(SimilarUser.objects.get_recommendations(
1192- self.user2, RatingTestModel))
1193- self.assertEquals(len(recs), 4)
1194-
1195- ct = ContentType.objects.get_for_model(RatingTestModel)
1196-
1197- IgnoredObject.objects.create(
1198- user=self.user2, content_type=ct, object_id=self.instance2.pk)
1199-
1200- recs = list(SimilarUser.objects.get_recommendations(
1201- self.user2, RatingTestModel))
1202- self.assertEquals(len(recs), 3)
1203-
1204- IgnoredObject.objects.create(
1205- user=self.user2, content_type=ct, object_id=self.instance3.pk)
1206- IgnoredObject.objects.create(
1207- user=self.user2, content_type=ct, object_id=self.instance4.pk)
1208-
1209- recs = list(SimilarUser.objects.get_recommendations(
1210- self.user2, RatingTestModel))
1211- self.assertEquals(len(recs), 1)
1212- self.assertEquals(recs, [self.instance5])
1213-
1214- self.instance5.rating.add(
1215- score=1, user=self.user2, ip_address='127.0.0.2')
1216- recs = list(SimilarUser.objects.get_recommendations(
1217- self.user2, RatingTestModel))
1218- self.assertEquals(len(recs), 0)
1219-
1220- def testSimilarUsers(self):
1221- Vote.objects.all().delete()
1222-
1223- self.instance.rating.add(
1224- score=1, user=self.user, ip_address='127.0.0.1')
1225- self.instance2.rating.add(
1226- score=1, user=self.user, ip_address='127.0.0.1')
1227- self.instance3.rating.add(
1228- score=1, user=self.user, ip_address='127.0.0.1')
1229- self.instance4.rating.add(
1230- score=1, user=self.user, ip_address='127.0.0.1')
1231- self.instance5.rating.add(
1232- score=1, user=self.user, ip_address='127.0.0.1')
1233- self.instance.rating.add(
1234- score=1, user=self.user2, ip_address='127.0.0.2')
1235- self.instance2.rating.add(
1236- score=1, user=self.user2, ip_address='127.0.0.2')
1237- self.instance3.rating.add(
1238- score=1, user=self.user2, ip_address='127.0.0.2')
1239-
1240- SimilarUser.objects.update_recommendations()
1241-
1242- self.assertEquals(SimilarUser.objects.count(), 2)
1243-
1244- recs = list(SimilarUser.objects.get_recommendations(
1245- self.user2, RatingTestModel))
1246- self.assertEquals(len(recs), 2)
1247-
1248- self.instance4.rating.add(
1249- score=1, user=self.user2, ip_address='127.0.0.2')
1250-
1251- SimilarUser.objects.update_recommendations()
1252-
1253- self.assertEquals(SimilarUser.objects.count(), 2)
1254-
1255- recs = list(SimilarUser.objects.get_recommendations(
1256- self.user2, RatingTestModel))
1257- self.assertEquals(len(recs), 1)
1258- self.assertEquals(recs, [self.instance5])
1259-
1260- self.instance5.rating.add(
1261- score=1, user=self.user2, ip_address='127.0.0.2')
1262-
1263- SimilarUser.objects.update_recommendations()
1264-
1265- self.assertEquals(SimilarUser.objects.count(), 2)
1266-
1267- recs = list(SimilarUser.objects.get_recommendations(
1268- self.user2, RatingTestModel))
1269- self.assertEquals(len(recs), 0)
1270
1271=== removed file 'djangoratings/views.py'
1272--- djangoratings/views.py 2016-12-13 18:28:51 +0000
1273+++ djangoratings/views.py 1970-01-01 00:00:00 +0000
1274@@ -1,138 +0,0 @@
1275-from django.contrib.contenttypes.models import ContentType
1276-from django.core.exceptions import ObjectDoesNotExist
1277-from django.http import HttpResponse, Http404
1278-
1279-from exceptions import *
1280-from django.conf import settings
1281-from default_settings import RATINGS_VOTES_PER_IP
1282-from wl_utils import get_real_ip
1283-
1284-
1285-class AddRatingView(object):
1286-
1287- def __call__(self, request, content_type_id, object_id, field_name, score):
1288- """__call__(request, content_type_id, object_id, field_name, score)
1289-
1290- Adds a vote to the specified model field.
1291-
1292- """
1293-
1294- try:
1295- instance = self.get_instance(content_type_id, object_id)
1296- except ObjectDoesNotExist:
1297- raise Http404('Object does not exist')
1298-
1299- context = self.get_context(request)
1300- context['instance'] = instance
1301-
1302- try:
1303- field = getattr(instance, field_name)
1304- except AttributeError:
1305- return self.invalid_field_response(request, context)
1306-
1307- context.update({
1308- 'field': field,
1309- 'score': score,
1310- })
1311-
1312- had_voted = bool(field.get_rating_for_user(
1313- request.user, get_real_ip(request), request.COOKIES))
1314-
1315- context['had_voted'] = had_voted
1316-
1317- try:
1318- adds = field.add(score, request.user,
1319- get_real_ip(request), request.COOKIES)
1320- except IPLimitReached:
1321- return self.too_many_votes_from_ip_response(request, context)
1322- except AuthRequired:
1323- return self.authentication_required_response(request, context)
1324- except InvalidRating:
1325- return self.invalid_rating_response(request, context)
1326- except CannotChangeVote:
1327- return self.cannot_change_vote_response(request, context)
1328- except CannotDeleteVote:
1329- return self.cannot_delete_vote_response(request, context)
1330- if had_voted:
1331- return self.rating_changed_response(request, context, adds)
1332- return self.rating_added_response(request, context, adds)
1333-
1334- def get_context(self, request, context={}):
1335- return context
1336-
1337- def render_to_response(self, template, context, request):
1338- raise NotImplementedError
1339-
1340- def too_many_votes_from_ip_response(self, request, context):
1341- response = HttpResponse(
1342- 'Too many votes from this IP address for this object.')
1343- return response
1344-
1345- def rating_changed_response(self, request, context, adds={}):
1346- response = HttpResponse('Vote changed.')
1347- if 'cookie' in adds:
1348- cookie_name, cookie = adds['cookie_name'], adds['cookie']
1349- if 'deleted' in adds:
1350- response.delete_cookie(cookie_name)
1351- else:
1352- # TODO: move cookie max_age to settings
1353- response.set_cookie(cookie_name, cookie, 31536000, path='/')
1354- return response
1355-
1356- def rating_added_response(self, request, context, adds={}):
1357- response = HttpResponse('Vote recorded.')
1358- if 'cookie' in adds:
1359- cookie_name, cookie = adds['cookie_name'], adds['cookie']
1360- if 'deleted' in adds:
1361- response.delete_cookie(cookie_name)
1362- else:
1363- # TODO: move cookie max_age to settings
1364- response.set_cookie(cookie_name, cookie, 31536000, path='/')
1365- return response
1366-
1367- def authentication_required_response(self, request, context):
1368- response = HttpResponse('You must be logged in to vote.')
1369- response.status_code = 403
1370- return response
1371-
1372- def cannot_change_vote_response(self, request, context):
1373- response = HttpResponse('You have already voted.')
1374- response.status_code = 403
1375- return response
1376-
1377- def cannot_delete_vote_response(self, request, context):
1378- response = HttpResponse('You can\'t delete this vote.')
1379- response.status_code = 403
1380- return response
1381-
1382- def invalid_field_response(self, request, context):
1383- response = HttpResponse('Invalid field name.')
1384- response.status_code = 403
1385- return response
1386-
1387- def invalid_rating_response(self, request, context):
1388- response = HttpResponse('Invalid rating value.')
1389- response.status_code = 403
1390- return response
1391-
1392- def get_instance(self, content_type_id, object_id):
1393- return ContentType.objects.get(pk=content_type_id)\
1394- .get_object_for_this_type(pk=object_id)
1395-
1396-
1397-class AddRatingFromModel(AddRatingView):
1398-
1399- def __call__(self, request, model, app_label, object_id, field_name, score):
1400- """__call__(request, model, app_label, object_id, field_name, score)
1401-
1402- Adds a vote to the specified model field.
1403-
1404- """
1405- try:
1406- content_type = ContentType.objects.get(
1407- model=model, app_label=app_label)
1408- except ContentType.DoesNotExist:
1409- raise Http404('Invalid `model` or `app_label`.')
1410-
1411- return super(AddRatingFromModel, self).__call__(request, content_type.id,
1412- object_id, field_name, score)
1413
1414=== modified file 'media/css/base.css'
1415--- media/css/base.css 2018-11-18 16:16:04 +0000
1416+++ media/css/base.css 2018-11-21 06:22:00 +0000
1417@@ -108,7 +108,7 @@
1418 font-weight: bold;
1419 }
1420
1421-.star-ratings input, button {
1422+.star-ratings input, .star-ratings button {
1423 padding: inherit;
1424 }
1425
1426
1427=== modified file 'settings.py'
1428--- settings.py 2018-11-19 17:19:29 +0000
1429+++ settings.py 2018-11-21 06:22:00 +0000
1430@@ -111,7 +111,6 @@
1431 'dj_pagination',
1432 'tagging',
1433 'star_ratings',
1434- 'djangoratings', # included as wlapp
1435 ]
1436
1437 MIDDLEWARE = [
1438
1439=== modified file 'templates/wlmaps/base.html'
1440--- templates/wlmaps/base.html 2018-11-18 11:31:20 +0000
1441+++ templates/wlmaps/base.html 2018-11-21 06:22:00 +0000
1442@@ -1,6 +1,5 @@
1443 {% extends "base.html" %}
1444 {% load static %}
1445-
1446 {% comment %}
1447 vim:ft=htmldjango
1448 {% endcomment %}
1449@@ -8,7 +7,7 @@
1450 {% block extra_head %}
1451 <link rel="stylesheet" type="text/css" media="all" href="{{ MEDIA_URL }}css/forum.css" />
1452 <link rel="stylesheet" type="text/css" media="all" href="{{ MEDIA_URL }}css/maps.css" />
1453-<link rel="stylesheet" href="{% static 'star-ratings/css/star-ratings.css' %}">
1454+<link rel="stylesheet" href="{% static 'star-ratings/css/star-ratings.css' %}" />
1455 <script type="text/javascript" src="{% static 'star-ratings/js/dist/star-ratings.min.js' %}"></script>
1456 {{block.super}}
1457 {% endblock %}
1458
1459=== modified file 'templates/wlmaps/index.html'
1460--- templates/wlmaps/index.html 2018-11-18 16:16:04 +0000
1461+++ templates/wlmaps/index.html 2018-11-21 06:22:00 +0000
1462@@ -5,11 +5,9 @@
1463
1464 {% load custom_date %}
1465 {% load wlprofile_extras %}
1466-{% load wlmaps_extra %}
1467 {% load threadedcommentstags %}
1468 {% load pagination_tags %}
1469 {% load ratings %}
1470-{% load ratings_old %}
1471
1472 {% block content_header %}
1473 <h1>Maps</h1>
1474@@ -59,7 +57,7 @@
1475 <td class="grey">Rating:</td>
1476 <td>
1477 {% ratings map read_only template_name='star_rating/average.html' %}
1478- {{ map.rating|average_rating }} ({{ map.rating.votes }} Votes)</td>
1479+ </td>
1480 <td class="spacer"></td>
1481 {% get_comment_count for map as ccount %}
1482 <td class="grey">Comments:</td><td>{{ ccount }}</td>
1483
1484=== modified file 'templates/wlmaps/map_detail.html'
1485--- templates/wlmaps/map_detail.html 2018-11-18 16:16:04 +0000
1486+++ templates/wlmaps/map_detail.html 2018-11-21 06:22:00 +0000
1487@@ -4,35 +4,16 @@
1488 {% endcomment %}
1489
1490 {% load custom_date %}
1491-{% load wlmaps_extra %}
1492 {% load wlprofile_extras %}
1493 {% load threadedcommentstags %}
1494 {% load wl_markdown %}
1495 {% load ratings %}
1496-{% load ratings_old %}
1497
1498 {% block title %}{{ map.name }} - {{ block.super }}{% endblock %}
1499
1500 {% block extra_head %}
1501 {{ block.super }}
1502-<link rel="stylesheet" type="text/css" media="all" href="{{ MEDIA_URL }}css/comments.css" />
1503-{% if not user.is_anonymous %}
1504-<script src="{{ MEDIA_URL}}/js/jquery.sexy-vote.js" type="text/javascript"></script>
1505-<script type="text/javascript">
1506-$(function() {
1507- $('#vote').sexyVote( {
1508- activeImageSrc: "{{ MEDIA_URL }}img/active_star.gif",
1509- passiveImageSrc: "{{ MEDIA_URL }}img/passive_star.gif",
1510- maxScore: 10,
1511- messages: ["","","","","","","","","",""],
1512- fn: function(e, score) {
1513- $.post("{% url 'wlmaps_rate' map.slug %}",{ vote: score });
1514- }
1515- });
1516-});
1517-</script>
1518-
1519-{% endif %}
1520+ <link rel="stylesheet" type="text/css" media="all" href="{{ MEDIA_URL }}css/comments.css" />
1521 {% endblock %}
1522
1523 {% block content_header %}
1524@@ -97,13 +78,8 @@
1525 </tr>
1526 <tr>
1527 <td class="grey">Rating:</td>
1528- <td>{% ratings map template_name='star_rating/rate.html' %}
1529- {{ map.rating|average_rating }} ({{ map.rating.votes }} Votes)
1530- {% if not user.is_anonymous %}
1531- <span id="vote"></span>
1532- {% else %}
1533- - Login to vote
1534- {% endif %}
1535+ <td>
1536+ {% ratings map template_name='star_rating/rate.html' %}
1537 </td>
1538 </tr>
1539 <tr>
1540
1541=== added file 'wlmaps/migrations/0002_auto_20181119_1855.py'
1542--- wlmaps/migrations/0002_auto_20181119_1855.py 1970-01-01 00:00:00 +0000
1543+++ wlmaps/migrations/0002_auto_20181119_1855.py 2018-11-21 06:22:00 +0000
1544@@ -0,0 +1,33 @@
1545+# -*- coding: utf-8 -*-
1546+# Generated by Django 1.11.12 on 2018-11-19 18:55
1547+from __future__ import unicode_literals
1548+
1549+from django.db import migrations, models
1550+
1551+
1552+class Migration(migrations.Migration):
1553+
1554+ dependencies = [
1555+ ('wlmaps', '0001_initial'),
1556+ ]
1557+
1558+ operations = [
1559+ migrations.RemoveField(
1560+ model_name='map',
1561+ name='rating_score',
1562+ ),
1563+ migrations.RemoveField(
1564+ model_name='map',
1565+ name='rating_votes',
1566+ ),
1567+ migrations.AlterField(
1568+ model_name='map',
1569+ name='hint',
1570+ field=models.TextField(blank=True, verbose_name=b'Hint'),
1571+ ),
1572+ migrations.AlterField(
1573+ model_name='map',
1574+ name='world_name',
1575+ field=models.CharField(blank=True, max_length=50),
1576+ ),
1577+ ]
1578
1579=== modified file 'wlmaps/models.py'
1580--- wlmaps/models.py 2018-11-18 16:16:04 +0000
1581+++ wlmaps/models.py 2018-11-21 06:22:00 +0000
1582@@ -11,8 +11,6 @@
1583 except ImportError:
1584 notification = None
1585
1586-from djangoratings.fields import AnonymousRatingField
1587-
1588
1589 class Map(models.Model):
1590 name = models.CharField(max_length=255, unique=True)
1591@@ -38,7 +36,6 @@
1592 nr_downloads = models.PositiveIntegerField(
1593 verbose_name='Download count', default=0)
1594
1595- rating = AnonymousRatingField(range=10, can_change_vote=True)
1596
1597 class Meta:
1598 ordering = ('-pub_date',)
1599
1600=== removed directory 'wlmaps/templatetags'
1601=== removed file 'wlmaps/templatetags/__init__.py'
1602=== removed file 'wlmaps/templatetags/wlmaps_extra.py'
1603--- wlmaps/templatetags/wlmaps_extra.py 2018-11-18 16:16:04 +0000
1604+++ wlmaps/templatetags/wlmaps_extra.py 1970-01-01 00:00:00 +0000
1605@@ -1,15 +0,0 @@
1606-#!/usr/bin/env python -tt
1607-# encoding: utf-8
1608-
1609-from django import template
1610-
1611-register = template.Library()
1612-
1613-
1614-@register.filter
1615-def average_rating(rating):
1616- if rating.votes > 0:
1617- avg = '%.1f' % (float(rating.score) / rating.votes)
1618- else:
1619- avg = '0.0'
1620- return 'Old: {}'.format(avg)
1621
1622=== modified file 'wlmaps/tests/test_views.py'
1623--- wlmaps/tests/test_views.py 2018-04-08 14:40:17 +0000
1624+++ wlmaps/tests/test_views.py 2018-11-21 06:22:00 +0000
1625@@ -143,66 +143,3 @@
1626 reverse('wlmaps_view', args=('a-map-that-doesnt-exist',)))
1627 self.assertEqual(c.status_code, 404)
1628
1629-
1630-############
1631-# RATING #
1632-############
1633-class TestWLMapsViews_Rating(_LoginToSite):
1634-
1635- def setUp(self):
1636- _LoginToSite.setUp(self)
1637-
1638- # Add maps
1639- nm = Map.objects.create(
1640- name='Map',
1641- author='Author',
1642- w=128,
1643- h=64,
1644- nr_players=4,
1645- descr='a good map to play with',
1646- minimap='/wlmaps/minimaps/Map.png',
1647- world_name='blackland',
1648-
1649- uploader=self.user,
1650- uploader_comment='Rockdamap'
1651- )
1652- nm.save()
1653- self.map = nm
1654-
1655- def test_RatingNonExistingMap_Except404(self):
1656- c = self.client.post(
1657- reverse('wlmaps_rate', args=('a-map-that-doesnt-exist',)),
1658- {'vote': 10})
1659- self.assertEqual(c.status_code, 404)
1660-
1661- def test_RatingGet_Except405(self):
1662- c = self.client.get(
1663- reverse('wlmaps_rate', args=('map',)),
1664- {'vote': 10})
1665- self.assertEqual(c.status_code, 405)
1666-
1667- def test_RatingInvalidValue_Except400(self):
1668- c = self.client.post(
1669- reverse('wlmaps_rate', args=('map',)),
1670- {'vote': 11})
1671- self.assertEqual(c.status_code, 400)
1672-
1673- def test_RatingNonIntegerValue_Except400(self):
1674- c = self.client.post(
1675- reverse('wlmaps_rate', args=('map',)),
1676- {'vote': 'shubidu'})
1677- self.assertEqual(c.status_code, 400)
1678-
1679- def test_RatingExistingMap_ExceptCorrectResult(self):
1680- c = self.client.post(
1681- reverse('wlmaps_rate', args=('map',)),
1682- {'vote': 7})
1683- # Except redirect
1684- self.assertEqual(c.status_code, 302)
1685-
1686- # We have to refetch this map, because
1687- # votes doesn't hit the database
1688- m = Map.objects.get(slug='map')
1689-
1690- self.assertEqual(m.rating.votes, 1)
1691- self.assertEqual(m.rating.score, 7)
1692
1693=== modified file 'wlmaps/urls.py'
1694--- wlmaps/urls.py 2016-12-13 18:28:51 +0000
1695+++ wlmaps/urls.py 2018-11-21 06:22:00 +0000
1696@@ -4,6 +4,7 @@
1697 from models import Map
1698 from views import *
1699
1700+
1701 urlpatterns = [
1702 url(r'^$', index, name='wlmaps_index'),
1703 url(r'^upload/$', upload, name='wlmaps_upload'),
1704@@ -14,7 +15,4 @@
1705 edit_comment, name='wlmaps_edit_comment'),
1706 url(r'^(?P<map_slug>[-\w]+)/download/$',
1707 download, name='wlmaps_download'),
1708-
1709- url(r'^(?P<map_slug>[-\w]+)/rate/$',
1710- rate, name='wlmaps_rate'),
1711 ]
1712
1713=== modified file 'wlmaps/views.py'
1714--- wlmaps/views.py 2018-04-08 14:40:17 +0000
1715+++ wlmaps/views.py 2018-11-21 06:22:00 +0000
1716@@ -24,31 +24,6 @@
1717 })
1718
1719
1720-def rate(request, map_slug):
1721- """Rate a given map."""
1722- if request.method != 'POST':
1723- return HttpResponseNotAllowed(['post'])
1724-
1725- m = get_object_or_404(models.Map, slug=map_slug)
1726-
1727- if not 'vote' in request.POST:
1728- return HttpResponseBadRequest()
1729- try:
1730- val = int(request.POST['vote'])
1731- except ValueError:
1732- return HttpResponseBadRequest()
1733-
1734- if not (0 < val <= 10):
1735- return HttpResponseBadRequest()
1736-
1737- m.rating.add(score=val, user=request.user,
1738- ip_address=get_real_ip(request))
1739-
1740- # m.save() is called in djangoratings.fields.add for each instance
1741-
1742- return HttpResponseRedirect(reverse('wlmaps_view', kwargs= {'map_slug': m.slug}))
1743-
1744-
1745 def download(request, map_slug):
1746 """Very simple view that just returns the binary data of this map and
1747 increases the download count."""

Subscribers

People subscribed via source and target branches