Passed
Branch main (854eb5)
by Jochen
04:24
created

byceps.services.board.last_view_service   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Test Coverage

Coverage 82%

Importance

Changes 0
Metric Value
eloc 73
dl 0
loc 153
ccs 41
cts 50
cp 0.82
rs 10
c 0
b 0
f 0
wmc 14

10 Functions

Rating   Name   Duplication   Size   Complexity  
A delete_last_topic_views() 0 6 1
A find_last_category_view() 0 7 1
A contains_topic_unseen_postings() 0 7 1
A contains_category_unseen_postings() 0 15 3
A mark_topic_as_just_viewed() 0 14 1
A mark_category_as_just_viewed() 0 16 1
A find_last_topic_view() 0 7 1
A find_topic_last_viewed_at() 0 8 2
A delete_last_category_views() 0 6 1
A mark_all_topics_in_category_as_viewed() 0 19 2
1
"""
2
byceps.services.board.last_view_service
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2021 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from datetime import datetime
10 1
from typing import Optional
11
12 1
from ...database import db, upsert, upsert_many
13 1
from ...typing import UserID
14
15 1
from .dbmodels.last_category_view import LastCategoryView
16 1
from .dbmodels.last_topic_view import LastTopicView
17 1
from .dbmodels.topic import Topic as DbTopic
18 1
from . import topic_query_service
19 1
from .transfer.models import CategoryID, CategoryWithLastUpdate, TopicID
20
21
22
# -------------------------------------------------------------------- #
23
# categories
24
25
26 1
def contains_category_unseen_postings(
27
    category: CategoryWithLastUpdate, user_id: UserID
28
) -> bool:
29
    """Return `True` if the category contains postings created after the
30
    last time the user viewed it.
31
    """
32 1
    if category.last_posting_updated_at is None:
33
        return False
34
35 1
    last_view = find_last_category_view(user_id, category.id)
36
37 1
    if last_view is None:
38 1
        return True
39
40
    return category.last_posting_updated_at > last_view.occurred_at
41
42
43 1
def find_last_category_view(
44
    user_id: UserID, category_id: CategoryID
45
) -> Optional[LastCategoryView]:
46
    """Return the user's last view of the category, or `None` if not found."""
47 1
    return LastCategoryView.query \
48
        .filter_by(user_id=user_id, category_id=category_id) \
49
        .first()
50
51
52 1
def mark_category_as_just_viewed(
53
    category_id: CategoryID, user_id: UserID
54
) -> None:
55
    """Mark the category as last viewed by the user (if logged in) at
56
    the current time.
57
    """
58 1
    table = LastCategoryView.__table__
59 1
    identifier = {
60
        'user_id': user_id,
61
        'category_id': category_id,
62
    }
63 1
    replacement = {
64
        'occurred_at': datetime.utcnow(),
65
    }
66
67 1
    upsert(table, identifier, replacement)
68
69
70 1
def delete_last_category_views(category_id: CategoryID) -> None:
71
    """Delete the category's last views."""
72 1
    db.session.query(LastCategoryView) \
73
        .filter_by(category_id=category_id) \
74
        .delete()
75 1
    db.session.commit()
76
77
78
# -------------------------------------------------------------------- #
79
# topics
80
81
82 1
def contains_topic_unseen_postings(topic: DbTopic, user_id: UserID) -> bool:
83
    """Return `True` if the topic contains postings created after the
84
    last time the user viewed it.
85
    """
86 1
    last_viewed_at = find_topic_last_viewed_at(topic.id, user_id)
87
88 1
    return last_viewed_at is None or topic.last_updated_at > last_viewed_at
89
90
91 1
def find_last_topic_view(
92
    user_id: UserID, topic_id: TopicID
93
) -> Optional[LastTopicView]:
94
    """Return the user's last view of the topic, or `None` if not found."""
95 1
    return LastTopicView.query \
96
        .filter_by(user_id=user_id, topic_id=topic_id) \
97
        .first()
98
99
100 1
def find_topic_last_viewed_at(
101
    topic_id: TopicID, user_id: UserID
102
) -> Optional[datetime]:
103
    """Return the time the topic was last viewed by the user (or
104
    nothing, if it hasn't been viewed by the user yet).
105
    """
106 1
    last_view = find_last_topic_view(user_id, topic_id)
107 1
    return last_view.occurred_at if (last_view is not None) else None
108
109
110 1
def mark_topic_as_just_viewed(topic_id: TopicID, user_id: UserID) -> None:
111
    """Mark the topic as last viewed by the user (if logged in) at the
112
    current time.
113
    """
114 1
    table = LastTopicView.__table__
115 1
    identifier = {
116
        'user_id': user_id,
117
        'topic_id': topic_id,
118
    }
119 1
    replacement = {
120
        'occurred_at': datetime.utcnow(),
121
    }
122
123 1
    upsert(table, identifier, replacement)
124
125
126 1
def mark_all_topics_in_category_as_viewed(
127
    category_id: CategoryID, user_id: UserID
128
) -> None:
129
    """Mark all topics in the category as viewed."""
130
    topic_ids = topic_query_service.get_all_topic_ids_in_category(category_id)
131
132
    if not topic_ids:
133
        return
134
135
    table = LastTopicView.__table__
136
    replacement = {
137
        'occurred_at': datetime.utcnow(),
138
    }
139
140
    identifiers = [
141
        {'user_id': user_id, 'topic_id': topic_id} for topic_id in topic_ids
142
    ]
143
144
    upsert_many(table, identifiers, replacement)
145
146
147 1
def delete_last_topic_views(topic_id: TopicID) -> None:
148
    """Delete the topic's last views."""
149 1
    db.session.query(LastTopicView) \
150
        .filter_by(topic_id=topic_id) \
151
        .delete()
152
    db.session.commit()
153