3 Commits

18 changed files with 342 additions and 31 deletions

View File

@@ -0,0 +1,121 @@
# Generated by Django 5.0.1 on 2024-01-20 21:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0010_alter_bookimage_image"),
]
operations = [
migrations.AlterField(
model_name="book",
name="language",
field=models.CharField(
choices=[
("af", "Afrikaans"),
("ar", "Arabic"),
("ar-dz", "Algerian Arabic"),
("ast", "Asturian"),
("az", "Azerbaijani"),
("bg", "Bulgarian"),
("be", "Belarusian"),
("bn", "Bengali"),
("br", "Breton"),
("bs", "Bosnian"),
("ca", "Catalan"),
("ckb", "Central Kurdish (Sorani)"),
("cs", "Czech"),
("cy", "Welsh"),
("da", "Danish"),
("de", "German"),
("dsb", "Lower Sorbian"),
("el", "Greek"),
("en", "English"),
("en-au", "Australian English"),
("en-gb", "British English"),
("eo", "Esperanto"),
("es", "Spanish"),
("es-ar", "Argentinian Spanish"),
("es-co", "Colombian Spanish"),
("es-mx", "Mexican Spanish"),
("es-ni", "Nicaraguan Spanish"),
("es-ve", "Venezuelan Spanish"),
("et", "Estonian"),
("eu", "Basque"),
("fa", "Persian"),
("fi", "Finnish"),
("fr", "French"),
("fy", "Frisian"),
("ga", "Irish"),
("gd", "Scottish Gaelic"),
("gl", "Galician"),
("he", "Hebrew"),
("hi", "Hindi"),
("hr", "Croatian"),
("hsb", "Upper Sorbian"),
("hu", "Hungarian"),
("hy", "Armenian"),
("ia", "Interlingua"),
("id", "Indonesian"),
("ig", "Igbo"),
("io", "Ido"),
("is", "Icelandic"),
("it", "Italian"),
("ja", "Japanese"),
("ka", "Georgian"),
("kab", "Kabyle"),
("kk", "Kazakh"),
("km", "Khmer"),
("kn", "Kannada"),
("ko", "Korean"),
("ky", "Kyrgyz"),
("lb", "Luxembourgish"),
("lt", "Lithuanian"),
("lv", "Latvian"),
("mk", "Macedonian"),
("ml", "Malayalam"),
("mn", "Mongolian"),
("mr", "Marathi"),
("ms", "Malay"),
("my", "Burmese"),
("nb", "Norwegian Bokmål"),
("ne", "Nepali"),
("nl", "Dutch"),
("nn", "Norwegian Nynorsk"),
("os", "Ossetic"),
("pa", "Punjabi"),
("pl", "Polish"),
("pt", "Portuguese"),
("pt-br", "Brazilian Portuguese"),
("ro", "Romanian"),
("ru", "Russian"),
("sk", "Slovak"),
("sl", "Slovenian"),
("sq", "Albanian"),
("sr", "Serbian"),
("sr-latn", "Serbian Latin"),
("sv", "Swedish"),
("sw", "Swahili"),
("ta", "Tamil"),
("te", "Telugu"),
("tg", "Tajik"),
("th", "Thai"),
("tk", "Turkmen"),
("tr", "Turkish"),
("tt", "Tatar"),
("udm", "Udmurt"),
("ug", "Uyghur"),
("uk", "Ukrainian"),
("ur", "Urdu"),
("uz", "Uzbek"),
("vi", "Vietnamese"),
("zh-hans", "Simplified Chinese"),
("zh-hant", "Traditional Chinese"),
],
default="en",
max_length=7,
),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.0.2 on 2024-02-17 12:19
import tinymce.models
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0011_alter_book_language"),
]
operations = [
migrations.AlterField(
model_name="book",
name="notes",
field=tinymce.models.HTMLField(blank=True),
),
]

View File

@@ -6,7 +6,7 @@ from django.conf import settings
from django.urls import reverse
from django_countries.fields import CountryField
from ckeditor_uploader.fields import RichTextUploadingField
from tinymce import models as tinymce
from metadata.models import Tag
from ram.utils import DeduplicatedStorage
@@ -56,7 +56,7 @@ class Book(models.Model):
tags = models.ManyToManyField(
Tag, related_name="bookshelf", blank=True
)
notes = RichTextUploadingField(blank=True)
notes = tinymce.HTMLField(blank=True)
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.0.2 on 2024-02-17 12:19
import tinymce.models
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("consist", "0009_alter_consist_image"),
]
operations = [
migrations.AlterField(
model_name="consist",
name="notes",
field=tinymce.models.HTMLField(blank=True),
),
]

