Commit 2f24436a authored by luxcem's avatar luxcem

Change vote to use django-und

parent a8b051fc
from django.contrib import admin
from .models import Article, UnDVotes
from .models import Article
admin.site.register(Article)
admin.site.register(UnDVotes)
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-04-25 15:00
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('rp', '0009_auto_20170423_1633'),
]
operations = [
migrations.RemoveField(
model_name='undvotes',
name='content_type',
),
migrations.RemoveField(
model_name='article',
name='und_score',
),
migrations.DeleteModel(
name='UnDVotes',
),
]
from .vote import UnDVotes, UnDVotedMixin # noqa
from .article import Article # noqa
from django.db import models
from django.utils.translation import ugettext_lazy as _
from taggit.managers import TaggableManager
from .vote import UnDVotedMixin
from newspaper import Article as ArticleParser
from django_und.models import VoteMixin
STATUS_CHOICES = (
......@@ -12,7 +13,7 @@ STATUS_CHOICES = (
)
class Article(UnDVotedMixin):
class Article(VoteMixin):
url = models.URLField("URL")
lang = models.CharField(_("Language"), max_length=50, null=True)
metadata = models.TextField(_("Opengraph metadata"), blank=True, null=True)
......
from django.db import models
from django.db.models import Sum, F
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
class UnDVotes(models.Model):
"""
Up and down vote model
"""
#: username
username = models.CharField(max_length=255, null=False)
#: Score of the vote
score = models.IntegerField(default=1)
# Django generic relation
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
#: The Voted object
content_object = GenericForeignKey("content_type", "object_id")
class Meta:
verbose_name = _("Vote")
verbose_name_plural = _("Votes")
def __str__(self):
return "{}:{}:{}".format(
self.username, self.content_object, self.score)
class UnDVotedMixin(models.Model):
"""
A mixin to attach to a model that has up and down votes
"""
#: Votes
und_votes = GenericRelation(UnDVotes)
#: Score of the model
und_score = models.IntegerField(default=0)
und_score_up = models.IntegerField(default=0)
und_score_down = models.IntegerField(default=0)
class Meta:
abstract = True
def upvote(self, username):
diff_score = 0
try:
# Already voted content
vote = self.und_votes.get(username=username)
if vote.score == 1:
# Cancel previous upvote
vote.delete()
diff_score = -1
else:
# Previously downvoted
vote.score = 1
vote.save()
diff_score = 2
except:
vote = UnDVotes(content_object=self, username=username, score=1)
vote.save()
diff_score = 1
self.und_score += diff_score
self.und_score_up += diff_score
# Update self score, use update and filter to avoid triggering signals
self.__class__.objects.filter(id=self.id).update(
und_score=F("und_score") + diff_score,
und_score_up=F("und_score_up") + diff_score
)
def downvote(self, username):
diff_score = 0
try:
# Already voted content
vote = self.und_votes.get(username=username)
if vote.score == -1:
# Cancel previous downvote
vote.delete()
diff_score = 1
else:
# Previously upvoted
vote.score = -1
vote.save()
diff_score = -2
except:
vote = UnDVotes(content_object=self, username=username, score=-1)
vote.save()
diff_score = -1
self.und_score += diff_score
self.und_score_down += diff_score
# Update self score, use update and filter to avoid triggering signals
self.__class__.objects.filter(id=self.id).update(
und_score=F("und_score") + diff_score,
und_score_down=F("und_score_down") + diff_score
)
def update_und_score(self):
"""Reset score to the correct count (should not be necessary)"""
score_up = self.und_votes.filter(score=1).count()
score_down = self.und_votes.filter(score=-1).count()
score = score_up + score_down
self.und_score_up = score_up
self.und_score_down = score_down
self.und_score = score
# Update self score, use update and filter to avoid triggering signals
self.__class__.objects.filter(id=self.id).update(und_score=score)
from django.test import TestCase
from rp.models import Article
from rp.factories import ArticleFactory
from rp.apps import RpConfig
def test_init():
assert RpConfig.name == "rp"
def test_article():
article = ArticleFactory()
assert type(article) == Article
def test_votes():
article = ArticleFactory()
# Upvote
article.upvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == 1
assert article_db.und_score == 1
votes = article_db.und_votes.all()
assert len(votes) == 1
assert str(votes[0]) == "{}:{}:{}".format(
"test_user", str(article_db), 1)
# Upvote -> upvote
article.upvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == 0
assert article_db.und_score == 0
# 0 -> downvote
article.downvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == -1
assert article_db.und_score == -1
# Downvote -> Downvote
article.downvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == 0
assert article_db.und_score == 0
# Downvote -> Upvote
article.downvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == -1
assert article_db.und_score == -1
article.upvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == 1
assert article_db.und_score == 1
class TestVote(TestCase):
def setUp(self):
self.article = ArticleFactory()
# Upvote -> Downwote
article.downvote("test_user")
article_db = Article.objects.get(id=article.id)
assert article.und_score == -1
assert article_db.und_score == -1
def test_init(self):
assert RpConfig.name == "rp"
article.update_und_score()
article_db = Article.objects.get(id=article.id)
assert article.und_score == -1
assert article_db.und_score == -1
def test_article(self):
assert type(self.article) == Article
from django.urls import reverse
from django.test import TestCase
from django.contrib.contenttypes.models import ContentType
from userprofile.factories import ProfileFactory
from rp.factories import ArticleFactory
......@@ -10,30 +9,25 @@ from rp.models import Article
class VoteViewTestCase(TestCase):
def setUp(self):
self.article = ArticleFactory()
self.content_type = ContentType.objects.get_for_model(
self.article
).pk
self.profile = ProfileFactory()
self.user = self.profile.user
self.client.force_login(self.user)
def test_votes(self):
url_upvote = reverse("und-upvote", kwargs={
"content_type": self.content_type,
"object_id": self.article.id
url_upvote = reverse("api:article-upvote", kwargs={
"pk": self.article.id
})
url_downvote = reverse("und-downvote", kwargs={
"content_type": self.content_type,
"object_id": self.article.id
url_downvote = reverse("api:article-downvote", kwargs={
"pk": self.article.id
})
response = self.client.get(url_upvote)
response = self.client.post(url_upvote)
assert response.status_code == 200
article_db = Article.objects.get(id=self.article.id)
assert article_db.und_score == 1
response = self.client.get(url_downvote)
response = self.client.post(url_downvote)
assert response.status_code == 200
article_db = Article.objects.get(id=self.article.id)
assert article_db.und_score == -1
......@@ -14,12 +14,12 @@ class UDList(ListView):
"upvoted": queryset.filter(
und_votes__username=self.request.user.username,
und_votes__content_type=content_type,
und_votes__score=1
und_votes__score__gt=0
).values_list("id", flat=True),
"downvoted": queryset.filter(
und_votes__username=self.request.user.username,
und_votes__content_type=content_type,
und_votes__score=-1
und_votes__score__lt=0
).values_list("id", flat=True)
}
return context
......@@ -16,6 +16,7 @@ DJANGO_APPS = [
CONTRIB_APPS = [
"django_extensions", # http://django-extensions.readthedocs.io/
"rest_framework", # http://www.django-rest-framework.org/
"django_und", # https://github.com/luxcem/django_und
# https://github.com/philipn/django-rest-framework-filters
# "rest_framework_filters",
"taggit",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment