Merge pull request #10 from daniviga/flat-pages

Introduce support for Flatpages
This commit is contained in:
2022-08-24 14:54:14 +02:00
committed by GitHub
28 changed files with 293 additions and 36 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,6 +1,38 @@
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 portal.models import SiteConfiguration from portal.models import SiteConfiguration, Flatpage
admin.site.register(SiteConfiguration, SingletonModelAdmin) admin.site.register(SiteConfiguration, SingletonModelAdmin)
@admin.register(Flatpage)
class FlatpageAdmin(admin.ModelAdmin):
readonly_fields = ("path", "creation_time", "updated_time")
list_display = ("name", "path")
search_fields = ("name",)
fieldsets = (
(
None,
{
"fields": (
"name",
"path",
"content",
"draft",
)
},
),
(
"Audit",
{
"classes": ("collapse",),
"fields": (
"creation_time",
"updated_time",
),
},
),
)

View File

@@ -0,0 +1,22 @@
# Generated by Django 4.0.6 on 2022-08-07 15:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('portal', '0007_siteconfiguration_items_ordering'),
]
operations = [
migrations.CreateModel(
name='Flatpage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=256, unique=True)),
('draft', models.BooleanField(default=True)),
('content', models.TextField(blank=True)),
],
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.0.6 on 2022-08-07 15:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('portal', '0008_flatpage'),
]
operations = [
migrations.AddField(
model_name='flatpage',
name='path',
field=models.CharField(default='', max_length=256, unique=True),
preserve_default=False,
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.0.6 on 2022-08-07 15:46
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('portal', '0009_flatpage_path'),
]
operations = [
migrations.AddField(
model_name='flatpage',
name='creation_time',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
preserve_default=False,
),
migrations.AddField(
model_name='flatpage',
name='updated_time',
field=models.DateTimeField(auto_now=True),
),
]

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

@@ -1,8 +1,14 @@
import django import django
from django.db import models from django.db import models
from django.urls import reverse
from django.dispatch.dispatcher import receiver
from solo.models import SingletonModel
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 solo.models import SingletonModel from ram.utils import slugify
class SiteConfiguration(SingletonModel): class SiteConfiguration(SingletonModel):
@@ -10,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)],
@@ -25,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:
@@ -40,3 +46,23 @@ class SiteConfiguration(SingletonModel):
def django_version(self): def django_version(self):
return django.get_version() return django.get_version()
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 = RichTextUploadingField()
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("flatpage", kwargs={"flatpage": self.path})
@receiver(models.signals.pre_save, sender=Flatpage)
def tag_pre_save(sender, instance, **kwargs):
instance.path = slugify(instance.name)

View File

