Commit e4e93a34 authored by okhin's avatar okhin 🚴

Remving the django-und system for a classic score like system

parent 8dac2f43
......@@ -22,23 +22,14 @@ class ArticleSerializer(serializers.ModelSerializer):
tags = TagListSerializer(help_text="""
List of short tags to describe the article (eg."Privacy, Copyright").
Must be a list of tags, coma separated (or an empty string).
""")
und_score_up = serializers.IntegerField(
required=False,
help_text="This is used to increase the vote count by this value")
und_score_down = serializers.IntegerField(
required=False,
help_text="This is used to decrease the vote count by this value")
und_score = serializers.IntegerField(
required=False,
help_text="This is the actual computed score for an Article")
""", default="")
class Meta:
model = Article
fields = ('id', 'url', 'title', 'tags', 'extracts', 'status',
'und_score_up', 'und_score_down', 'und_score')
fields = ('id', 'url', 'title', 'tags', 'extracts', 'status', 'score')
def create(self, validated_data):
article = Article.add_new_url(**validated_data)
article.save()
if article is not None:
article.save()
return article
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2019-05-07 14:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rp', '0020_article_original_status'),
]
operations = [
migrations.RemoveField(
model_name='article',
name='und_score_down',
),
migrations.RemoveField(
model_name='article',
name='und_score_up',
),
migrations.AddField(
model_name='article',
name='score',
field=models.IntegerField(default=0),
),
]
......@@ -4,7 +4,6 @@ from django.core import files
from taggit.managers import TaggableManager
from newspaper import Article as ArticleParser, ArticleException
from django_und.models import VoteMixin
from django_fsm import FSMField, transition, RETURN_VALUE
from io import BytesIO
......@@ -38,7 +37,8 @@ EXTRACTS_HELP_TEXT = """Please select short and helpful extracts from the
article content. You should aim at around 500 characters. Use bracket ellipsis
[…] to cut parts not required to understand the context."""
class Article(VoteMixin):
class Article(models.Model):
#: Logical state (eg. article submitted, published, or rejected)
# This is unprotected because superuser should be able to change
# the status from the django admin interface
......@@ -94,6 +94,9 @@ class Article(VoteMixin):
#: Comma separated list of short tags to describe the article (eg: "Privacy", "Copyright").
tags = TaggableManager(blank=True)
#: Score of the article, modifiedby upvote and downvote methods
score = models.IntegerField(default=0)
class Meta:
verbose_name = _("Article")
verbose_name_plural = _("Articles")
......@@ -147,14 +150,14 @@ class Article(VoteMixin):
@transition(field=status, source='DRAFT', target='DRAFT')
@transition(field=status, source='NEW',
target=RETURN_VALUE('NEW', 'DRAFT'), permission="rp.can_vote")
def upvote(self, by=None):
def upvote(self):
"""
Upvote the article score for the given user and remove previous votes.
If the score crosses the threshold ```ARTICLE_SCORE_THRESHOLD```,
automatically moves the article from _NEW_ to _DRAFT_.
"""
super(Article, self).upvote(by)
if self.und_score >= ARTICLE_SCORE_THRESHOLD:
self.score += 1
if self.score >= ARTICLE_SCORE_THRESHOLD - 1:
return 'DRAFT'
else:
return self.status
......@@ -169,7 +172,7 @@ class Article(VoteMixin):
votes. Draft articles can be downvoted but will not be moved back in
the _NEW_ queue.
"""
super(Article, self).downvote(by)
self.score -= 1
@classmethod
def add_new_url(by=None, **data):
......@@ -184,13 +187,15 @@ class Article(VoteMixin):
(article, created) = Article.objects.get_or_create(url=url,
defaults=data)
# Let's add the tags
if tags:
article.tags.add(','.join([t for t in tags if len(t) > 0]))
# If the article was already there, we should upvote it
if not created:
article.upvote(str(by))
if article.status == "REJECTED":
return None
article.upvote()
# Let's add the tags
if tags:
article.tags.add(','.join([t for t in tags if len(t) > 0]))
try:
r = requests.get(url, timeout=0.5)
article.original_status = r.status_code
......
from django.test import TestCase
from django.urls import reverse
from userprofile.factories import ProfileFactory
from rp.factories import ArticleFactory
from rp.models import Article
class ArticleListTestCase(TestCase):
def setUp(self):
self.article = ArticleFactory(status='NEW')
self.article2 = ArticleFactory(status='NEW')
self.user = ProfileFactory().user
self.user2 = ProfileFactory().user
self.user3 = ProfileFactory().user
def test_empty_upvoted(self):
self.client.force_login(self.user)
response = self.client.get(reverse("rp:article-list", kwargs={
"filter_view": "flux"
}))
assert response.status_code == 200
# Get the context
context = response.context
assert context["und_votes"]["upvoted"].count() == 0
assert context["und_votes"]["downvoted"].count() == 0
def test_upvoted(self):
self.article.upvote(self.user.username)
self.client.force_login(self.user)
response = self.client.get(reverse("rp:article-list", kwargs={
"filter_view": "flux"
}))
assert list(
response.context["und_votes"]["upvoted"]) == [self.article.id]
assert list(
response.context["und_votes"]["downvoted"]) == []
def test_downvoted(self):
self.article.downvote(self.user.username)
self.client.force_login(self.user)
response = self.client.get(reverse("rp:article-list", kwargs={
"filter_view": "flux"
}))
assert list(
response.context["und_votes"]["upvoted"]) == []
assert list(
response.context["und_votes"]["downvoted"]) == [self.article.id]
def test_2users(self):
self.article.downvote(self.user.username)
self.article2.upvote(self.user.username)
self.article.upvote(self.user2.username)
self.client.force_login(self.user)
response = self.client.get(reverse("rp:article-list", kwargs={
"filter_view": "flux"
}))
assert list(
response.context["und_votes"]["upvoted"]) == [self.article2.id]
assert list(
response.context["und_votes"]["downvoted"]) == [self.article.id]
self.client.force_login(self.user2)
response = self.client.get(reverse("rp:article-list", kwargs={
"filter_view": "flux"
}))
assert list(
response.context["und_votes"]["upvoted"]) == [self.article.id]
assert list(
response.context["und_votes"]["downvoted"]) == []
def _test_filter_view(self, filter_view):
"""Return list of articles ids in filter_view"""
response = self.client.get(reverse("rp:article-list", kwargs={
"filter_view": filter_view
}))
return sorted(
response.context["object_list"].values_list('id', flat=True))
def test_filter_view(self):
self.article.upvote(self.user.username)
self.article.upvote(self.user2.username)
self.client.force_login(self.user)
assert self._test_filter_view("flux") == sorted(
[self.article.pk, self.article2.pk]
)
assert self._test_filter_view("published") == []
assert self._test_filter_view("draft") == []
assert self._test_filter_view("rejected") == []
self.article.upvote(self.user3.username)
assert self._test_filter_view("flux") == sorted(
[self.article.pk, self.article2.pk]
)
self.article.save()
assert self._test_filter_view("published") == []
assert self._test_filter_view("draft") == [self.article.id]
assert self._test_filter_view("rejected") == []
self.article2.reject()
self.article2.save()
assert self._test_filter_view("published") == []
assert self._test_filter_view("flux") == []
assert self._test_filter_view("draft") == [self.article.id]
assert self._test_filter_view("rejected") == [self.article2.id]
self.article.publish()
self.article.save()
assert self._test_filter_view("published") == [self.article.id]
assert self._test_filter_view("flux") == []
assert self._test_filter_view("draft") == []
assert self._test_filter_view("rejected") == [self.article2.id]
......@@ -39,12 +39,17 @@ class VoteViewTestCase(TestCase):
response = self.client.post(url_upvote)
self.assertEqual(response.status_code, 200)
article_db = Article.objects.get(id=self.article.id)
assert article_db.und_score == 1
assert article_db.score == 1
response = self.client.post(url_upvote)
self.assertEqual(response.status_code, 200)
article_db.refresh_from_db()
assert article_db.score == 2
response = self.client.post(url_downvote)
self.assertEqual(response.status_code, 200)
article_db = Article.objects.get(id=self.article.id)
assert article_db.und_score == -1
assert article_db.score == 1
def test_publish(self):
url_publish = reverse("api:article-publish", kwargs={
......
......@@ -19,7 +19,6 @@ from taggit.models import Tag
from rp.forms import TagMultipleChoiceField
from rp.models import Article
from .votes import UDList
class ArticleList(ListView):
......@@ -58,7 +57,7 @@ class ArticleList(ListView):
return context
class ArticleListFlux(LoginRequiredMixin, UDList):
class ArticleListFlux(LoginRequiredMixin, ListView):
model = Article
paginate_by = 10
......
from django.views.generic import ListView
from django.contrib.contenttypes.models import ContentType
class UDList(ListView):
"""
Adds id upvoted by user
"""
def get_context_data(self, **kwargs):
content_type = ContentType.objects.get_for_model(self.model)
queryset = self.get_queryset()
context = super().get_context_data(**kwargs)
context["und_votes"] = {
"upvoted": queryset.filter(
und_votes__username=self.request.user.username,
und_votes__content_type=content_type,
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__lt=0
).values_list("id", flat=True)
}
return context
......@@ -19,7 +19,6 @@ CONTRIB_APPS = [
"rest_framework", # http://www.django-rest-framework.org/
"rest_framework.authtoken",
"django_und", # https://github.com/luxcem/django_und
"taggit",
"crispy_forms",
"django_markdown2",
......
......@@ -3,7 +3,6 @@ djangorestframework==3.6.3
django-extensions==1.7.9
django-imagekit==4.0
django-taggit==0.22.0
django-und
Pillow==4.1.0
selenium
newspaper3k
......
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