Passed
Push — main ( 2c88b8...eed5d0 )
by Jochen
04:23
created

DbNewsItemVersion.__init__()   A

Complexity

Conditions 1

Size

Total Lines 13
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 12
nop 6
dl 0
loc 13
ccs 6
cts 6
cp 1
crap 1
rs 9.8
c 0
b 0
f 0
1
"""
2
byceps.services.news.dbmodels.item
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2014-2023 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from datetime import datetime
10 1
from typing import TYPE_CHECKING
11
12 1
if TYPE_CHECKING:
13
    hybrid_property = property
14
else:
15 1
    from sqlalchemy.ext.hybrid import hybrid_property
16
17 1
from sqlalchemy.ext.associationproxy import association_proxy
18
19 1
from ....database import db, generate_uuid
20 1
from ....typing import UserID
21 1
from ....util.instances import ReprBuilder
22
23 1
from ...user.dbmodels.user import DbUser
24
25 1
from ..transfer.models import BodyFormat, NewsChannelID
26
27 1
from .channel import DbNewsChannel
28
29
30 1
class DbNewsItem(db.Model):
31
    """A news item.
32
33
    Each one is expected to have at least one version (the initial one).
34
35
    News items with a publication date set are considered public unless
36
    that date is in the future (i.e. those items have been pre-published
37
    and are awaiting publication).
38
    """
39
40 1
    __tablename__ = 'news_items'
41
42 1
    id = db.Column(db.Uuid, default=generate_uuid, primary_key=True)
43 1
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
44 1
    channel_id = db.Column(
45
        db.UnicodeText,
46
        db.ForeignKey('news_channels.id'),
47
        index=True,
48
        nullable=False,
49
    )
50 1
    channel = db.relationship(DbNewsChannel)
51 1
    slug = db.Column(db.UnicodeText, unique=True, index=True, nullable=False)
52 1
    published_at = db.Column(db.DateTime, nullable=True)
53 1
    current_version = association_proxy(
54
        'current_version_association', 'version'
55
    )
56 1
    featured_image_id = db.Column(db.Uuid, nullable=True)
57
58 1
    def __init__(self, channel_id: NewsChannelID, slug: str) -> None:
59 1
        self.channel_id = channel_id
60 1
        self.slug = slug
61
62 1
    @property
63 1
    def title(self) -> str:
64
        return self.current_version.title
65
66 1
    @property
67 1
    def published(self) -> bool:
68 1
        return self.published_at is not None
69
70 1
    def __repr__(self) -> str:
71
        return (
72
            ReprBuilder(self)
73
            .add_with_lookup('id')
74
            .add('channel', self.channel_id)
75
            .add_with_lookup('slug')
76
            .add_with_lookup('published_at')
77
            .build()
78
        )
79
80
81 1
class DbNewsItemVersion(db.Model):
82
    """A snapshot of a news item at a certain time."""
83
84 1
    __tablename__ = 'news_item_versions'
85
86 1
    id = db.Column(db.Uuid, default=generate_uuid, primary_key=True)
87 1
    item_id = db.Column(
88
        db.Uuid, db.ForeignKey('news_items.id'), index=True, nullable=False
89
    )
90 1
    item = db.relationship(DbNewsItem)
91 1
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
92 1
    creator_id = db.Column(db.Uuid, db.ForeignKey('users.id'), nullable=False)
93 1
    creator = db.relationship(DbUser)
94 1
    title = db.Column(db.UnicodeText, nullable=False)
95 1
    body = db.Column(db.UnicodeText, nullable=False)
96 1
    _body_format = db.Column('body_format', db.UnicodeText, nullable=False)
97 1
    image_url_path = db.Column(db.UnicodeText, nullable=True)
98
99 1
    def __init__(
100
        self,
101
        item: DbNewsItem,
102
        creator_id: UserID,
103
        title: str,
104
        body: str,
105
        body_format: BodyFormat,
106
    ) -> None:
107 1
        self.item = item
108 1
        self.creator_id = creator_id
109 1
        self.title = title
110 1
        self.body = body
111 1
        self.body_format = body_format
112
113 1
    @hybrid_property
114 1
    def body_format(self) -> BodyFormat:
115 1
        return BodyFormat[self._body_format]
116
117 1
    @body_format.setter
118 1
    def body_format(self, body_format: BodyFormat) -> None:
119 1
        assert body_format is not None
120 1
        self._body_format = body_format.name
121
122 1
    @property
123 1
    def is_current(self) -> bool:
124
        """Return `True` if this version is the current version of the
125
        item it belongs to.
126
        """
127 1
        return self.id == self.item.current_version.id
128
129 1
    def __repr__(self) -> str:
130
        return (
131
            ReprBuilder(self)
132
            .add_with_lookup('id')
133
            .add_with_lookup('item')
134
            .add_with_lookup('created_at')
135
            .build()
136
        )
137
138
139 1
class DbCurrentNewsItemVersionAssociation(db.Model):
140 1
    __tablename__ = 'news_item_current_versions'
141
142 1
    item_id = db.Column(
143
        db.Uuid, db.ForeignKey('news_items.id'), primary_key=True
144
    )
145 1
    item = db.relationship(
146
        DbNewsItem,
147
        backref=db.backref('current_version_association', uselist=False),
148
    )
149 1
    version_id = db.Column(
150
        db.Uuid,
151
        db.ForeignKey('news_item_versions.id'),
152
        unique=True,
153
        nullable=False,
154
    )
155 1
    version = db.relationship(DbNewsItemVersion)
156
157 1
    def __init__(self, item: DbNewsItem, version: DbNewsItemVersion) -> None:
158 1
        self.item = item
159
        self.version = version
160