Replace md editor with ckeditor

This commit is contained in:
2022-08-23 17:54:58 +02:00
parent 7cc917d9f7
commit ca459c467b
23 changed files with 97 additions and 112 deletions

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.1 on 2022-08-23 15:54
import ckeditor_uploader.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("consist", "0004_alter_consist_company"),
]
operations = [
migrations.AlterField(
model_name="consist",
name="notes",
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True),
),
]

View File

@@ -2,6 +2,8 @@ from uuid import uuid4
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from ckeditor_uploader.fields import RichTextUploadingField
from metadata.models import Company, Tag from metadata.models import Company, Tag
from roster.models import RollingStock from roster.models import RollingStock
@@ -16,7 +18,7 @@ class Consist(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE) company = models.ForeignKey(Company, on_delete=models.CASCADE)
era = models.CharField(max_length=32, blank=True) era = models.CharField(max_length=32, blank=True)
image = models.ImageField(upload_to="images/", null=True, blank=True) image = models.ImageField(upload_to="images/", null=True, blank=True)
notes = models.TextField(blank=True) notes = RichTextUploadingField(blank=True)
creation_time = models.DateTimeField(auto_now_add=True) creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True) updated_time = models.DateTimeField(auto_now=True)

View File

@@ -1,7 +1,6 @@
from django.db import models from django.db import models
from django.contrib import admin from django.contrib import admin
from solo.admin import SingletonModelAdmin from solo.admin import SingletonModelAdmin
from martor.widgets import AdminMartorWidget
from portal.models import SiteConfiguration, Flatpage from portal.models import SiteConfiguration, Flatpage
@@ -14,10 +13,6 @@ class FlatpageAdmin(admin.ModelAdmin):
list_display = ("name", "path") list_display = ("name", "path")
search_fields = ("name",) search_fields = ("name",)
formfield_overrides = {
models.TextField: {'widget': AdminMartorWidget},
}
fieldsets = ( fieldsets = (
( (
None, None,

View File

@@ -0,0 +1,35 @@
# Generated by Django 4.1 on 2022-08-23 15:54
import ckeditor.fields
import ckeditor_uploader.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("portal", "0010_flatpage_creation_time_flatpage_updated_time"),
]
operations = [
migrations.AlterField(
model_name="flatpage",
name="content",
field=ckeditor_uploader.fields.RichTextUploadingField(),
),
migrations.AlterField(
model_name="siteconfiguration",
name="about",
field=ckeditor.fields.RichTextField(blank=True),
),
migrations.AlterField(
model_name="siteconfiguration",
name="footer",
field=ckeditor.fields.RichTextField(blank=True),
),
migrations.AlterField(
model_name="siteconfiguration",
name="footer_extended",
field=ckeditor.fields.RichTextField(blank=True),
),
]

View File

@@ -3,7 +3,9 @@ from django.db import models
from django.urls import reverse from django.urls import reverse
from django.dispatch.dispatcher import receiver from django.dispatch.dispatcher import receiver
from solo.models import SingletonModel from solo.models import SingletonModel
from martor.models import MartorField
from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField
from ram import __version__ as app_version from ram import __version__ as app_version
from ram.utils import slugify from ram.utils import slugify
@@ -14,7 +16,7 @@ class SiteConfiguration(SingletonModel):
max_length=256, default="Railroad Assets Manager" max_length=256, default="Railroad Assets Manager"
) )
site_author = models.CharField(max_length=256, blank=True) site_author = models.CharField(max_length=256, blank=True)
about = models.TextField(blank=True) about = RichTextField(blank=True)
items_per_page = models.CharField( items_per_page = models.CharField(
max_length=2, max_length=2,
choices=[(str(x * 3), str(x * 3)) for x in range(2, 11)], choices=[(str(x * 3), str(x * 3)) for x in range(2, 11)],
@@ -29,8 +31,8 @@ class SiteConfiguration(SingletonModel):
], ],
default="type", default="type",
) )
footer = models.TextField(blank=True) footer = RichTextField(blank=True)
footer_extended = models.TextField(blank=True) footer_extended = RichTextField(blank=True)
show_version = models.BooleanField(default=True) show_version = models.BooleanField(default=True)
class Meta: class Meta:
@@ -50,7 +52,7 @@ class Flatpage(models.Model):
name = models.CharField(max_length=256, unique=True) name = models.CharField(max_length=256, unique=True)
path = models.CharField(max_length=256, unique=True) path = models.CharField(max_length=256, unique=True)
draft = models.BooleanField(default=True) draft = models.BooleanField(default=True)
content = MartorField() content = RichTextUploadingField()
creation_time = models.DateTimeField(auto_now_add=True) creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True) updated_time = models.DateTimeField(auto_now=True)

View File

@@ -1,6 +1,5 @@
{% load static %} {% load static %}
{% load solo_tags %} {% load solo_tags %}
{% load markdown %}
{% load show_menu %} {% load show_menu %}
{% get_solo 'portal.SiteConfiguration' as site_conf %} {% get_solo 'portal.SiteConfiguration' as site_conf %}

View File

