Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
R
rp
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
14
Issues
14
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
La Quadrature du Net
rpteam
rp
Commits
206bfc61
Commit
206bfc61
authored
Jun 19, 2017
by
cynddl
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Document the Article model
parent
c32a9424
Pipeline
#1190
passed with stages
in 1 minute and 57 seconds
Changes
2
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
44 additions
and
33 deletions
+44
-33
apps/core/base.html
apps/core/base.html
+0
-0
apps/rp/models.py
apps/rp/models.py
+44
-33
No files found.
apps/core/base.html
deleted
100644 → 0
View file @
c32a9424
apps/rp/models.py
View file @
206bfc61
...
...
@@ -43,37 +43,60 @@ article content. You should aim at around 500 characters. Use bracket ellipsis
class
Article
(
VoteMixin
):
#: Logical state (eg. article submitted, published, or rejected)
status
=
FSMField
(
default
=
'NEW'
,
choices
=
STATUS_CHOICES
,
protected
=
True
)
#: Original URL
url
=
models
.
URLField
(
"URL"
,
help_text
=
URL_HELP_TEXT
)
#: Language of the webpage
lang
=
models
.
CharField
(
_
(
"Language"
),
choices
=
LANG_CHOICES
,
default
=
"NA"
,
max_length
=
50
)
#: Plain-text Opengraph metadata
metadata
=
models
.
TextField
(
_
(
"Opengraph metadata"
),
blank
=
True
,
null
=
True
)
#: Screenshot or banner image for the original webpage
screenshot
=
models
.
ImageField
(
_
(
"Article screenshot"
),
blank
=
True
,
null
=
True
)
#: Article title
title
=
models
.
CharField
(
_
(
"Article title"
),
max_length
=
255
,
default
=
""
,
help_text
=
TITLE_HELP_TEXT
)
#: Short name for the website (eg. "NY Times")
website
=
models
.
CharField
(
_
(
"Website"
),
max_length
=
255
,
default
=
""
)
#: Short content extracts (eg. two to three paragraphs)
extracts
=
models
.
TextField
(
_
(
"Content extracts"
),
blank
=
True
,
null
=
True
,
help_text
=
EXTRACTS_HELP_TEXT
)
#: First submission date
created_at
=
models
.
DateTimeField
(
_
(
"Creation date"
),
auto_now_add
=
True
)
#: Name of the user who first submitted the article
created_by
=
models
.
CharField
(
max_length
=
255
,
null
=
True
)
#: Last update date
updated_at
=
models
.
DateTimeField
(
_
(
"Last update"
),
auto_now
=
True
)
#: Published date
published_at
=
models
.
DateTimeField
(
_
(
"Publication date"
),
blank
=
True
,
null
=
True
)
#: priority: True if article have priority
priority
=
models
.
BooleanField
(
default
=
False
)
#: List of short tags to describe the article (eg. "Privacy", "Copyright")
tags
=
TaggableManager
(
blank
=
True
)
class
Meta
:
verbose_name
=
_
(
"Article"
)
verbose_name_plural
=
_
(
"Articles"
)
permissions
=
(
(
"can_change_status"
,
"Can change article status"
),
(
"can_change_priority"
,
"Can change article priority"
),
...
...
@@ -81,9 +104,11 @@ class Article(VoteMixin):
(
"can_edit"
,
"Can edit articles"
)
)
#: By default, sort articles by published, updated, or created date
ordering
=
[
"-published_at"
,
"-updated_at"
,
"-created_at"
]
def
__str__
(
self
):
""" Returns article title. """
return
self
.
title
# Finite state logic
...
...
@@ -91,32 +116,42 @@ class Article(VoteMixin):
@
transition
(
field
=
status
,
source
=
'DRAFT'
,
target
=
'PUBLISHED'
,
permission
=
"rp.can_change_status"
)
def
publish
(
self
):
""" Publish a complete draft. """
self
.
published_at
=
datetime
.
now
()
@
transition
(
field
=
status
,
source
=
'NEW'
,
target
=
'DRAFT'
,
permission
=
"rp.can_change_status"
)
def
recover
(
self
):
""" Force an article to be considered as a draft. """
pass
@
transition
(
field
=
status
,
source
=
[
'NEW'
,
'DRAFT'
],
target
=
'REJECTED'
,
permission
=
"rp.can_change_status"
)
def
reject
(
self
):
""" Manual rejection of the article. """
pass
@
transition
(
field
=
status
,
source
=
'DRAFT'
,
target
=
'DRAFT'
,
permission
=
"rp.can_change_priority"
)
def
set_priority
(
self
):
""" Set the boolean priority of an article to True. """
self
.
priority
=
True
@
transition
(
field
=
status
,
source
=
'DRAFT'
,
target
=
'DRAFT'
,
permission
=
"rp.can_change_priority"
)
def
unset_priority
(
self
):
""" Set the boolean priority of an article to False. """
self
.
priority
=
False
@
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
):
"""
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
:
return
'DRAFT'
...
...
@@ -127,9 +162,18 @@ class Article(VoteMixin):
@
transition
(
field
=
status
,
source
=
'DRAFT'
,
target
=
'DRAFT'
,
permission
=
"rp.can_vote"
)
def
downvote
(
self
,
by
=
None
):
"""
Downvote the article score for the given user and remove previous votes.
Draft articles can be downvoted but will not be moved back in the
_NEW_ queue.
"""
super
(
Article
,
self
).
downvote
(
by
)
def
add_new_url
(
url
,
by
=
None
):
""" Manually add a new article from its URL.
Verify if the article has not been submitted before and automatically
upvote for the given user if applicable.
"""
url
=
cleanup_url
(
url
)
article
,
_
=
Article
.
objects
.
get_or_create
(
url
=
url
)
...
...
@@ -179,36 +223,3 @@ class Article(VoteMixin):
self
.
screenshot
.
save
(
"screenshot-{0}.{1}"
.
format
(
self
.
id
,
file_name_ext
),
files
.
File
(
fp
),
save
=
True
)
def
fetch_screenshot
(
self
):
from
selenium
import
webdriver
from
selenium.webdriver.firefox.firefox_binary
import
FirefoxBinary
from
PIL
import
Image
from
pyvirtualdisplay
import
Display
with
NamedTemporaryFile
()
as
f
,
Display
(
visible
=
False
,
size
=
(
3200
,
1800
)):
binary
=
None
if
hasattr
(
env
,
"FIREFOX_BINARY_PATH"
):
binary
=
FirefoxBinary
(
env
.
FIREFOX_BINARY_PATH
)
profile
=
None
if
hasattr
(
env
,
"FIREFOX_PROFILE_PATH"
):
profile
=
webdriver
.
FirefoxProfile
(
env
.
FIREFOX_PROFILE_PATH
)
driver
=
webdriver
.
Firefox
(
profile
,
firefox_binary
=
binary
)
driver
.
set_window_size
(
1200
,
1800
)
driver
.
get
(
self
.
url
)
driver
.
save_screenshot
(
f
.
name
)
screen
=
driver
.
get_screenshot_as_png
()
driver
.
quit
()
im
=
Image
.
open
(
BytesIO
(
screen
))
im
.
thumbnail
((
240
,
360
))
im_io
=
BytesIO
()
im
.
save
(
im_io
,
format
=
"PNG"
)
self
.
screenshot
.
save
(
"screenshot-%i"
%
self
.
id
,
ContentFile
(
im_io
.
getvalue
()),
save
=
True
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment