Passed
Push — main ( cf69f4...26e6c3 )
by Jochen
06:03
created

get_items_for_menu_id()   A

Complexity

Conditions 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.2963

Importance

Changes 0
Metric Value
cc 1
eloc 7
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0
ccs 1
cts 3
cp 0.3333
crap 1.2963
1
"""
2
byceps.services.site_navigation.site_navigation_service
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2014-2023 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from typing import Iterable, Optional
10
11 1
from sqlalchemy import select
12
13 1
from ...database import db
14 1
from ...services.site.transfer.models import SiteID
15
16 1
from .dbmodels import DbNavItem, DbNavMenu
17 1
from .transfer.models import (
18
    NavItem,
19
    NavItemID,
20
    NavItemTargetType,
21
    NavMenu,
22
    NavMenuAggregate,
23
    NavMenuID,
24
)
25
26
27 1
def create_menu(
28
    site_id: SiteID,
29
    name: str,
30
    language_code: str,
31
    *,
32
    hidden: bool = False,
33
) -> NavMenu:
34
    """Create a menu."""
35
    db_menu = DbNavMenu(site_id, name, language_code, hidden)
36
    db.session.add(db_menu)
37
    db.session.commit()
38
39
    return _db_entity_to_menu(db_menu)
40
41
42 1
def update_menu(
43
    menu_id: NavMenuID,
44
    name: str,
45
    language_code: str,
46
    hidden: bool,
47
) -> NavMenu:
48
    """Update a menu."""
49
    db_menu = _get_db_menu(menu_id)
50
51
    db_menu.name = name
52
    db_menu.language_code = language_code
53
    db_menu.hidden = hidden
54
55
    db.session.commit()
56
57
    return _db_entity_to_menu(db_menu)
58
59
60 1
def create_item(
61
    menu_id: NavMenuID,
62
    target_type: NavItemTargetType,
63
    target: str,
64
    label: str,
65
    current_page_id: str,
66
    *,
67
    parent_item_id: Optional[NavItemID] = None,
68
    hidden: bool = False,
69
) -> NavItem:
70
    """Create a menu item."""
71
    db_menu = _get_db_menu(menu_id)
72
73
    db_item = DbNavItem(
74
        db_menu.id,
75
        parent_item_id,
76
        target_type,
77
        target,
78
        label,
79
        current_page_id,
80
        hidden,
81
    )
82
    db_menu.items.append(db_item)
83
    db.session.commit()
84
85
    return _db_entity_to_item(db_item)
86
87
88 1
def find_menu(menu_id: NavMenuID) -> Optional[NavMenu]:
89
    """Return the menu, or `None` if not found."""
90
    db_menu = _find_db_menu(menu_id)
91
92
    if db_menu is None:
93
        return None
94
95
    return _db_entity_to_menu(db_menu)
96
97
98 1
def get_menu(menu_id: NavMenuID) -> NavMenu:
99
    """Return the menu.
100
101
    Raise error if not found.
102
    """
103
    db_menu = _get_db_menu(menu_id)
104
105
    return _db_entity_to_menu(db_menu)
106
107
108 1
def _find_db_menu(menu_id: NavMenuID) -> Optional[DbNavMenu]:
109
    """Return the menu, or `None` if not found."""
110
    return db.session.get(DbNavMenu, menu_id)
111
112
113 1
def _get_db_menu(menu_id: NavMenuID) -> DbNavMenu:
114
    """Return the menu.
115
116
    Raise error if not found.
117
    """
118
    db_menu = _find_db_menu(menu_id)
119
120
    if db_menu is None:
121
        raise ValueError('Unknown menu ID')
122
123
    return db_menu
124
125
126 1
def find_menu_aggregate(menu_id: NavMenuID) -> Optional[NavMenuAggregate]:
127
    """Return the menu aggregate, or `None` if not found."""
128
    db_menu = _find_db_menu(menu_id)
129
    if db_menu is None:
130
        return None
131
132
    db_items = db.session.scalars(
133
        select(DbNavItem).filter(DbNavItem.menu_id == db_menu.id)
134
    )
135
136
    return _db_entity_to_menu_aggregate(db_menu, db_items)
137
138
139 1
def get_menus(site_id: SiteID) -> list[NavMenu]:
140
    """Return the menus for this site."""
141
    db_menus = db.session.scalars(
142
        select(DbNavMenu).filter(DbNavMenu.site_id == site_id)
143
    )
144
145
    return [_db_entity_to_menu(db_menu) for db_menu in db_menus]
146
147
148 1
def find_item(item_id: NavItemID) -> Optional[NavItem]:
149
    """Return the menu item, or `None` if not found."""
150
    db_item = _find_db_item(item_id)
151
152
    if db_item is None:
153
        return None
154
155
    return _db_entity_to_item(db_item)
156
157
158 1
def _find_db_item(item_id: NavItemID) -> Optional[DbNavItem]:
159
    """Return the menu item, or `None` if not found."""
160
    return db.session.get(DbNavItem, item_id)
161
162
163 1
def _get_db_item(item_id: NavItemID) -> DbNavItem:
164
    """Return the menu item.