View File

@@ -4,7 +4,7 @@ from uuid import uuid4
from django.db import models
from django.urls import reverse
from ckeditor_uploader.fields import RichTextUploadingField
from tinymce import models as tinymce
from ram.utils import DeduplicatedStorage
from metadata.models import Company, Tag
@@ -26,7 +26,7 @@ class Consist(models.Model):
null=True,
blank=True,
)
notes = RichTextUploadingField(blank=True)
notes = tinymce.HTMLField(blank=True)
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)

View File

@@ -6,6 +6,7 @@ from portal.models import SiteConfiguration, Flatpage
@admin.register(SiteConfiguration)
class SiteConfigurationAdmin(SingletonModelAdmin):
readonly_fields = ("site_name",)
fieldsets = (
(
None,

View File

@@ -0,0 +1,16 @@
# Generated by Django 5.0.1 on 2024-01-20 21:02
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("portal", "0015_siteconfiguration_use_cdn"),
]
operations = [
migrations.RemoveField(
model_name="siteconfiguration",
name="site_name",
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.0.2 on 2024-02-17 12:19
import tinymce.models
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("portal", "0016_remove_siteconfiguration_site_name"),
]
operations = [
migrations.AlterField(
model_name="flatpage",
name="content",
field=tinymce.models.HTMLField(),
),
migrations.AlterField(
model_name="siteconfiguration",
name="about",
field=tinymce.models.HTMLField(blank=True),
),
migrations.AlterField(
model_name="siteconfiguration",
name="footer",
field=tinymce.models.HTMLField(blank=True),
),
migrations.AlterField(
model_name="siteconfiguration",
name="footer_extended",
field=tinymce.models.HTMLField(blank=True),
),
]

View File

@@ -1,23 +1,20 @@
import django
from django.db import models
from django.conf import settings
from django.urls import reverse
from django.dispatch.dispatcher import receiver
from django.utils.safestring import mark_safe
from solo.models import SingletonModel
from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField
from tinymce import models as tinymce
from ram import __version__ as app_version
from ram.utils import slugify
class SiteConfiguration(SingletonModel):
site_name = models.CharField(
max_length=256, default="Railroad Assets Manager"
)
site_author = models.CharField(max_length=256, blank=True)
about = RichTextField(blank=True)
about = tinymce.HTMLField(blank=True)
items_per_page = models.CharField(
max_length=2,
choices=[(str(x * 3), str(x * 3)) for x in range(2, 11)],
@@ -32,8 +29,8 @@ class SiteConfiguration(SingletonModel):
],
default="type",
)
footer = RichTextField(blank=True)
footer_extended = RichTextField(blank=True)
footer = tinymce.HTMLField(blank=True)
footer_extended = tinymce.HTMLField(blank=True)
show_version = models.BooleanField(default=True)
use_cdn = models.BooleanField(default=True)
extra_head = models.TextField(blank=True)
@@ -44,6 +41,9 @@ class SiteConfiguration(SingletonModel):
def __str__(self):
return "Site Configuration"
def site_name(self):
return settings.SITE_NAME
def version(self):
return app_version
@@ -55,7 +55,7 @@ class Flatpage(models.Model):
name = models.CharField(max_length=256, unique=True)
path = models.CharField(max_length=256, unique=True)
published = models.BooleanField(default=False)
content = RichTextUploadingField()
content = tinymce.HTMLField()
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)

View File

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

View File

@@ -1,10 +1,4 @@
from django.contrib import admin
from django.db.utils import OperationalError, ProgrammingError
from portal.utils import get_site_conf
from django.conf import settings
try:
site_name = get_site_conf().site_name
except (OperationalError, ProgrammingError):
site_name = "Train Assets Manager"
admin.site.site_header = site_name
admin.site.site_header = settings.SITE_NAME

View File

