3 Commits

Author SHA1 Message Date
e7d34ce8e0 Remove unused args in upload_image 2024-02-17 23:06:41 +01:00
19eb70c492 Replace ckeditor with tinymce (#30)
* Replace ckeditor with tinymce due to deprecation
* Remove any ckeditor dependency from old migrations
   Disable alters, replace create with plain models.TextField
* Reformat files
* Add more hardening in image_upload
2024-02-17 23:05:18 +01:00
4428b8c11d Fix a RuntimeWarning introduced in Django 5 (#29) 2024-01-20 22:08:10 +01:00
8 changed files with 73 additions and 66 deletions

View File

@@ -1,6 +1,7 @@
# Generated by Django 4.2.5 on 2023-10-01 20:16 # Generated by Django 4.2.5 on 2023-10-01 20:16
import ckeditor_uploader.fields # ckeditor removal
# import ckeditor_uploader.fields
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import uuid import uuid
@@ -47,7 +48,8 @@ class Migration(migrations.Migration):
("ISBN", models.CharField(max_length=13, unique=True)), ("ISBN", models.CharField(max_length=13, unique=True)),
("publication_year", models.SmallIntegerField(blank=True, null=True)), ("publication_year", models.SmallIntegerField(blank=True, null=True)),
("purchase_date", models.DateField(blank=True, null=True)), ("purchase_date", models.DateField(blank=True, null=True)),
("notes", ckeditor_uploader.fields.RichTextUploadingField(blank=True)), # ("notes", ckeditor_uploader.fields.RichTextUploadingField(blank=True)),
("notes", models.TextField(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)),
("authors", models.ManyToManyField(to="bookshelf.author")), ("authors", models.ManyToManyField(to="bookshelf.author")),

View File

@@ -1,6 +1,7 @@
# Generated by Django 4.1 on 2022-08-23 15:54 # Generated by Django 4.1 on 2022-08-23 15:54
import ckeditor_uploader.fields # ckeditor removal
# import ckeditor_uploader.fields
from django.db import migrations from django.db import migrations
@@ -11,9 +12,9 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.AlterField( # migrations.AlterField(
model_name="consist", # model_name="consist",
name="notes", # name="notes",
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True), # field=ckeditor_uploader.fields.RichTextUploadingField(blank=True),
), # ),
] ]

View File

@@ -1,7 +1,8 @@
# Generated by Django 4.1 on 2022-08-23 15:54 # Generated by Django 4.1 on 2022-08-23 15:54
import ckeditor.fields # ckeditor dependency removal
import ckeditor_uploader.fields # import ckeditor.fields
# import ckeditor_uploader.fields
from django.db import migrations from django.db import migrations
@@ -12,24 +13,24 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.AlterField( # migrations.AlterField(
model_name="flatpage", # model_name="flatpage",
name="content", # name="content",
field=ckeditor_uploader.fields.RichTextUploadingField(), # field=ckeditor_uploader.fields.RichTextUploadingField(),
), # ),
migrations.AlterField( # migrations.AlterField(
model_name="siteconfiguration", # model_name="siteconfiguration",
name="about", # name="about",
field=ckeditor.fields.RichTextField(blank=True), # field=ckeditor.fields.RichTextField(blank=True),
), # ),
migrations.AlterField( # migrations.AlterField(
model_name="siteconfiguration", # model_name="siteconfiguration",
name="footer", # name="footer",
field=ckeditor.fields.RichTextField(blank=True), # field=ckeditor.fields.RichTextField(blank=True),
), # ),
migrations.AlterField( # migrations.AlterField(
model_name="siteconfiguration", # model_name="siteconfiguration",
name="footer_extended", # name="footer_extended",
field=ckeditor.fields.RichTextField(blank=True), # field=ckeditor.fields.RichTextField(blank=True),
), # ),
] ]

View File

