-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathcms_menus.py
191 lines (154 loc) · 6.81 KB
/
cms_menus.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
from cms import constants as cms_constants
from cms.apphook_pool import apphook_pool
from cms.cms_menus import CMSMenu as OriginalCMSMenu, get_visible_nodes
from cms.models import Page
try:
from cms.models import TreeNode
except ImportError:
TreeNode = None
from cms.toolbar.utils import get_object_preview_url, get_toolbar_from_request
from cms.utils.page import get_page_queryset
from django.apps import apps
from menus.base import Menu, NavigationNode
from menus.menu_pool import menu_pool
from . import conf, constants
class CMSVersionedNavigationNode(NavigationNode):
def is_selected(self, request):
try:
page_id = request.current_page.pk
except AttributeError:
return False
return page_id == self.id
def _get_attrs_for_node(renderer, page_content):
page = page_content.page
language = renderer.request_language
attr = {
"is_page": True,
"soft_root": page_content.soft_root,
"auth_required": page.login_required,
"reverse_id": page.reverse_id,
}
limit_visibility_in_menu = page_content.limit_visibility_in_menu
if limit_visibility_in_menu is cms_constants.VISIBILITY_ALL:
attr["visible_for_authenticated"] = True
attr["visible_for_anonymous"] = True
else:
attr["visible_for_authenticated"] = (
limit_visibility_in_menu == cms_constants.VISIBILITY_USERS
)
attr["visible_for_anonymous"] = (
limit_visibility_in_menu == cms_constants.VISIBILITY_ANONYMOUS
)
attr["is_home"] = page.is_home
extenders = []
if page.navigation_extenders:
if page.navigation_extenders in renderer.menus:
extenders.append(page.navigation_extenders)
elif f"{page.navigation_extenders}:{page.pk}" in renderer.menus:
extenders.append(f"{page.navigation_extenders}:{page.pk}")
if page.application_urls:
app = apphook_pool.get_apphook(page.application_urls)
if app:
extenders += app.get_menus(page, language)
exts = []
for ext in extenders:
if hasattr(ext, "get_instances"):
exts.append(f"{ext.__name__}:{page.pk}")
elif hasattr(ext, "__name__"):
exts.append(ext.__name__)
else:
exts.append(ext)
if exts:
attr["navigation_extenders"] = exts
attr["redirect_url"] = page_content.redirect
return attr
class CMSMenu(Menu):
"""This is a legacy class used by django CMS 4.0 and django CMS 4.1.0 only. Its language
fallback mechanism does not comply with django CMS' core's. Also, it is by far slower
than django CMS core's. As of django CMS 4.1.1, this class is by default deactivated.
See https://discord.com/channels/800813886689247262/1204047551570120755 for more information."""
def get_nodes(self, request):
site = self.renderer.site
language = self.renderer.request_language
pages_qs = get_page_queryset(site).select_related("node")
visible_pages_for_user = get_visible_nodes(request, pages_qs, site)
if not visible_pages_for_user:
return []
cms_extension = apps.get_app_config("djangocms_versioning").cms_extension
toolbar = get_toolbar_from_request(request)
edit_or_preview = toolbar.edit_mode_active or toolbar.preview_mode_active
menu_nodes = []
node_id_to_page = {}
homepage_content = None
# Depending on the toolbar mode, we need to get the correct version.
# On edit or preview mode: return DRAFT,
# if DRAFT does not exist then return PUBLISHED.
# On public mode: return PUBLISHED.
if edit_or_preview:
states = [constants.DRAFT, constants.PUBLISHED]
else:
states = [constants.PUBLISHED]
versionable_item = cms_extension.versionables_by_grouper[Page]
versioned_page_contents = (
versionable_item.content_model._base_manager.filter(
language=language, page__in=pages_qs, versions__state__in=states
)
.order_by("page__node__path" if TreeNode else "page__path", "versions__state")
.select_related("page", "page__node" if TreeNode else "page")
.prefetch_related("versions")
)
added_pages = []
for page_content in versioned_page_contents:
page = page_content.page
if page not in visible_pages_for_user:
# The page is restricted for the user.
# Therefore, we avoid adding it to the menu.
continue
version = page_content.versions.all()[0]
if (
page.pk in added_pages
and edit_or_preview
and version.state == constants.PUBLISHED
):
# Page content is already added. This is the case where you
# have both draft and published and in edit/preview mode.
# We give priority to draft which is already sorted by the query.
# Therefore we ignore the published version.
continue
page_tree_node = page.node
parent_id = node_id_to_page.get(page_tree_node.parent_id)
if page_tree_node.parent_id and not parent_id:
# If the parent page is not available,
# we skip adding the menu node.
continue
# Construct the url based on the toolbar mode.
if edit_or_preview:
url = get_object_preview_url(page_content)
else:
url = page_content.get_absolute_url()
# Create the new navigation node.
new_node = CMSVersionedNavigationNode(
id=page.pk,
attr=_get_attrs_for_node(self.renderer, page_content),
title=page_content.menu_title or page_content.title,
url=url,
visible=page_content.in_navigation,
)
if not homepage_content:
# Set the home page content.
homepage_content = page_content if page.is_home else None
cut_homepage = homepage_content and not homepage_content.in_navigation
if cut_homepage and parent_id == homepage_content.page.pk:
# When the homepage is hidden from navigation,
# we need to cut all its direct children from it.
new_node.parent_id = None
else:
new_node.parent_id = parent_id
node_id_to_page[page_tree_node.pk] = page.pk
menu_nodes.append(new_node)
added_pages.append(page.pk)
return menu_nodes
if conf.ENABLE_MENU_REGISTRATION:
# Remove the core djangoCMS CMSMenu and register the new CMSVersionedMenu.
menu_pool.menus.pop(OriginalCMSMenu.__name__)
menu_pool.register_menu(CMSMenu)