@@ -1,5 +1,4 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load markdown %}
{% block header %} {% block header %}
<h1 class="fw-light">Companies</h1> <h1 class="fw-light">Companies</h1>

View File

@@ -1,5 +1,4 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load markdown %}
{% block header %} {% block header %}
<h1 class="fw-light">{{ consist }}</h1> <h1 class="fw-light">{{ consist }}</h1>

View File

@@ -1,5 +1,4 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load markdown %}
{% block header %} {% block header %}
<h1 class="fw-light">Consists</h1> <h1 class="fw-light">Consists</h1>

View File

@@ -1,5 +1,4 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load markdown %}
{% block header %} {% block header %}
<h1 class="fw-light">{{ flatpage.name }}</h1> <h1 class="fw-light">{{ flatpage.name }}</h1>
@@ -9,7 +8,7 @@
<section class="py-4 text-start container"> <section class="py-4 text-start container">
<div class="row"> <div class="row">
<div class="mx-auto"> <div class="mx-auto">
<div>{{ flatpage.content | markdown | safe }} </div> <div>{{ flatpage.content | safe }} </div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end"> <div class="d-grid gap-2 d-md-flex justify-content-md-end">
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:portal_flatpage_change' flatpage.pk %}">Edit</a>{% endif %} {% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:portal_flatpage_change' flatpage.pk %}">Edit</a>{% endif %}
</div> </div>

View File

@@ -1,9 +1,8 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load markdown %}
{% block header %} {% block header %}
{% if site_conf.about %}<h1 class="fw-light">About</h1>{% endif %} {% if site_conf.about %}<h1 class="fw-light">About</h1>{% endif %}
<p class="lead text-muted">{{ site_conf.about | markdown | safe }}</p> <p class="lead text-muted">{{ site_conf.about | safe }}</p>
{% endblock %} {% endblock %}
{% block pagination %} {% block pagination %}

View File

@@ -1,15 +1,13 @@
{% load markdown %}
<footer class="text-muted py-4"> <footer class="text-muted py-4">
<div class="container"> <div class="container">
<p class="float-end mb-1"> <p class="float-end mb-1">
<a href="#">Back to top</a> <a href="#">Back to top</a>
</p> </p>
<div id="footer" class="mb-1"> <div id="footer" class="mb-1">
<p>&copy; {% now "Y" %}</p> {{ site_conf.footer | markdown | safe }} <p>&copy; {% now "Y" %}</p> {{ site_conf.footer | safe }}
</div> </div>
<div id="footer_extended" class="mb-0"> <div id="footer_extended" class="mb-0">
{{ site_conf.footer_extended | markdown | safe }} {{ site_conf.footer_extended | safe }}
</div> </div>
</div> </div>

View File

@@ -1,5 +1,4 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load markdown %}
{% block header %} {% block header %}
<h1 class="fw-light">{{ rolling_stock }}</h1> <h1 class="fw-light">{{ rolling_stock }}</h1>
@@ -258,7 +257,7 @@
</table> </table>
</div> </div>
<div class="tab-pane fade" id="nav-notes" role="tabpanel" aria-labelledby="nav-notes-tab"> <div class="tab-pane fade" id="nav-notes" role="tabpanel" aria-labelledby="nav-notes-tab">
{{ rolling_stock.notes | markdown | safe }} {{ rolling_stock.notes | safe }}
</div> </div>
<div class="tab-pane fade" id="nav-documents" role="tabpanel" aria-labelledby="nav-documents-tab"> <div class="tab-pane fade" id="nav-documents" role="tabpanel" aria-labelledby="nav-documents-tab">
<table class="table table-striped"> <table class="table table-striped">

View File

@@ -1,5 +1,4 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load markdown %}
{% block header %} {% block header %}
<h1 class="fw-light">Scales</h1> <h1 class="fw-light">Scales</h1>

View File