@@ -44,8 +44,7 @@ INSTALLED_APPS = [
"adminsortable2",
"django_countries",
"solo",
"ckeditor",
"ckeditor_uploader",
"tinymce",
"rest_framework",
"ram",
"portal",
@@ -60,7 +59,7 @@ MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware',
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
@@ -142,13 +141,31 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
MEDIA_URL = "media/"
MEDIA_ROOT = STORAGE_DIR / "media"
CKEDITOR_UPLOAD_PATH = "uploads/"
TINYMCE_DEFAULT_CONFIG = {
"height": "500px",
"menubar": False,
"plugins": "autolink lists link image charmap preview anchor "
"searchreplace visualblocks code fullscreen insertdatetime media "
"table paste code",
"toolbar": "undo redo | "
"bold italic underline strikethrough removeformat | "
"fontsizeselect formatselect | "
"alignleft aligncenter alignright alignjustify | "
"outdent indent numlist bullist | "
"insertfile image media pageembed template link anchor codesample | "
"charmap | "
"fullscreen preview code",
"images_upload_url": "/tinymce/upload_image",
}
COUNTRIES_OVERRIDE = {
"EU": "Europe",
"XX": "None",
}
SITE_NAME = "Railroad Assets Manger"
# Image used on cards without a custom image uploaded.
# The file must be placed in the root of the 'static' folder
DEFAULT_CARD_IMAGE = "coming_soon.svg"

View File

@@ -20,9 +20,16 @@ from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
from ram.views import UploadImage
urlpatterns = [
path("", lambda r: redirect("portal/")),
path("ckeditor/", include("ckeditor_uploader.urls")),
path('tinymce/', include('tinymce.urls')),
path(
"tinymce/upload_image",
UploadImage.as_view(),
name="upload_image"
),
path("portal/", include("portal.urls")),
path("admin/", admin.site.urls),
path("api/v1/consist/", include("consist.urls")),

59
ram/ram/views.py Normal file
View File

@@ -0,0 +1,59 @@
import os
import datetime
import posixpath
from pathlib import Path
from PIL import Image, UnidentifiedImageError
from django.views import View
from django.conf import settings
from django.http import (
JsonResponse, HttpResponseForbidden, HttpResponse
)
from django.utils.text import slugify as slugify
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name='dispatch')
class UploadImage(View):
def post(self, request, application=None, model=None):
if not request.user.is_authenticated:
raise HttpResponseForbidden()
file_obj = request.FILES['file']
file_name, file_extension = os.path.splitext(file_obj.name)
file_name = slugify(file_name) + file_extension
try:
Image.open(file_obj)
except UnidentifiedImageError:
response = HttpResponse("Invalid extension") # FIXME
response.status_code = 400
return response
today = datetime.date.today()
container = (
"uploads",
today.strftime("%Y"),
today.strftime("%m"),
today.strftime("%d"),
)
file_path = os.path.join(
settings.MEDIA_ROOT,
*(p for p in container)
)
Path(file_path).mkdir(parents=True, exist_ok=True)
with open(os.path.join(file_path, file_name), 'wb+') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return JsonResponse({
'message': 'Image uploaded successfully',
'location': posixpath.join(
settings.MEDIA_URL,
*(p for p in container),
file_name
)
})

View File

@@ -0,0 +1,24 @@
# Generated by Django 5.0.2 on 2024-02-17 12:19
import tinymce.models
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("roster", "0021_alter_rollingstockdocument_file_and_more"),
]
operations = [
migrations.AlterField(
model_name="rollingstock",
name="notes",
field=tinymce.models.HTMLField(blank=True),
),
migrations.AlterField(
model_name="rollingstockjournal",
name="log",
field=tinymce.models.HTMLField(),
),
]

View File

@@ -7,7 +7,7 @@ from django.urls import reverse
from django.conf import settings
from django.dispatch import receiver
from ckeditor_uploader.fields import RichTextUploadingField
from tinymce import models as tinymce
from ram.models import Document, Image, PropertyInstance
from ram.utils import DeduplicatedStorage
@@ -85,7 +85,7 @@ class RollingStock(models.Model):
era = models.CharField(max_length=32, blank=True)
production_year = models.SmallIntegerField(null=True, blank=True)
purchase_date = models.DateField(null=True, blank=True)
notes = RichTextUploadingField(blank=True)
notes = tinymce.HTMLField(blank=True)
tags = models.ManyToManyField(
Tag, related_name="rolling_stock", blank=True
)
@@ -175,7 +175,7 @@ class RollingStockJournal(models.Model):
blank=False,
)
date = models.DateField()
log = RichTextUploadingField()
log = tinymce.HTMLField()
private = models.BooleanField(default=False)
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)

View File

@@ -7,7 +7,7 @@ django-solo
django-countries
django-health-check
django-admin-sortable2
django-ckeditor
django-tinymce
# Optional: # psycopg2-binary
# Optional: # pySerial
# Required by django-countries and not always installed

BIN
sample_data/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB