Completed
Push — main ( dc9c2e...80557c )
by Jochen
05:20
created

ItemVersionQuery.for_item()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 2
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
"""
2
byceps.services.news.models.item
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2020 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9 1
from datetime import datetime
10
11 1
from sqlalchemy.ext.associationproxy import association_proxy
12
13 1
from ....database import BaseQuery, db, generate_uuid
14 1
from ....typing import UserID
15 1
from ....util.instances import ReprBuilder
16
17 1
from ...user.models.user import User
18
19 1
from ..transfer.models import ChannelID, ItemID
20
21 1
from .channel import Channel
22
23
24 1
class ItemQuery(BaseQuery):
25
26 1
    def for_channel(self, channel_id: ChannelID) -> BaseQuery:
27 1
        return self.filter_by(channel_id=channel_id)
28
29 1
    def with_channel(self) -> BaseQuery:
30 1
        return self.options(
31
            db.joinedload('channel'),
32
        )
33
34 1
    def with_images(self) -> BaseQuery:
35 1
        return self.options(
36
            db.joinedload('images'),
37
        )
38
39 1
    def published(self) -> BaseQuery:
40
        """Return items that have been published."""
41 1
        return self.filter(Item.published_at <= datetime.utcnow())
42
43 1
    def with_current_version(self) -> BaseQuery:
44 1
        return self.options(
45
            db.joinedload('current_version_association').joinedload('version'),
46
        )
47
48
49 1
class Item(db.Model):
50
    """A news item.
51
52
    Each one is expected to have at least one version (the initial one).
53
    """
54
55 1
    __tablename__ = 'news_items'
56 1
    __table_args__ = (
57
        db.UniqueConstraint('channel_id', 'slug'),
58
    )
59 1
    query_class = ItemQuery
60
61 1
    id = db.Column(db.Uuid, default=generate_uuid, primary_key=True)
62 1
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
63 1
    channel_id = db.Column(db.UnicodeText, db.ForeignKey('news_channels.id'), index=True, nullable=False)
64 1
    channel = db.relationship(Channel)
65 1
    slug = db.Column(db.UnicodeText, index=True, nullable=False)
66 1
    published_at = db.Column(db.DateTime, nullable=True)
67 1
    current_version = association_proxy('current_version_association', 'version')
68
69 1
    def __init__(self, channel_id: ChannelID, slug: str) -> None:
70 1
        self.channel_id = channel_id
71 1
        self.slug = slug
72
73 1
    @property
74 1
    def title(self) -> str:
75
        return self.current_version.title
76
77 1
    @property
78 1
    def published(self) -> bool:
79 1
        return self.published_at is not None
80
81 1
    def __repr__(self) -> str:
82
        return ReprBuilder(self) \
83
            .add_with_lookup('id') \
84
            .add('channel', self.channel_id) \
85
            .add_with_lookup('slug') \
86
            .add_with_lookup('published_at') \
87
            .build()
88
89
90 1
class ItemVersionQuery(BaseQuery):
91
92 1
    def for_item(self, item_id: ItemID) -> BaseQuery:
93 1
        return self.filter_by(item_id=item_id)
94
95
96 1
class ItemVersion(db.Model):
97
    """A snapshot of a news item at a certain time."""
98
99 1
    __tablename__ = 'news_item_versions'
100 1
    query_class = ItemVersionQuery
101
102 1
    id = db.Column(db.Uuid, default=generate_uuid, primary_key=True)
103 1
    item_id = db.Column(db.Uuid, db.ForeignKey('news_items.id'), index=True, nullable=False)
104 1
    item = db.relationship(Item)
105 1
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
106 1
    creator_id = db.Column(db.Uuid, db.ForeignKey('users.id'), nullable=False)
107 1
    creator = db.relationship(User)
108 1
    title = db.Column(db.UnicodeText, nullable=False)
109 1
    body = db.Column(db.UnicodeText, nullable=False)
110 1
    image_url_path = db.Column(db.UnicodeText, nullable=True)
111
112 1
    def __init__(
113
        self, item: Item, creator_id: UserID, title: str, body: str
114
    ) -> None:
115 1
        self.item = item
116 1
        self.creator_id = creator_id
117 1
        self.title = title
118 1
        self.body = body
119
120 1
    @property
121 1
    def is_current(self) -> bool:
122
        """Return `True` if this version is the current version of the
123
        item it belongs to.
124
        """
125 1
        return self.id == self.item.current_version.id
126
127 1
    def __repr__(self) -> str:
128
        return ReprBuilder(self) \
129
            .add_with_lookup('id') \
130
            .add_with_lookup('item') \
131
            .add_with_lookup('created_at') \
132
            .build()
133
134
135 1
class CurrentVersionAssociation(db.Model):
136 1
    __tablename__ = 'news_item_current_versions'
137
138 1
    item_id = db.Column(db.Uuid, db.ForeignKey('news_items.id'), primary_key=True)
139 1
    item = db.relationship(Item, backref=db.backref('current_version_association', uselist=False))
140 1
    version_id = db.Column(db.Uuid, db.ForeignKey('news_item_versions.id'), unique=True, nullable=False)
141 1
    version = db.relationship(ItemVersion)
142
143 1
    def __init__(self, item: Item, version: ItemVersion) -> None:
144 1
        self.item = item
145
        self.version = version
146