@@ -13,6 +13,7 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path 1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.shortcuts import redirect from django.shortcuts import redirect
@@ -24,12 +25,8 @@ from ram.views import UploadImage
urlpatterns = [ urlpatterns = [
path("", lambda r: redirect("portal/")), path("", lambda r: redirect("portal/")),
path('tinymce/', include('tinymce.urls')), path("tinymce/", include("tinymce.urls")),
path( path("tinymce/upload_image", UploadImage.as_view(), name="upload_image"),
"tinymce/upload_image",
UploadImage.as_view(),
name="upload_image"
),
path("portal/", include("portal.urls")), path("portal/", include("portal.urls")),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("api/v1/consist/", include("consist.urls")), path("api/v1/consist/", include("consist.urls")),

View File

@@ -8,29 +8,29 @@ from PIL import Image, UnidentifiedImageError
from django.views import View from django.views import View
from django.conf import settings from django.conf import settings
from django.http import ( from django.http import (
JsonResponse, HttpResponseForbidden, HttpResponse HttpResponseBadRequest,
HttpResponseForbidden,
JsonResponse,
) )
from django.utils.text import slugify as slugify from django.utils.text import slugify as slugify
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name='dispatch') @method_decorator(csrf_exempt, name="dispatch")
class UploadImage(View): class UploadImage(View):
def post(self, request, application=None, model=None): def post(self, request):
if not request.user.is_authenticated: if not request.user.is_authenticated:
raise HttpResponseForbidden() raise HttpResponseForbidden()
file_obj = request.FILES['file'] file_obj = request.FILES["file"]
file_name, file_extension = os.path.splitext(file_obj.name) file_name, file_extension = os.path.splitext(file_obj.name)
file_name = slugify(file_name) + file_extension file_name = slugify(file_name) + file_extension
try: try:
Image.open(file_obj) Image.open(file_obj)
except UnidentifiedImageError: except UnidentifiedImageError:
response = HttpResponse("Invalid extension") # FIXME return HttpResponseBadRequest()
response.status_code = 400
return response
today = datetime.date.today() today = datetime.date.today()
container = ( container = (
@@ -40,20 +40,23 @@ class UploadImage(View):
today.strftime("%d"), today.strftime("%d"),
) )
file_path = os.path.join( dir_path = os.path.join(settings.MEDIA_ROOT, *(p for p in container))
settings.MEDIA_ROOT, file_path = os.path.normpath(os.path.join(dir_path, file_name))
*(p for p in container) # even if we apply slugify to the file name, add more hardening
) # to avoid any path transversal risk
Path(file_path).mkdir(parents=True, exist_ok=True) if not file_path.startswith(str(settings.MEDIA_ROOT)):
with open(os.path.join(file_path, file_name), 'wb+') as f: return HttpResponseBadRequest()
Path(dir_path).mkdir(parents=True, exist_ok=True)
with open(file_path, "wb+") as f:
for chunk in file_obj.chunks(): for chunk in file_obj.chunks():
f.write(chunk) f.write(chunk)
return JsonResponse({ return JsonResponse(
'message': 'Image uploaded successfully', {
'location': posixpath.join( "message": "Image uploaded successfully",
settings.MEDIA_URL, "location": posixpath.join(
*(p for p in container), settings.MEDIA_URL, *(p for p in container), file_name
file_name ),
}
) )
})

View File

@@ -1,6 +1,7 @@
# Generated by Django 4.1 on 2022-08-23 15:54 # Generated by Django 4.1 on 2022-08-23 15:54
import ckeditor_uploader.fields # ckeditor removal
# import ckeditor_uploader.fields
from django.db import migrations from django.db import migrations
@@ -11,9 +12,9 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.AlterField( # migrations.AlterField(
model_name="rollingstock", # model_name="rollingstock",
name="notes", # name="notes",
field=ckeditor_uploader.fields.RichTextUploadingField(blank=True), # field=ckeditor_uploader.fields.RichTextUploadingField(blank=True),
), # ),
] ]

View File

@@ -1,6 +1,7 @@
# Generated by Django 4.1 on 2022-08-27 12:43 # Generated by Django 4.1 on 2022-08-27 12:43
import ckeditor_uploader.fields # ckeditor removal
# import ckeditor_uploader.fields
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@@ -25,7 +26,8 @@ class Migration(migrations.Migration):
), ),
), ),
("date", models.DateField()), ("date", models.DateField()),
("log", ckeditor_uploader.fields.RichTextUploadingField()), # ("log", ckeditor_uploader.fields.RichTextUploadingField()),
("log", models.TextField()),
("private", models.BooleanField(default=False)), ("private", models.BooleanField(default=False)),
("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)),