@@ -1,6 +1,6 @@
{% load static %} {% load static %}
{% load solo_tags %} {% load solo_tags %}
{% load markdown %} {% load show_menu %}
{% get_solo 'portal.SiteConfiguration' as site_conf %} {% get_solo 'portal.SiteConfiguration' as site_conf %}
<!doctype html> <!doctype html>
@@ -71,6 +71,7 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{% url 'scales' %}">Scales</a> <a class="nav-link" href="{% url 'scales' %}">Scales</a>
</li> </li>
{% show_menu %}
</ul> </ul>
{% include 'includes/search.html' %} {% include 'includes/search.html' %}
</div> </div>
@@ -84,7 +85,7 @@
</div> </div>
</div> </div>
</section> </section>
<div class="album py-5 bg-light"> <div class="album py-4 bg-light">
<div class="container"> <div class="container">
<a id="rolling-stock"></a> <a id="rolling-stock"></a>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3"> <div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">

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>
@@ -57,7 +56,7 @@
{% block pagination %} {% block pagination %}
{% if company.has_other_pages %} {% if company.has_other_pages %}
<nav aria-label="Page navigation example"> <nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if company.has_previous %} {% if company.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'company_pagination' page=company.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'company_pagination' page=company.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>

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>
@@ -103,7 +102,7 @@
{% block pagination %} {% block pagination %}
{% if rolling_stock.has_other_pages %} {% if rolling_stock.has_other_pages %}
<nav aria-label="Page navigation example"> <nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if rolling_stock.has_previous %} {% if rolling_stock.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'consist_pagination' uuid=consist.uuid page=rolling_stock.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'consist_pagination' uuid=consist.uuid page=rolling_stock.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>

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>
@@ -70,7 +69,7 @@
{% block pagination %} {% block pagination %}
{% if consist.has_other_pages %} {% if consist.has_other_pages %}
<nav aria-label="Page navigation example"> <nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if consist.has_previous %} {% if consist.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'consists_pagination' page=consist.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'consists_pagination' page=consist.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>

View File

@@ -0,0 +1,18 @@
{% extends 'base.html' %}
{% block header %}
<h1 class="fw-light">{{ flatpage.name }}</h1>
<small class="text-muted">Updated {{ flatpage.updated_time | date:"M d, Y H:i" }}</small>
{% endblock %}
{% block extra_content %}
<section class="py-4 text-start container">
<div class="row">
<div class="mx-auto">
<div>{{ flatpage.content | safe }} </div>
<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 %}
</div>
</div>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,12 @@
{% if menu %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
More ...
</a>
{% for m in menu %}
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="{{ m.get_absolute_url }}">{{ m.name }}</a></li>
</ul>
{% endfor %}
</li>
{% endif %}

View File

@@ -1,15 +1,14 @@
{% 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 %}
{% if rolling_stock.has_other_pages %} {% if rolling_stock.has_other_pages %}
<nav aria-label="Page navigation example"> <nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if rolling_stock.has_previous %} {% if rolling_stock.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'index_pagination' page=rolling_stock.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'index_pagination' page=rolling_stock.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>

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>
@@ -47,7 +46,7 @@
{% block pagination %} {% block pagination %}
{% if scale.has_other_pages %} {% if scale.has_other_pages %}
<nav aria-label="Page navigation example"> <nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if scale.has_previous %} {% if scale.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'scale_pagination' page=scale.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'scale_pagination' page=scale.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>

View File

@@ -7,7 +7,7 @@
{% block pagination %} {% block pagination %}
{% if rolling_stock.has_other_pages %} {% if rolling_stock.has_other_pages %}
<nav aria-label="Page navigation example"> <nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-4"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if rolling_stock.has_previous %} {% if rolling_stock.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'filtered_pagination' _filter=filter search=search page=rolling_stock.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'filtered_pagination' _filter=filter search=search page=rolling_stock.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>

View File

@@ -0,0 +1,10 @@
from django import template
from portal.views import Flatpage
register = template.Library()
@register.inclusion_tag('flatpage_menu.html')
def show_menu():
menu = Flatpage.objects.all()
return {"menu": menu}

View File

@@ -3,6 +3,7 @@ from django.urls import path
from portal.views import ( from portal.views import (
GetHome, GetHome,
GetHomeFiltered, GetHomeFiltered,
GetFlatpage,
GetRollingStock, GetRollingStock,
GetConsist, GetConsist,
Consists, Consists,
@@ -13,6 +14,11 @@ from portal.views import (
urlpatterns = [ urlpatterns = [
path("", GetHome.as_view(), name="index"), path("", GetHome.as_view(), name="index"),
path("<int:page>", GetHome.as_view(), name="index_pagination"), path("<int:page>", GetHome.as_view(), name="index_pagination"),
path(
"page/<str:flatpage>",
GetFlatpage.as_view(),
name="flatpage",
),
path( path(
"search", "search",
GetHomeFiltered.as_view(http_method_names=["post"]), GetHomeFiltered.as_view(http_method_names=["post"]),
@@ -32,14 +38,10 @@ urlpatterns = [
path( path(
"companies/<int:page>", "companies/<int:page>",
Companies.as_view(), Companies.as_view(),
name="companies_pagination" name="companies_pagination",
), ),
path("scales", Scales.as_view(), name="scales"), path("scales", Scales.as_view(), name="scales"),
path( path("scales/<int:page>", Scales.as_view(), name="scales_pagination"),
"scales/<int:page>",
Scales.as_view(),
name="scales_pagination"
),
path( path(
"<str:_filter>/<str:search>", "<str:_filter>/<str:search>",
GetHomeFiltered.as_view(), GetHomeFiltered.as_view(),

View File

@@ -6,9 +6,10 @@ from django.http import Http404
from django.db.models import Q from django.db.models import Q
from django.shortcuts import render from django.shortcuts import render
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.paginator import Paginator, PageNotAnInteger
from portal.utils import get_site_conf from portal.utils import get_site_conf
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
from metadata.models import Company, Scale from metadata.models import Company, Scale
@@ -242,3 +243,19 @@ class Scales(View):
"scales.html", "scales.html",
{"scale": scale, "page_range": page_range}, {"scale": scale, "page_range": page_range},
) )
class GetFlatpage(View):
def get(self, request, flatpage):
try:
flatpage = Flatpage.objects.get(
Q(Q(path=flatpage) & Q(draft=False))
)
except ObjectDoesNotExist:
raise Http404
return render(
request,
"flatpage.html",
{"flatpage": flatpage},
)

View File

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

View File

@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/4.0/ref/settings/
""" """
import os import os
import time
from pathlib import Path from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -45,6 +46,8 @@ INSTALLED_APPS = [
"adminsortable2", "adminsortable2",
"django_countries", "django_countries",
"solo", "solo",
"ckeditor",
"ckeditor_uploader",
"rest_framework", "rest_framework",
"ram", "ram",
"portal", "portal",
@@ -139,6 +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/"
COUNTRIES_OVERRIDE = { COUNTRIES_OVERRIDE = {
"ZZ": "Freelance", "ZZ": "Freelance",

View File

@@ -21,6 +21,7 @@ from django.urls import include, path
urlpatterns = [ urlpatterns = [
path("", lambda r: redirect("portal/")), path("", lambda r: redirect("portal/")),
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