@@ -4,7 +4,6 @@ from portal.views import (
GetHome, GetHome,
GetHomeFiltered, GetHomeFiltered,
GetFlatpage, GetFlatpage,
MDUploader,
GetRollingStock, GetRollingStock,
GetConsist, GetConsist,
Consists, Consists,
@@ -14,7 +13,6 @@ from portal.views import (
urlpatterns = [ urlpatterns = [
path("", GetHome.as_view(), name="index"), path("", GetHome.as_view(), name="index"),
path("uploader/", MDUploader.as_view(), name="markdown_uploader"),
path("<int:page>", GetHome.as_view(), name="index_pagination"), path("<int:page>", GetHome.as_view(), name="index_pagination"),
path( path(
"page/<str:flatpage>", "page/<str:flatpage>",

View File

@@ -1,72 +1,4 @@
import os
import json
import uuid
from django.apps import apps from django.apps import apps
from django.conf import settings
from django.http import HttpResponse
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.decorators import login_required
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from martor.utils import LazyEncoder
@login_required
def markdown_uploader(request):
"""
Makdown image upload for locale storage
and represent as json to markdown editor.
"""
if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest":
if "markdown-image-upload" in request.FILES:
image = request.FILES["markdown-image-upload"]
image_types = [
"image/png",
"image/jpg",
"image/jpeg",
"image/pjpeg",
"image/gif",
]
if image.content_type not in image_types:
data = json.dumps(
{"status": 405, "error": _("Bad image format.")},
cls=LazyEncoder,
)
return HttpResponse(
data, content_type="application/json", status=405
)
if image.size > settings.MAX_IMAGE_UPLOAD_SIZE:
to_MB = settings.MAX_IMAGE_UPLOAD_SIZE / (1024 * 1024)
data = json.dumps(
{
"status": 405,
"error": _("Maximum image file is %(size)s MB.")
% {"size": to_MB},
},
cls=LazyEncoder,
)
return HttpResponse(
data, content_type="application/json", status=405
)
img_uuid = "{0}-{1}".format(
uuid.uuid4().hex[:10], image.name.replace(" ", "-")
)
tmp_file = os.path.join(settings.MARTOR_UPLOAD_PATH, img_uuid)
def_path = default_storage.save(
tmp_file, ContentFile(image.read())
)
img_url = os.path.join(settings.MEDIA_URL, def_path)
data = json.dumps(
{"status": 200, "link": img_url, "name": image.name}
)
return HttpResponse(data, content_type="application/json")
return HttpResponse(_("Invalid request!"))
return HttpResponse(_("Invalid request!"))
def get_site_conf(): def get_site_conf():

View File

@@ -8,7 +8,7 @@ from django.shortcuts import render
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, PageNotAnInteger from django.core.paginator import Paginator, PageNotAnInteger
from portal.utils import get_site_conf, markdown_uploader from portal.utils import get_site_conf
from portal.models import Flatpage from portal.models import Flatpage
from roster.models import RollingStock from roster.models import RollingStock
from consist.models import Consist from consist.models import Consist
@@ -259,8 +259,3 @@ class GetFlatpage(View):
"flatpage.html", "flatpage.html",
{"flatpage": flatpage}, {"flatpage": flatpage},
) )
class MDUploader(View):
def post(self, request):
return markdown_uploader(request)

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix from ram.utils import git_suffix
__version__ = "0.0.15" __version__ = "0.0.16"
__version__ += git_suffix(__file__) __version__ += git_suffix(__file__)

View File

@@ -46,7 +46,8 @@ INSTALLED_APPS = [
"adminsortable2", "adminsortable2",
"django_countries", "django_countries",
"solo", "solo",
"martor", "ckeditor",
"ckeditor_uploader",
"rest_framework", "rest_framework",
"ram", "ram",
"portal", "portal",
@@ -141,11 +142,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
MEDIA_URL = "media/" MEDIA_URL = "media/"
MEDIA_ROOT = STORAGE_DIR / "media" MEDIA_ROOT = STORAGE_DIR / "media"
CKEDITOR_UPLOAD_PATH = "uploads/"
MARTOR_UPLOAD_PATH = "images/uploads/{}".format(time.strftime("%Y/%m/%d/"))
MARTOR_UPLOAD_URL = "/portal/uploader/"
MAX_IMAGE_UPLOAD_SIZE = 5242880 # 5MB
COUNTRIES_OVERRIDE = { COUNTRIES_OVERRIDE = {
"ZZ": "Freelance", "ZZ": "Freelance",

View File

@@ -21,7 +21,7 @@ from django.urls import include, path
urlpatterns = [ urlpatterns = [
path("", lambda r: redirect("portal/")), path("", lambda r: redirect("portal/")),
path('martor/', include('martor.urls')), path("ckeditor/", include("ckeditor_uploader.urls")),
path("portal/", include("portal.urls")), path("portal/", include("portal.urls")),
path("ht/", include("health_check.urls")), path("ht/", include("health_check.urls")),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.1 on 2022-08-23 15:54
import ckeditor_uploader.fields
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("roster", "0009_alter_rollingstock_options_and_more"),
]
operations = [
migrations.AlterField(
model_name="rollingstock",
name="notes",
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True),
),
]

View File

@@ -6,7 +6,7 @@ from django.urls import reverse
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
# from django.core.files.storage import FileSystemStorage from ckeditor_uploader.fields import RichTextUploadingField
from ram.utils import get_image_preview from ram.utils import get_image_preview
from metadata.models import ( from metadata.models import (
@@ -94,7 +94,7 @@ class RollingStock(models.Model):
era = models.CharField(max_length=32, blank=True) era = models.CharField(max_length=32, blank=True)
production_year = models.SmallIntegerField(null=True, blank=True) production_year = models.SmallIntegerField(null=True, blank=True)
purchase_date = models.DateField(null=True, blank=True) purchase_date = models.DateField(null=True, blank=True)
notes = models.TextField(blank=True) notes = RichTextUploadingField(blank=True)
tags = models.ManyToManyField( tags = models.ManyToManyField(
Tag, related_name="rolling_stock", blank=True Tag, related_name="rolling_stock", blank=True
) )

View File

@@ -7,5 +7,6 @@ django-solo
django-countries django-countries
django-health-check django-health-check
django-admin-sortable2 django-admin-sortable2
django-ckeditor
# psycopg2-binary # psycopg2-binary
pySerial pySerial