forked from rc/aircox
integrate tiptap text editor
This commit is contained in:
@ -2,6 +2,7 @@ import os
|
||||
|
||||
import inspect
|
||||
|
||||
from bleach import sanitizer
|
||||
from django.conf import settings as d_settings
|
||||
|
||||
|
||||
@ -179,5 +180,10 @@ class Settings(BaseSettings):
|
||||
ALLOW_COMMENTS = True
|
||||
"""Allow comments."""
|
||||
|
||||
# ---- bleach
|
||||
ALLOWED_TAGS = [*sanitizer.ALLOWED_TAGS, "br", "p", "h3", "h4", "h5"]
|
||||
ALLOWED_ATTRIBUTES = sanitizer.ALLOWED_ATTRIBUTES
|
||||
ALLOWED_PROTOCOLS = sanitizer.ALLOWED_PROTOCOLS
|
||||
|
||||
|
||||
settings = Settings("AIRCOX")
|
||||
|
@ -13,6 +13,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from filer.fields.image import FilerImageField
|
||||
from model_utils.managers import InheritanceQuerySet
|
||||
|
||||
from ..conf import settings
|
||||
from .station import Station
|
||||
|
||||
__all__ = (
|
||||
@ -120,6 +121,14 @@ class BasePage(Renderable, models.Model):
|
||||
return "{}".format(self.title or self.pk)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.content:
|
||||
self.content = bleach.clean(
|
||||
self.content,
|
||||
tags=settings.ALLOWED_TAGS,
|
||||
attributes=settings.ALLOWED_ATTRIBUTES,
|
||||
protocols=settings.ALLOWED_PROTOCOLS,
|
||||
)
|
||||
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.title)[:100]
|
||||
count = Page.objects.filter(slug__startswith=self.slug).count()
|
||||
@ -165,17 +174,6 @@ class BasePage(Renderable, models.Model):
|
||||
headline[-1] += suffix
|
||||
return mark_safe(" ".join(headline))
|
||||
|
||||
_url_re = re.compile(
|
||||
"((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:@\-_=#])*"
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def display_content(self):
|
||||
if "<p>" in self.content:
|
||||
return self.content
|
||||
content = self._url_re.sub(r'<a href="\1" target="new">\1</a>', self.content)
|
||||
return content.replace("\n\n", "\n").replace("\n", "<br>")
|
||||
|
||||
@classmethod
|
||||
def get_init_kwargs_from(cls, page, **kwargs):
|
||||
kwargs.setdefault("cover", page.cover)
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -136,9 +136,9 @@ Usefull context:
|
||||
|
||||
{% block content-container %}
|
||||
{% if page and page.content %}
|
||||
<section class="container content page-content">
|
||||
<section class="container no-reset content page-content">
|
||||
{% block content %}
|
||||
{{ page.display_content|safe }}
|
||||
{{ page.content|safe }}
|
||||
{% endblock %}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
@ -18,6 +18,12 @@ aircox.labels = {% inline_labels %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title-container %}
|
||||
{{ block.super }}
|
||||
{% block page-actions %}
|
||||
{% include "aircox/widgets/page_actions.html" %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content-container %}
|
||||
<a-select-file ref="cover-select"
|
||||
@ -102,8 +108,11 @@ aircox.labels = {% inline_labels %}
|
||||
<div>
|
||||
<div class="field {% if field.name != "content" %}is-horizontal{% endif %}">
|
||||
<label class="label">{{ field.label }}</label>
|
||||
<div class="control clear-unset">
|
||||
<div class="control clear-unset no-reset">
|
||||
<a-editor name="{{ field.name }}" initial="{{ field.value }}"/>
|
||||
{% comment %}
|
||||
<textarea name="{{ field.name }}" class="is-fullwidth height-25">{{ field.value|default:""|striptags|safe }}</textarea>
|
||||
{% endcomment %}
|
||||
</div>
|
||||
<p class="help">{{ field.help_text }}</p>
|
||||
</div>
|
||||
|
@ -2,24 +2,24 @@
|
||||
|
||||
{% block user-actions-container %}
|
||||
{% if user.is_authenticated %}
|
||||
{{ object.get_status_display }}
|
||||
{{ object.get_status_display|capfirst }}
|
||||
|
||||
{% if object.pub_date %}
|
||||
({{ object.pub_date|date:"d/m/Y H:i" }})
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if user.is_authenticated and can_edit %}
|
||||
{% if user.is_authenticated %}
|
||||
{% with request.resolver_match.view_name as view_name %}
|
||||
|
||||
{% if "-edit" in view_name %}
|
||||
{% if request.path != object.get_absolute_url %}
|
||||
<a href="{% url view_name|detail_view page.slug %}" target="_self" title="{% translate 'View' %} {{ page }}">
|
||||
<span class="icon">
|
||||
<i class="fa-regular fa-eye"></i>
|
||||
</span>
|
||||
<span>{% translate 'View' %} </span>
|
||||
</a>
|
||||
{% else %}
|
||||
{% elif can_edit %}
|
||||
<a href="{% url view_name|edit_view page.pk %}" target="_self" title="{% translate 'Edit' %} {{ page }}">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
|
@ -55,6 +55,9 @@ class EpisodeUpdateView(UserPassesTestMixin, VueFormDataMixin, PageUpdateView):
|
||||
form_class = forms.EpisodeForm
|
||||
template_name = "aircox/episode_form.html"
|
||||
|
||||
def can_edit(self, obj):
|
||||
return self.test_func()
|
||||
|
||||
def test_func(self):
|
||||
obj = self.get_object()
|
||||
return permissions.program.can(self.request.user, "update", obj)
|
||||
|
@ -33,6 +33,17 @@ def attach(cls):
|
||||
return cls
|
||||
|
||||
|
||||
class CanEditMixin:
|
||||
"""Add context 'can_edit' set to True when object is editable by user."""
|
||||
|
||||
def can_edit(self, object):
|
||||
"""Return True if user can edit current page."""
|
||||
return False
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(can_edit=self.can_edit(self.object), **kwargs)
|
||||
|
||||
|
||||
class BasePageMixin:
|
||||
category = None
|
||||
|
||||
@ -156,16 +167,12 @@ class PageListView(FiltersMixin, BasePageListView):
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class PageDetailView(BasePageDetailView):
|
||||
class PageDetailView(CanEditMixin, BasePageDetailView):
|
||||
"""Base view class for pages."""
|
||||
|
||||
template_name = None
|
||||
context_object_name = "page"
|
||||
|
||||
def can_edit(self, object):
|
||||
"""Return True if user can edit current page."""
|
||||
return False
|
||||
|
||||
def get_template_names(self):
|
||||
return super().get_template_names() + ["aircox/page_detail.html"]
|
||||
|
||||
@ -185,7 +192,6 @@ class PageDetailView(BasePageDetailView):
|
||||
if related:
|
||||
related = related[: self.related_count]
|
||||
kwargs["related_objects"] = related
|
||||
kwargs["can_edit"] = self.can_edit(self.object)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
def get_comment_form(self):
|
||||
@ -210,7 +216,7 @@ class PageDetailView(BasePageDetailView):
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class PageCreateView(BaseView, CreateView):
|
||||
class PageCreateView(CanEditMixin, BaseView, CreateView):
|
||||
def get_page(self):
|
||||
return self.object
|
||||
|
||||
@ -218,7 +224,7 @@ class PageCreateView(BaseView, CreateView):
|
||||
return self.request.path
|
||||
|
||||
|
||||
class PageUpdateView(BaseView, UpdateView):
|
||||
class PageUpdateView(CanEditMixin, BaseView, UpdateView):
|
||||
def get_page(self):
|
||||
return self.object
|
||||
|
||||
|
@ -71,6 +71,9 @@ class ProgramCreateView(PermissionRequiredMixin, ProgramEditMixin, page.PageCrea
|
||||
|
||||
|
||||
class ProgramUpdateView(UserPassesTestMixin, ProgramEditMixin, page.PageUpdateView):
|
||||
def can_edit(self, obj):
|
||||
return self.test_func()
|
||||
|
||||
def test_func(self):
|
||||
obj = self.get_object()
|
||||
return permissions.program.can(self.request.user, "update", obj)
|
||||
|
Reference in New Issue
Block a user