From 7cc917d9f75c24dc25914a9474d8499cd1efc5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniele=20Vigan=C3=B2?= Date: Mon, 22 Aug 2022 18:16:59 +0200 Subject: [PATCH] Use a markdown editor --- ram/portal/admin.py | 6 ++++ ram/portal/models.py | 3 +- ram/portal/urls.py | 2 ++ ram/portal/utils.py | 68 ++++++++++++++++++++++++++++++++++++++++++++ ram/portal/views.py | 11 +++++-- ram/ram/settings.py | 7 +++++ ram/ram/urls.py | 1 + 7 files changed, 95 insertions(+), 3 deletions(-) diff --git a/ram/portal/admin.py b/ram/portal/admin.py index ef8097e..f481218 100644 --- a/ram/portal/admin.py +++ b/ram/portal/admin.py @@ -1,5 +1,7 @@ +from django.db import models from django.contrib import admin from solo.admin import SingletonModelAdmin +from martor.widgets import AdminMartorWidget from portal.models import SiteConfiguration, Flatpage @@ -12,6 +14,10 @@ class FlatpageAdmin(admin.ModelAdmin): list_display = ("name", "path") search_fields = ("name",) + formfield_overrides = { + models.TextField: {'widget': AdminMartorWidget}, + } + fieldsets = ( ( None, diff --git a/ram/portal/models.py b/ram/portal/models.py index 225493f..d8c77c9 100644 --- a/ram/portal/models.py +++ b/ram/portal/models.py @@ -3,6 +3,7 @@ from django.db import models from django.urls import reverse from django.dispatch.dispatcher import receiver from solo.models import SingletonModel +from martor.models import MartorField from ram import __version__ as app_version from ram.utils import slugify @@ -49,7 +50,7 @@ class Flatpage(models.Model): name = models.CharField(max_length=256, unique=True) path = models.CharField(max_length=256, unique=True) draft = models.BooleanField(default=True) - content = models.TextField(blank=True) + content = MartorField() creation_time = models.DateTimeField(auto_now_add=True) updated_time = models.DateTimeField(auto_now=True) diff --git a/ram/portal/urls.py b/ram/portal/urls.py index 297527a..23545d1 100644 --- a/ram/portal/urls.py +++ b/ram/portal/urls.py @@ -4,6 +4,7 @@ from portal.views import ( GetHome, GetHomeFiltered, GetFlatpage, + MDUploader, GetRollingStock, GetConsist, Consists, @@ -13,6 +14,7 @@ from portal.views import ( urlpatterns = [ path("", GetHome.as_view(), name="index"), + path("uploader/", MDUploader.as_view(), name="markdown_uploader"), path("", GetHome.as_view(), name="index_pagination"), path( "page/", diff --git a/ram/portal/utils.py b/ram/portal/utils.py index 0c2b6cb..9338ca2 100644 --- a/ram/portal/utils.py +++ b/ram/portal/utils.py @@ -1,4 +1,72 @@ +import os +import json +import uuid + 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(): diff --git a/ram/portal/views.py b/ram/portal/views.py index 422ad9c..19ae7e9 100644 --- a/ram/portal/views.py +++ b/ram/portal/views.py @@ -8,7 +8,7 @@ from django.shortcuts import render from django.core.exceptions import ObjectDoesNotExist from django.core.paginator import Paginator, PageNotAnInteger -from portal.utils import get_site_conf +from portal.utils import get_site_conf, markdown_uploader from portal.models import Flatpage from roster.models import RollingStock from consist.models import Consist @@ -248,7 +248,9 @@ class Scales(View): class GetFlatpage(View): def get(self, request, flatpage): try: - flatpage = Flatpage.objects.get(path=flatpage) + flatpage = Flatpage.objects.get( + Q(Q(path=flatpage) & Q(draft=False)) + ) except ObjectDoesNotExist: raise Http404 @@ -257,3 +259,8 @@ class GetFlatpage(View): "flatpage.html", {"flatpage": flatpage}, ) + + +class MDUploader(View): + def post(self, request): + return markdown_uploader(request) diff --git a/ram/ram/settings.py b/ram/ram/settings.py index c5f0a7e..caa664d 100644 --- a/ram/ram/settings.py +++ b/ram/ram/settings.py @@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/4.0/ref/settings/ """ import os +import time from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -45,6 +46,7 @@ INSTALLED_APPS = [ "adminsortable2", "django_countries", "solo", + "martor", "rest_framework", "ram", "portal", @@ -140,6 +142,11 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" MEDIA_URL = "media/" MEDIA_ROOT = STORAGE_DIR / "media" +MARTOR_UPLOAD_PATH = "images/uploads/{}".format(time.strftime("%Y/%m/%d/")) +MARTOR_UPLOAD_URL = "/portal/uploader/" + +MAX_IMAGE_UPLOAD_SIZE = 5242880 # 5MB + COUNTRIES_OVERRIDE = { "ZZ": "Freelance", } diff --git a/ram/ram/urls.py b/ram/ram/urls.py index e05412a..1f6f9b2 100644 --- a/ram/ram/urls.py +++ b/ram/ram/urls.py @@ -21,6 +21,7 @@ from django.urls import include, path urlpatterns = [ path("", lambda r: redirect("portal/")), + path('martor/', include('martor.urls')), path("portal/", include("portal.urls")), path("ht/", include("health_check.urls")), path("admin/", admin.site.urls),