class LocationAdmin(ContentEditor): search_fields = [ 'name', 'street', 'city', ] list_display = [ 'name', 'slug', 'street', 'city', 'lng', 'lat', ] list_filter = ['city'] prepopulated_fields = {'slug': ('name', )} fieldsets = ( (None, { 'fields': ( 'name', 'street', ( 'city', 'zip_code', ), 'country', ) }), (_('advanced'), { 'classes': ('tabbed', ), 'fields': ('slug', 'lat', 'lng', 'header_image', 'header_image_ppoi') }), MetaMixin.admin_fieldset(), ) inlines = [ plugins.image.ImageInline.create(models.LocationImage), ] def save_model(self, request, obj, form, change): if (not change): locator = Nominatim(user_agent=settings.NOMINATIM_USER_AGENT) location = locator.geocode( f"{obj.street}, {obj.zip_code} {obj.city}, {obj.country}") obj.lat = location.latitude obj.lng = location.longitude super().save_model(request, obj, form, change)
class CategoryAdmin(VersionAdmin, TreeAdmin): list_display = [ "indented_title", "move_column", "name", "slug", "parent", "language_code", ] list_filter = ["language_code"] search_fields = ["name", "slug"] prepopulated_fields = {"slug": ("name", )} autocomplete_fields = ["parent", "translations"] fieldsets = ( ( None, { "fields": ( "name", "slug", "language_code", "parent", "header_image", "header_image_ppoi", "color", ) }, ), MetaMixin.admin_fieldset(), (_("translations"), { "classes": ("collapse", ), "fields": ("translations", ), }), )
class PageAdmin(ContentEditor, TreeAdmin): list_display = [ "indented_title", "move_column", 'slug', 'static_path', 'path', "is_active", 'language_code', "template_key", 'application', "position", ] actions = ['copy_selected'] prepopulated_fields = {'slug': ('title', )} autocomplete_fields = [ 'parent', 'namespace', 'redirect_to_page', 'collection', ] search_fields = ['title'] list_editable = [ 'is_active', 'slug', 'static_path', 'path', 'language_code', ] list_filter = ['is_active', 'menu', 'language_code', 'site'] inlines = [ plugins.richtext.RichTextInline.create(models.RichText), plugins.image.ImageInline.create(models.Image), plugins.html.HTMLInline.create(models.HTML), plugins.external.ExternalInline.create(models.External), ButtonInline.create(models.Button), events_plugins.EventPluginInline.create(models.EventPlugin), blog_plugins.ArticlePluginInline.create(models.ArticlePlugin), ] fieldsets = ( (None, { 'fields': ( 'title', 'parent', ) }), (_('settings'), { 'classes': ('tabbed', ), 'fields': ('is_active', 'menu', 'language_code', 'template_key', 'image', 'image_ppoi'), }), (_('path'), { 'classes': ('tabbed', ), 'fields': ( 'slug', 'static_path', 'path', 'site', ) }), (_('application'), { 'classes': ('tabbed', ), 'fields': ( 'application', 'namespace', 'collection', ) }), MetaMixin.admin_fieldset(), (_('redirect'), { 'classes': ('tabbed', ), 'fields': ( 'redirect_to_page', 'redirect_to_url', ) }), ) mptt_level_indent = 30 class Media: js = ( 'admin/js/jquery.init.js', JS('https://use.fontawesome.com/0fc4ca6dfe.js', { 'async': 'async', 'crossorigin': 'anonymous', }, static=False), 'admin/plugin_buttons.js', )
class ArticleAdmin(VersionAdmin, ContentEditor, CopyContentMixin): list_display = ( "title", "slug", "publication_date", "category", "section", "language_code", "namespace", ) list_filter = ( "namespace", "section", "language_code", "category", ) list_editable = ( "language_code", "slug", ) date_hierarchy = "publication_date" autocomplete_fields = ( "category", "namespace", "author", "section", "translations", ) search_fields = ( "title", "blog_richtext_set__text", ) prepopulated_fields = { "slug": ("title", ), } readonly_fields = ( "created_date", "edited_date", ) fieldsets = ( ( None, { "fields": ( "title", "author", "category", "tags", "header_image", "header_image_ppoi", ) }, ), ( _("settings"), { "classes": ("tabbed", ), "fields": ( "language_code", "slug", ("publication_date", "created_date", "edited_date"), "section", "namespace", "template_key", ), }, ), MetaMixin.admin_fieldset(), (_("translations"), { "classes": ("tabbed", ), "fields": ("translations", ) }), ) inlines = ( plugins.richtext.RichTextInline.create(models.RichText), plugins.image.ImageInline.create(models.Image), plugins.html.HTMLInline.create(models.HTML), plugins.external.ExternalInline.create(models.External), ButtonInline.create(models.Button), download.DownloadInline.create(models.Download), people_plugins.TeamPluginInline.create(models.Team), people_plugins.CandidateListPluginInline.create( models.CandidaturePlugin), GlossaryContentInline.create(models.GlossaryRichText), blog_plugins.ArticlePluginInline.create(models.ArticlePlugin), event_plugins.EventPluginInline.create(models.EventPlugin), form_plugins.FormPluginInline.create(models.FormPlugin), ) plugins = models.plugins actions = ("copy_selected", "send_webpush") class Media: js = ( "admin/js/jquery.init.js", JS( "https://kit.fontawesome.com/91a6274901.js", { "async": "async", "crossorigin": "anonymous", }, static=False, ), "admin/plugin_buttons.js", ) def send_webpush(self, request, queryset): for article in queryset: pages = Page.objects.filter( (Q(application="blog") & Q(language_code=article.language_code)) & (Q(category__isnull=True) | Q(category=article.category)) & (Q(blog_namespace__isnull=True) | Q(blog_namespace=article.namespace)) & (Q(site__section=article.section) | Q(sections=article.section))) for page in pages: subscriptions = webpush.Subscription.objects.filter(page=page) data = article.webpush_data(page) for subscription in subscriptions: tasks.send_data_to.delay(data, subscription.pk) def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) section_field = form.base_fields["section"] sections = request.user.section_set.all() section_field.initial = sections[0] return form def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser: return qs sections = request.user.section_set.all() return qs.filter(section__in=sections)
class LocationAdmin(VersionAdmin, ContentEditor): search_fields = [ "name", "street", "city", ] list_display = [ "name", "slug", "street", "city", "lng", "lat", ] list_filter = ["city"] prepopulated_fields = {"slug": ("name", )} autocomplete_fields = ["section", "translations"] fieldsets = ( (None, { "fields": ( "name", "street", ( "city", "zip_code", ), "country", ) }), ( _("advanced"), { "classes": ("tabbed", ), "fields": ( "section", "slug", "is_physical", "lat", "lng", "header_image", "header_image_ppoi", ), }, ), MetaMixin.admin_fieldset(), (_("translations"), { "classes": ("tabbed", ), "fields": ("translations", ) }), ) inlines = [ plugins.image.ImageInline.create(models.LocationImage), ] def has_change_permission(self, request, obj=None): if obj is None or obj.section is None: return super().has_change_permission(request, obj) sections = request.user.section_set.all() return obj.section in sections def save_model(self, request, obj, form, change): if not change and obj.is_physical: locator = Nominatim(user_agent=settings.NOMINATIM_USER_AGENT) location = locator.geocode( f"{obj.street}, {obj.zip_code} {obj.city}, {obj.country}") obj.lat = location.latitude obj.lng = location.longitude super().save_model(request, obj, form, change)
class EventAdmin(ContentEditor): list_display = [ 'title', 'slug', 'start_date', 'end_date', 'location', 'language_code', ] list_filter = [ 'language_code', ] search_fields = [ 'location', 'title', 'description', ] date_hierarchy = 'start_date' autocomplete_fields = [ 'location', ] search_fields = [ 'title', ] prepopulated_fields = { "slug": ("title", ), } fieldsets = ( (None, { 'fields': ( 'title', 'author', ( 'start_date', 'end_date', ), 'location', ) }), (_('settings'), { 'classes': ('tabbed', ), 'fields': ('language_code', 'slug', 'template_key', 'header_image', 'header_image_ppoi') }), MetaMixin.admin_fieldset(), ) inlines = [ plugins.richtext.RichTextInline.create(models.RichText), plugins.image.ImageInline.create(models.Image), plugins.html.HTMLInline.create(models.HTML), plugins.external.ExternalInline.create(models.External), blog_plugins.ArticlePluginInline.create(models.ArticlePlugin), event_plugins.EventPluginInline.create(models.EventPlugin), ButtonInline.create(models.Button), ] class Media: js = ( 'admin/js/jquery.init.js', JS('https://use.fontawesome.com/0fc4ca6dfe.js', { 'async': 'async', 'crossorigin': 'anonymous', }, static=False), 'admin/plugin_buttons.js', )
class PageAdmin(VersionAdmin, CopyContentMixin, ContentEditor, TreeAdmin): list_display = [ "indented_title", "move_column", "slug", "static_path", "path", "is_active", "language_code", "template_key", "application", "position", ] actions = ["open_duplicate_form"] list_per_page = 50 prepopulated_fields = {"slug": ("title", )} autocomplete_fields = [ "site", "parent", "blog_namespace", "category", "redirect_to_page", "translations", "featured_categories", "sections", "collection", ] search_fields = ["title"] list_editable = [] list_filter = ["is_active", "menu", "language_code", "site"] inlines = [ plugins.richtext.RichTextInline.create(models.RichText), plugins.image.ImageInline.create(models.Image), plugins.html.HTMLInline.create(models.HTML), plugins.external.ExternalInline.create(models.External), download.DownloadInline.create(models.Download), ButtonInline.create(models.Button), people_plugins.TeamPluginInline.create(models.Team), people_plugins.CandidateListPluginInline.create( models.CandidaturePlugin), event_plugins.EventPluginInline.create(models.EventPlugin), blog_plugins.ArticlePluginInline.create(models.ArticlePlugin), GlossaryContentInline.create(models.GlossaryRichText), form_plugins.FormPluginInline.create(models.FormPlugin), form_plugins.EntryCounterInline.create(models.FormEntryCounterPlugin), NavigationPluginInline.create(models.NavigationPlugin), CategoryLinkingInline, ] plugins = models.plugins readonly_fields = ["app_instance_namespace"] fieldsets = ( (None, { "fields": ( "title", "parent", ) }), ( _("settings"), { "classes": ("tabbed", ), "fields": ( "is_active", "menu", "language_code", "template_key", "is_landing_page", "header_image", "header_image_ppoi", ), }, ), ( _("path"), { "classes": ("tabbed", ), "fields": ( "slug", "static_path", "path", "site", ), }, ), ( _("application"), { "classes": ("tabbed", ), "fields": ( "application", "category", "blog_namespace", "featured_categories", "sections", "collection", "app_instance_namespace", ), }, ), MetaMixin.admin_fieldset(), ( _("redirect"), { "classes": ("tabbed", ), "fields": ( "redirect_to_page", "redirect_to_url", ), }, ), (_("translations"), { "classes": ("tabbed", ), "fields": ("translations", ) }), ( _("advanced"), { "classes": ("tabbed", ), "fields": ( "in_meta", "is_navigation", "position", "logo", "favicon", "primary_color", "css_vars", "fonts", "prefetches", "google_site_verification", ), }, ), ) mptt_level_indent = 30 def move_view(self, request, obj): return self.action_form_view(request, obj, form_class=ResctrictedMoveForm, title=_("Move %s") % obj) class Media: js = ( "admin/js/jquery.init.js", JS( "https://kit.fontawesome.com/91a6274901.js", { "async": "async", "crossorigin": "anonymous", }, static=False, ), "admin/plugin_buttons.js", ) def get_inline_instances(self, request, obj=None): inlines = super().get_inline_instances(request, obj) if (hasattr(obj, "pk") and models.Page.objects.get(pk=obj.pk).application == "categories"): return inlines return inlines[:-1] def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) site_field = form.base_fields["site"] site_field.required = True sections = request.user.section_set.all() site_field.initial = Site.objects.filter(section__in=sections)[0] return form def indented_title(self, instance): """ Use Unicode box-drawing characters to visualize the tree hierarchy. """ box_drawing = [] for i in range(instance.tree_depth - 1): box_drawing.append('<i class="l"></i>') if instance.tree_depth > 0: box_drawing.append('<i class="a"></i>') return format_html( '<div class="box">' '<div class="box-drawing">{}</div>' '<div class="box-text" style="text-indent:{}px">{}</div>' "</div>", mark_safe("".join(box_drawing)), instance.tree_depth * 30, instance.title, ) def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser: return qs sections = request.user.section_set.all() return qs.filter(site__section__in=sections) def open_duplicate_form(self, request, queryset): return redirect( reverse( "admin:pages_Page_duplicate_page_tree", kwargs={"pk": queryset[0].pk}, )) open_duplicate_form.short_description = _("Duplicate page-tree") def get_urls(self): urls = super().get_urls() return [ path( "<int:pk>/duplicate/", self.admin_site.admin_view(self.duplicate_page_tree), name="pages_Page_duplicate_page_tree", ) ] + urls def duplicate_page_tree(self, request, pk): page = models.Page.objects.get(pk=pk) form = DuplicateForm(page=page, request=request) if request.method == "POST": form = DuplicateForm(request.POST, page=page, request=request) if form.is_valid(): old_pk = page.pk new_root = page language_code = form.cleaned_data["language_code"] site = form.cleaned_data["site"] link_translations = form.cleaned_data["link_translations"] children = page.children.all() new_root.pk = None new_root.language_code = language_code new_root.site = site new_root.slug = form.cleaned_data["new_slug"] new_root.path = form.cleaned_data["new_path"] new_root.static_path = True new_root.title = form.cleaned_data["new_title"] new_root.save() if link_translations: new_root.translations.add(old_pk) new_root.save() def copy_children(page, children): for child in children: new_children = child.children.all() child.parent = page old_pk = child.pk child.pk = None child.language_code = language_code child.site = site child.save() if link_translations: child.translations.add(old_pk) child.save() copy_children(child, new_children) copy_children(new_root, children) return redirect("admin:pages_page_changelist") context = dict( self.admin_site.each_context(request), form=form, title=_("Duplicate Page-Tree"), app_label="pages", opts=models.Page._meta, model=models.Page, ) return render(request, "admin/duplicate_page_tree.html", context)