article.py 4.12 KB
Newer Older
cynddl's avatar
cynddl committed
1
from django.db import models
cynddl's avatar
cynddl committed
2
from django.utils.translation import ugettext_lazy as _
luxcem's avatar
luxcem committed
3

cynddl's avatar
cynddl committed
4
from taggit.managers import TaggableManager
luxcem's avatar
luxcem committed
5
from newspaper import Article as ArticleParser
luxcem's avatar
luxcem committed
6
from django_und.models import VoteMixin
7
from django_fsm import FSMField, transition, RETURN_VALUE
luxcem's avatar
luxcem committed
8

9
10
from datetime import datetime

cynddl's avatar
cynddl committed
11

12
13
ARTICLE_SCORE_THRESHOLD = 3

luxcem's avatar
luxcem committed
14
STATUS_CHOICES = (
15
16
    ("NEW", _("New")),
    ("DRAFT", _("Draft")),
luxcem's avatar
luxcem committed
17
18
19
20
    ("PUBLISHED", _("Published")),
    ("REJECTED", _("Rejected"))
)

21
22
23
24
25
26
LANG_CHOICES = (
    ("FR", _("French")),
    ("EN", _("English")),
    ("NA", _("Other"))
)

27
28
29
30
31
32
33
34
35
36
URL_HELP_TEXT = """The URL should not contain any marketing tags. We
automatically strip the most known tags."""

TITLE_HELP_TEXT = """Please remove non-necessary parts such as newspapers'
names and leave only the article title."""

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."""

luxcem's avatar
luxcem committed
37

luxcem's avatar
luxcem committed
38
class Article(VoteMixin):
39
40
    status = FSMField(default='NEW', choices=STATUS_CHOICES, protected=True)

41
    url = models.URLField("URL", help_text=URL_HELP_TEXT)
42
43
    lang = models.CharField(
        _("Language"), choices=LANG_CHOICES, default="NA", max_length=50)
44
45
46
47
48
49
50
    metadata = models.TextField(
        _("Opengraph metadata"), blank=True, null=True)
    screenshot = models.ImageField(
        _("Article screenshot"), blank=True, null=True)
    title = models.CharField(
        _("Article title"), max_length=255, default="",
        help_text=TITLE_HELP_TEXT)
cynddl's avatar
cynddl committed
51
    website = models.CharField(_("Website"), max_length=255, default="")
52
53
54
    extracts = models.TextField(
        _("Content extracts"), blank=True, null=True,
        help_text=EXTRACTS_HELP_TEXT)
cynddl's avatar
cynddl committed
55
56
57

    created_at = models.DateTimeField(_("Creation date"), auto_now_add=True)
    updated_at = models.DateTimeField(_("Last update"), auto_now=True)
58
59
    published_at = models.DateTimeField(
        _("Publication date"), blank=True, null=True)
cynddl's avatar
cynddl committed
60

luxcem's avatar
luxcem committed
61
62
    #: priority: True if article have priority
    priority = models.BooleanField(default=False)
63

64
    tags = TaggableManager(blank=True)
65

66
67
68
    class Meta:
        verbose_name = _("Article")
        verbose_name_plural = _("Articles")
luxcem's avatar
luxcem committed
69
70
71
72
73
        permissions = (
            ("can_change_status", "Can change article status"),
            ("can_change_priority", "Can change article priority"),
            ("can_vote", "Can vote articles"),
        )
luxcem's avatar
luxcem committed
74
75
76

    def __str__(self):
        return self.title
dave's avatar
dave committed
77

78
    # Finite state logic
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    @transition(field=status, source='DRAFT', target='PUBLISHED')
    def publish(self):
        self.published_at = datetime.now()

    @transition(field=status, source='NEW', target='DRAFT',
                permission="can_change_status")
    def recover(self):
        pass

    @transition(field=status, source=['NEW', 'DRAFT'], target='REJECTED',
                permission="can_change_status")
    def reject(self):
        pass

    @transition(field=status, source='DRAFT', target='DRAFT',
                permission="can_change_priority")
    def set_priority(self, value):
        self.priority = value

    @transition(field=status, source='DRAFT', target='DRAFT')
    @transition(field=status, source='NEW',
                target=RETURN_VALUE('NEW', 'DRAFT'), permission="can_vote")
    def upvote(self, user_object):
        super(Article, self).upvote(user_object)
        if self.und_score >= ARTICLE_SCORE_THRESHOLD:
            return 'DRAFT'
        else:
            return self.status

    @transition(field=status, source='NEW', target='NEW', permission="can_vote")
    @transition(field=status, source='DRAFT', target='DRAFT',
                permission="can_vote")
    def downvote(self, user_object):
        super(Article, self).downvote(user_object)

    # Content extraction
116

dave's avatar
dave committed
117
    def parse(self):
118
119
        lang_lower = self.lang.lower() if self.lang != "NA" else None
        article = ArticleParser(url=self.url, language=lang_lower)
dave's avatar
dave committed
120
121
122
123
124
125
        article.download()
        article.parse()
        self.title = article.title
        self.extracts = article.text
        # self.screenshot = getScreenshot(self.url)
        # TODO: save metadata