165
166
    Raise error if not found.
167
    """
168
    db_item = _find_db_item(item_id)
169
170
    if db_item is None:
171
        raise ValueError('Unknown item ID')
172
173
    return db_item
174
175
176 1
def get_items_for_menu_id(menu_id: NavMenuID) -> list[NavItem]:
177
    """Return the items of a menu.
178
179
    An empty list is returned if the menu does not exist, is hidden, or
180
    contains no visible items.
181
    """
182
    db_items = db.session.scalars(
183
        select(DbNavItem)
184
        .join(DbNavMenu)
185
        .filter(DbNavMenu.id == menu_id)
186
        .filter(DbNavMenu.hidden == False)  # noqa: E712
187
    )
188
189
    return [_db_entity_to_item(db_item) for db_item in db_items]
190
191
192 1
def get_items_for_menu(
193
    site_id: SiteID, name: str, language_code: str
194
) -> list[NavItem]:
195
    """Return the items of a menu.
196
197
    An empty list is returned if the menu does not exist, is hidden, or
198
    contains no visible items.
199
    """
200
    db_items = db.session.scalars(
201
        select(DbNavItem)
202
        .join(DbNavMenu)
203
        .filter(DbNavMenu.site_id == site_id)
204
        .filter(DbNavMenu.name == name)
205
        .filter(DbNavMenu.language_code == language_code)
206
        .filter(DbNavMenu.hidden == False)  # noqa: E712
207
    )
208
209
    return [_db_entity_to_item(db_item) for db_item in db_items]
210
211
212 1
def move_item_up(item_id: NavItemID) -> NavItem:
213
    """Move a menu item upwards by one position."""
214
    item = _get_db_item(item_id)
215
216
    item_list = item.menu.items
217
218
    if item.position == 1:
219
        raise ValueError('Item is already at the top.')
220
221
    popped_item = item_list.pop(item.position - 1)
222
    item_list.insert(popped_item.position - 2, popped_item)
223
224
    db.session.commit()
225
226
    return _db_entity_to_item(item)
227
228
229 1
def move_item_down(item_id: NavItemID) -> NavItem:
230
    """Move a menu item downwards by one position."""
231
    item = _get_db_item(item_id)
232
233
    item_list = item.menu.items
234
235
    if item.position == len(item_list):
236
        raise ValueError('Item is already at the bottom.')
237
238
    popped_item = item_list.pop(item.position - 1)
239
    item_list.insert(popped_item.position, popped_item)
240
241
    db.session.commit()
242
243
    return _db_entity_to_item(item)
244
245
246 1
def _db_entity_to_menu(db_menu: DbNavMenu) -> NavMenu:
247
    return NavMenu(
248
        id=db_menu.id,
249
        site_id=db_menu.site_id,
250
        name=db_menu.name,
251
        language_code=db_menu.language_code,
252
        hidden=db_menu.hidden,
253
    )
254
255
256 1
def _db_entity_to_item(db_item: DbNavItem) -> NavItem:
257
    return NavItem(
258
        id=db_item.id,
259
        menu_id=db_item.menu_id,
260
        position=db_item.position,
261
        target_type=db_item.target_type,
262
        target=db_item.target,
263
        label=db_item.label,
264
        current_page_id=db_item.current_page_id,
265
        hidden=db_item.hidden,
266
    )
267
268
269 1
def _db_entity_to_menu_aggregate(
270
    db_menu: DbNavMenu, db_items: Iterable[DbNavItem]
271
) -> NavMenuAggregate:
272
    menu = _db_entity_to_menu(db_menu)
273
    items = [_db_entity_to_item(db_item) for db_item in db_items]
274
275
    return NavMenuAggregate(
276
        id=menu.id,
277
        site_id=menu.site_id,
278
        name=menu.name,
279
        language_code=menu.language_code,
280
        hidden=menu.hidden,
281
        items=items,
282
    )
283