kopia lustrzana https://github.com/rtts/django-simplecms
Blackify everything
rodzic
cd8151b2ce
commit
98de86f49d
|
@ -1,2 +1,2 @@
|
||||||
__version__ = "1.0.5"
|
__version__ = "1.0.6"
|
||||||
default_app_config = "cms.apps.CmsConfig"
|
default_app_config = "cms.apps.CmsConfig"
|
||||||
|
|
|
@ -1,58 +1,85 @@
|
||||||
import os, re, argparse, shutil, example, cms
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
|
||||||
from pip._internal.operations import freeze as pip
|
from pip._internal.operations import freeze as pip
|
||||||
|
|
||||||
|
import cms
|
||||||
|
import example
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description='SimpleCMS')
|
parser = argparse.ArgumentParser(description="SimpleCMS")
|
||||||
parser.add_argument('project_name', nargs='?', default='.')
|
parser.add_argument("project_name", nargs="?", default=".")
|
||||||
project_name = parser.parse_args().project_name
|
project_name = parser.parse_args().project_name
|
||||||
if project_name == '.':
|
if project_name == ".":
|
||||||
project_dir = os.getcwd()
|
project_dir = os.getcwd()
|
||||||
project_name = os.path.basename(project_dir)
|
project_name = os.path.basename(project_dir)
|
||||||
else:
|
else:
|
||||||
project_dir = os.path.join(os.getcwd(), project_name)
|
project_dir = os.path.join(os.getcwd(), project_name)
|
||||||
if re.match(r'^\w+$', project_name):
|
if re.match(r"^\w+$", project_name):
|
||||||
if input(f'Do you want to create a new project in `{project_dir}` ?\033[1D') in 'Yy':
|
if (
|
||||||
|
input(f"Do you want to create a new project in `{project_dir}` ?\033[1D")
|
||||||
|
in "Yy"
|
||||||
|
):
|
||||||
create_project(project_name, project_dir)
|
create_project(project_name, project_dir)
|
||||||
else:
|
else:
|
||||||
print(f'Invalid project name: {project_name}')
|
print(f"Invalid project name: {project_name}")
|
||||||
|
|
||||||
|
|
||||||
def create_project(project_name, project_dir):
|
def create_project(project_name, project_dir):
|
||||||
os.makedirs(project_dir, exist_ok=True)
|
os.makedirs(project_dir, exist_ok=True)
|
||||||
with open(os.path.join(project_dir, 'requirements.txt'), 'w') as f:
|
with open(os.path.join(project_dir, "requirements.txt"), "w") as f:
|
||||||
for line in pip.freeze():
|
for line in pip.freeze():
|
||||||
if 'django_simplecms' in line:
|
if "django_simplecms" in line:
|
||||||
line = f'django-simplecms=={cms.__version__}'
|
line = f"django-simplecms=={cms.__version__}"
|
||||||
print(line, file=f)
|
print(line, file=f)
|
||||||
|
|
||||||
shutil.copytree(os.path.dirname(example.__file__),os.path.join(project_dir, project_name), dirs_exist_ok=True)
|
shutil.copytree(
|
||||||
with open(os.open(os.path.join(project_dir, 'manage.py'), os.O_CREAT|os.O_WRONLY, 0o755), 'w') as f:
|
os.path.dirname(example.__file__),
|
||||||
print('#!/usr/bin/env python',
|
os.path.join(project_dir, project_name),
|
||||||
'import os, sys',
|
dirs_exist_ok=True,
|
||||||
f"os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{project_name}.settings')",
|
)
|
||||||
'from django.core.management import execute_from_command_line',
|
with open(
|
||||||
'execute_from_command_line(sys.argv)',
|
os.open(
|
||||||
sep='\n', file=f)
|
os.path.join(project_dir, "manage.py"), os.O_CREAT | os.O_WRONLY, 0o755
|
||||||
with open(os.path.join(project_dir, project_name, 'wsgi.py'), 'w') as f:
|
),
|
||||||
print('import os',
|
"w",
|
||||||
'from django.core.wsgi import get_wsgi_application',
|
) as f:
|
||||||
f"os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{project_name}.settings')",
|
print(
|
||||||
'application = get_wsgi_application()',
|
"#!/usr/bin/env python",
|
||||||
sep='\n', file=f)
|
"import os, sys",
|
||||||
with open(os.path.join(project_dir, '.gitignore'), 'w') as f:
|
f"os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{project_name}.settings')",
|
||||||
print('*.pyc\n__pycache__/', file=f)
|
"from django.core.management import execute_from_command_line",
|
||||||
|
"execute_from_command_line(sys.argv)",
|
||||||
|
sep="\n",
|
||||||
|
file=f,
|
||||||
|
)
|
||||||
|
with open(os.path.join(project_dir, project_name, "wsgi.py"), "w") as f:
|
||||||
|
print(
|
||||||
|
"import os",
|
||||||
|
"from django.core.wsgi import get_wsgi_application",
|
||||||
|
f"os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{project_name}.settings')",
|
||||||
|
"application = get_wsgi_application()",
|
||||||
|
sep="\n",
|
||||||
|
file=f,
|
||||||
|
)
|
||||||
|
with open(os.path.join(project_dir, ".gitignore"), "w") as f:
|
||||||
|
print("*.pyc\n__pycache__/", file=f)
|
||||||
|
|
||||||
print(f'Successfully created project "{project_name}"',
|
print(
|
||||||
'',
|
f'Successfully created project "{project_name}"',
|
||||||
'Things to do next:',
|
"",
|
||||||
'- create a database',
|
"Things to do next:",
|
||||||
'- ./manage.py makemigrations',
|
"- create a database",
|
||||||
'- ./manage.py migrate',
|
"- ./manage.py makemigrations",
|
||||||
'- ./manage.py createsuperuser',
|
"- ./manage.py migrate",
|
||||||
'- ./manage.py runserver',
|
"- ./manage.py createsuperuser",
|
||||||
sep='\n')
|
"- ./manage.py runserver",
|
||||||
|
sep="\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django.utils.module_loading import autodiscover_modules
|
from django.utils.module_loading import autodiscover_modules
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class CmsConfig(AppConfig):
|
class CmsConfig(AppConfig):
|
||||||
name = 'cms'
|
name = "cms"
|
||||||
verbose_name = _('Content Management System')
|
verbose_name = _("Content Management System")
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
autodiscover_modules('views')
|
autodiscover_modules("views")
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
from cms import registry
|
from cms import registry
|
||||||
|
|
||||||
|
|
||||||
def page_model(cls):
|
def page_model(cls):
|
||||||
'''Decorator to register the Page model'''
|
"""Decorator to register the Page model"""
|
||||||
registry.page_class = cls
|
registry.page_class = cls
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
||||||
def section_model(cls):
|
def section_model(cls):
|
||||||
'''Decorator to register the Section model'''
|
"""Decorator to register the Section model"""
|
||||||
registry.section_class = cls
|
registry.section_class = cls
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
||||||
def section_view(cls):
|
def section_view(cls):
|
||||||
'''Decorator to register a view for a specific section'''
|
"""Decorator to register a view for a specific section"""
|
||||||
registry.view_per_type[cls.__name__.lower()] = cls
|
registry.view_per_type[cls.__name__.lower()] = cls
|
||||||
registry.section_types.append((cls.__name__.lower(), cls.verbose_name))
|
registry.section_types.append((cls.__name__.lower(), cls.verbose_name))
|
||||||
return cls
|
return cls
|
||||||
|
|
75
cms/forms.py
75
cms/forms.py
|
@ -1,27 +1,28 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Prefetch
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from . import registry
|
from . import registry
|
||||||
|
|
||||||
|
|
||||||
class PageForm(forms.ModelForm):
|
class PageForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.label_suffix = ''
|
self.label_suffix = ""
|
||||||
|
|
||||||
self.formsets = [forms.inlineformset_factory(
|
self.formsets = [
|
||||||
parent_model=registry.page_class,
|
forms.inlineformset_factory(
|
||||||
model=registry.section_class,
|
parent_model=registry.page_class,
|
||||||
form=SectionForm,
|
model=registry.section_class,
|
||||||
extra=1,
|
form=SectionForm,
|
||||||
)(
|
extra=1,
|
||||||
data=self.data if self.is_bound else None,
|
)(
|
||||||
files=self.files if self.is_bound else None,
|
data=self.data if self.is_bound else None,
|
||||||
instance=self.instance,
|
files=self.files if self.is_bound else None,
|
||||||
)]
|
instance=self.instance,
|
||||||
|
)
|
||||||
|
]
|
||||||
self.formsets[0][0].empty_permitted = True
|
self.formsets[0][0].empty_permitted = True
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
|
@ -44,17 +45,18 @@ class PageForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = registry.page_class
|
model = registry.page_class
|
||||||
fields = '__all__'
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class SectionForm(forms.ModelForm):
|
class SectionForm(forms.ModelForm):
|
||||||
type = forms.ChoiceField()
|
type = forms.ChoiceField()
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.label_suffix = ''
|
self.label_suffix = ""
|
||||||
self.fields['DELETE'] = forms.BooleanField(label=_('Delete'), required=False)
|
self.fields["DELETE"] = forms.BooleanField(label=_("Delete"), required=False)
|
||||||
self.fields['type'].choices = registry.get_types()
|
self.fields["type"].choices = registry.get_types()
|
||||||
self.fields['type'].initial = registry.get_types()[0][0]
|
self.fields["type"].initial = registry.get_types()[0][0]
|
||||||
|
|
||||||
# Populate the 'formsets' attribute if the Section was
|
# Populate the 'formsets' attribute if the Section was
|
||||||
# extendend with one_to_many fields
|
# extendend with one_to_many fields
|
||||||
|
@ -64,14 +66,14 @@ class SectionForm(forms.ModelForm):
|
||||||
formset = forms.inlineformset_factory(
|
formset = forms.inlineformset_factory(
|
||||||
parent_model=registry.section_class,
|
parent_model=registry.section_class,
|
||||||
model=field.related_model,
|
model=field.related_model,
|
||||||
fields='__all__',
|
fields="__all__",
|
||||||
extra=1,
|
extra=1,
|
||||||
)(
|
)(
|
||||||
instance=self.instance,
|
instance=self.instance,
|
||||||
data=self.data if self.is_bound else None,
|
data=self.data if self.is_bound else None,
|
||||||
files=self.files if self.is_bound else None,
|
files=self.files if self.is_bound else None,
|
||||||
prefix=f'{self.prefix}-{field.name}',
|
prefix=f"{self.prefix}-{field.name}",
|
||||||
form_kwargs={'label_suffix': self.label_suffix},
|
form_kwargs={"label_suffix": self.label_suffix},
|
||||||
)
|
)
|
||||||
formset.name = field.name
|
formset.name = field.name
|
||||||
self.formsets.append(formset)
|
self.formsets.append(formset)
|
||||||
|
@ -79,19 +81,19 @@ class SectionForm(forms.ModelForm):
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
result = super().is_valid()
|
result = super().is_valid()
|
||||||
for formset in self.formsets:
|
for formset in self.formsets:
|
||||||
result = result and formset.is_valid() # AND
|
result = result and formset.is_valid() # AND
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def has_changed(self):
|
def has_changed(self):
|
||||||
result = super().has_changed()
|
result = super().has_changed()
|
||||||
for formset in self.formsets:
|
for formset in self.formsets:
|
||||||
result = result or formset.has_changed() # OR
|
result = result or formset.has_changed() # OR
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
section = super().save(commit=commit)
|
section = super().save(commit=commit)
|
||||||
|
|
||||||
if self.cleaned_data['DELETE']:
|
if self.cleaned_data["DELETE"]:
|
||||||
section.delete()
|
section.delete()
|
||||||
if section.page.slug and not section.page.sections.exists():
|
if section.page.slug and not section.page.sections.exists():
|
||||||
section.page.delete()
|
section.page.delete()
|
||||||
|
@ -106,25 +108,28 @@ class SectionForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = registry.section_class
|
model = registry.section_class
|
||||||
exclude = ['page']
|
exclude = ["page"]
|
||||||
|
|
||||||
|
|
||||||
class ContactForm(forms.Form):
|
class ContactForm(forms.Form):
|
||||||
sender = forms.EmailField(label=_('Your email address'))
|
sender = forms.EmailField(label=_("Your email address"))
|
||||||
spam_protection = forms.CharField(label=_('Your message'), widget=forms.Textarea())
|
spam_protection = forms.CharField(label=_("Your message"), widget=forms.Textarea())
|
||||||
message = forms.CharField(label=_('Your message'), widget=forms.Textarea(), initial='Hi there!')
|
message = forms.CharField(
|
||||||
|
label=_("Your message"), widget=forms.Textarea(), initial="Hi there!"
|
||||||
|
)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
body = self.cleaned_data.get('spam_protection')
|
body = self.cleaned_data.get("spam_protection")
|
||||||
if len(body.split()) < 7:
|
if len(body.split()) < 7:
|
||||||
return
|
return
|
||||||
spamcheck = self.cleaned_data.get('message')
|
spamcheck = self.cleaned_data.get("message")
|
||||||
if spamcheck != 'Hi there!':
|
if spamcheck != "Hi there!":
|
||||||
return
|
return
|
||||||
|
|
||||||
email = EmailMessage(
|
email = EmailMessage(
|
||||||
to = settings.DEFAULT_TO_EMAIL,
|
to=settings.DEFAULT_TO_EMAIL,
|
||||||
body = body,
|
body=body,
|
||||||
subject = _('Contact form'),
|
subject=_("Contact form"),
|
||||||
headers = {'Reply-To': self.cleaned_data.get('sender')},
|
headers={"Reply-To": self.cleaned_data.get("sender")},
|
||||||
)
|
)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import os
|
import os
|
||||||
from sass import compile
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.middleware import cache
|
from django.middleware import cache
|
||||||
|
from sass import compile
|
||||||
|
|
||||||
|
|
||||||
def locate(filename):
|
def locate(filename):
|
||||||
for path, dirs, files in os.walk(os.getcwd(), followlinks=True):
|
for path, dirs, files in os.walk(os.getcwd(), followlinks=True):
|
||||||
|
@ -9,38 +11,44 @@ def locate(filename):
|
||||||
if f == filename:
|
if f == filename:
|
||||||
yield os.path.join(path, filename)
|
yield os.path.join(path, filename)
|
||||||
|
|
||||||
|
|
||||||
class FetchFromCacheMiddleware(cache.FetchFromCacheMiddleware):
|
class FetchFromCacheMiddleware(cache.FetchFromCacheMiddleware):
|
||||||
'''Minor change to the original middleware that prevents caching of
|
"""Minor change to the original middleware that prevents caching of
|
||||||
requests that have a `sessionid` cookie. This should be the
|
requests that have a `sessionid` cookie. This should be the
|
||||||
Django default, IMHO.
|
Django default, IMHO.
|
||||||
|
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
if 'sessionid' not in request.COOKIES:
|
if "sessionid" not in request.COOKIES:
|
||||||
return super().process_request(request)
|
return super().process_request(request)
|
||||||
|
|
||||||
|
|
||||||
class SassMiddleware:
|
class SassMiddleware:
|
||||||
'''Simple SASS middleware that intercepts requests for .css files and
|
"""Simple SASS middleware that intercepts requests for .css files and
|
||||||
tries to compile the corresponding SCSS file.
|
tries to compile the corresponding SCSS file.
|
||||||
|
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
if settings.DEBUG and request.path.endswith('.css'):
|
if settings.DEBUG and request.path.endswith(".css"):
|
||||||
css_file = request.path.rsplit('/',1)[1]
|
css_file = request.path.rsplit("/", 1)[1]
|
||||||
sass_file = css_file[:-4]
|
sass_file = css_file[:-4]
|
||||||
sass_paths = locate(sass_file)
|
sass_paths = locate(sass_file)
|
||||||
for sass_path in list(sass_paths):
|
for sass_path in list(sass_paths):
|
||||||
if os.path.exists(sass_path):
|
if os.path.exists(sass_path):
|
||||||
css_path = sass_path + '.css'
|
css_path = sass_path + ".css"
|
||||||
map_path = css_path + '.map'
|
map_path = css_path + ".map"
|
||||||
css = compile(filename=sass_path, output_style='nested')
|
css = compile(filename=sass_path, output_style="nested")
|
||||||
css, mapping = compile(filename=sass_path, source_map_filename=map_path)
|
css, mapping = compile(
|
||||||
with open(css_path, 'w') as f:
|
filename=sass_path, source_map_filename=map_path
|
||||||
|
)
|
||||||
|
with open(css_path, "w") as f:
|
||||||
f.write(css)
|
f.write(css)
|
||||||
with open(map_path, 'w') as f:
|
with open(map_path, "w") as f:
|
||||||
f.write(mapping)
|
f.write(mapping)
|
||||||
|
|
||||||
response = self.get_response(request)
|
response = self.get_response(request)
|
||||||
|
|
|
@ -10,6 +10,8 @@ from . import fields, mixins
|
||||||
class Model(models.Model):
|
class Model(models.Model):
|
||||||
"""Felt cute, might delete later."""
|
"""Felt cute, might delete later."""
|
||||||
|
|
||||||
|
id = models.BigAutoField(primary_key=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,17 @@ section_class = None
|
||||||
section_types = []
|
section_types = []
|
||||||
view_per_type = {}
|
view_per_type = {}
|
||||||
|
|
||||||
|
|
||||||
def get_types():
|
def get_types():
|
||||||
return section_types
|
return section_types
|
||||||
|
|
||||||
|
|
||||||
def get_view(section, request):
|
def get_view(section, request):
|
||||||
return view_per_type[section.type](request)
|
return view_per_type[section.type](request)
|
||||||
|
|
||||||
|
|
||||||
def get_fields_per_type():
|
def get_fields_per_type():
|
||||||
fields_per_type = {}
|
fields_per_type = {}
|
||||||
for name, view in view_per_type.items():
|
for name, view in view_per_type.items():
|
||||||
fields_per_type[name] = ['title', 'type', 'number'] + view.fields
|
fields_per_type[name] = ["title", "type", "number"] + view.fields
|
||||||
return fields_per_type
|
return fields_per_type
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
from markdown import markdown as md
|
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from markdown import markdown as md
|
||||||
|
|
||||||
from cms import registry
|
from cms import registry
|
||||||
|
|
||||||
MARKDOWN_EXTENSIONS = ['extra', 'smarty']
|
MARKDOWN_EXTENSIONS = ["extra", "smarty"]
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def eval(context, expr):
|
def eval(context, expr):
|
||||||
'''USE WITH CAUTION!!!
|
"""USE WITH CAUTION!!!
|
||||||
|
|
||||||
This template tag runs its argument through Django's templating
|
This template tag runs its argument through Django's templating
|
||||||
system using the current context, placing all power into the
|
system using the current context, placing all power into the
|
||||||
|
@ -20,49 +19,61 @@ def eval(context, expr):
|
||||||
|
|
||||||
Also, it applies Markdown.
|
Also, it applies Markdown.
|
||||||
|
|
||||||
'''
|
"""
|
||||||
result = template.Template(expr).render(context)
|
result = template.Template(expr).render(context)
|
||||||
return mark_safe(md(result, extensions=MARKDOWN_EXTENSIONS))
|
return mark_safe(md(result, extensions=MARKDOWN_EXTENSIONS))
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def editsection(context, inner):
|
def editsection(context, inner):
|
||||||
'''Renders a simple link to edit the current section'''
|
"""Renders a simple link to edit the current section"""
|
||||||
section = context['section']
|
section = context["section"]
|
||||||
user = context['request'].user
|
user = context["request"].user
|
||||||
app_label = section._meta.app_label
|
app_label = section._meta.app_label
|
||||||
model_name = section._meta.model_name
|
model_name = section._meta.model_name
|
||||||
if user.has_perm(f'{app_label}.change_{model_name}'):
|
if user.has_perm(f"{app_label}.change_{model_name}"):
|
||||||
slug = section.page.slug
|
slug = section.page.slug
|
||||||
number = section.number
|
number = section.number
|
||||||
url = reverse('cms:updatesection', args=[slug, number]) if slug else reverse('cms:updatesection', args=[number])
|
url = (
|
||||||
|
reverse("cms:updatesection", args=[slug, number])
|
||||||
|
if slug
|
||||||
|
else reverse("cms:updatesection", args=[number])
|
||||||
|
)
|
||||||
return mark_safe(f'<a class="edit section" href="{url}">{inner}</a>')
|
return mark_safe(f'<a class="edit section" href="{url}">{inner}</a>')
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag(takes_context=True)
|
||||||
def editpage(context, inner):
|
def editpage(context, inner):
|
||||||
'''Renders a simple link to edit the current page'''
|
"""Renders a simple link to edit the current page"""
|
||||||
page = context['page']
|
page = context["page"]
|
||||||
user = context['request'].user
|
user = context["request"].user
|
||||||
app_label = page._meta.app_label
|
app_label = page._meta.app_label
|
||||||
model_name = page._meta.model_name
|
model_name = page._meta.model_name
|
||||||
if user.has_perm(f'{app_label}.change_{model_name}'):
|
if user.has_perm(f"{app_label}.change_{model_name}"):
|
||||||
slug = page.slug
|
slug = page.slug
|
||||||
url = reverse('cms:updatepage', args=[slug]) if slug else reverse('cms:updatepage')
|
url = (
|
||||||
|
reverse("cms:updatepage", args=[slug])
|
||||||
|
if slug
|
||||||
|
else reverse("cms:updatepage")
|
||||||
|
)
|
||||||
return mark_safe(f'<a class="edit page" href="{url}">{inner}</a>')
|
return mark_safe(f'<a class="edit page" href="{url}">{inner}</a>')
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
@register.tag('include_section')
|
|
||||||
|
@register.tag("include_section")
|
||||||
def do_include(parser, token):
|
def do_include(parser, token):
|
||||||
'''Renders the section with its own context'''
|
"""Renders the section with its own context"""
|
||||||
_, section = token.split_contents()
|
_, section = token.split_contents()
|
||||||
return IncludeSectionNode(section)
|
return IncludeSectionNode(section)
|
||||||
|
|
||||||
|
|
||||||
class IncludeSectionNode(template.Node):
|
class IncludeSectionNode(template.Node):
|
||||||
def __init__(self, section):
|
def __init__(self, section):
|
||||||
self.section = template.Variable(section)
|
self.section = template.Variable(section)
|
||||||
self.csrf_token = template.Variable('csrf_token')
|
self.csrf_token = template.Variable("csrf_token")
|
||||||
self.request = template.Variable('request')
|
self.request = template.Variable("request")
|
||||||
self.perms = template.Variable('perms')
|
self.perms = template.Variable("perms")
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
|
@ -73,13 +84,13 @@ class IncludeSectionNode(template.Node):
|
||||||
|
|
||||||
view = registry.get_view(section, request)
|
view = registry.get_view(section, request)
|
||||||
initial_context = {
|
initial_context = {
|
||||||
'csrf_token': csrf_token,
|
"csrf_token": csrf_token,
|
||||||
'section': section,
|
"section": section,
|
||||||
'request': request,
|
"request": request,
|
||||||
'perms': perms,
|
"perms": perms,
|
||||||
}
|
}
|
||||||
if hasattr(section, 'invalid_form'):
|
if hasattr(section, "invalid_form"):
|
||||||
initial_context['form'] = section.invalid_form
|
initial_context["form"] = section.invalid_form
|
||||||
|
|
||||||
section_context = view.get_context_data(**initial_context)
|
section_context = view.get_context_data(**initial_context)
|
||||||
t = context.template.engine.get_template(view.template_name)
|
t = context.template.engine.get_template(view.template_name)
|
||||||
|
|
28
cms/urls.py
28
cms/urls.py
|
@ -1,15 +1,23 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .views import PageView, CreatePage, UpdatePage, CreateSection, UpdateSection
|
|
||||||
|
|
||||||
app_name = 'cms'
|
from .views import CreatePage, CreateSection, PageView, UpdatePage, UpdateSection
|
||||||
|
|
||||||
|
app_name = "cms"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('new/', CreatePage.as_view(), name='createpage'),
|
path("new/", CreatePage.as_view(), name="createpage"),
|
||||||
path('edit/', UpdatePage.as_view(), kwargs={'slug': ''}, name='updatepage'),
|
path("edit/", UpdatePage.as_view(), kwargs={"slug": ""}, name="updatepage"),
|
||||||
path('edit/<int:number>/', UpdateSection.as_view(), kwargs={'slug': ''}, name='updatesection'),
|
path(
|
||||||
path('<slug:slug>/edit/', UpdatePage.as_view(), name='updatepage'),
|
"edit/<int:number>/",
|
||||||
path('<slug:slug>/edit/new/', CreateSection.as_view(), name='createsection'),
|
UpdateSection.as_view(),
|
||||||
path('<slug:slug>/edit/<int:number>/', UpdateSection.as_view(), name='updatesection'),
|
kwargs={"slug": ""},
|
||||||
path('', PageView.as_view(), name='page'),
|
name="updatesection",
|
||||||
path('<slug:slug>/', PageView.as_view(), name='page'),
|
),
|
||||||
|
path("<slug:slug>/edit/", UpdatePage.as_view(), name="updatepage"),
|
||||||
|
path("<slug:slug>/edit/new/", CreateSection.as_view(), name="createsection"),
|
||||||
|
path(
|
||||||
|
"<slug:slug>/edit/<int:number>/", UpdateSection.as_view(), name="updatesection"
|
||||||
|
),
|
||||||
|
path("", PageView.as_view(), name="page"),
|
||||||
|
path("<slug:slug>/", PageView.as_view(), name="page"),
|
||||||
]
|
]
|
||||||
|
|
168
cms/views.py
168
cms/views.py
|
@ -1,18 +1,20 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
|
from django.http import Http404, HttpResponseBadRequest, HttpResponseRedirect
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.views.generic import base, detail, edit
|
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.views.generic import base, detail, edit
|
||||||
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
|
|
||||||
|
|
||||||
from . import registry
|
from . import registry
|
||||||
from .forms import PageForm, SectionForm
|
from .forms import PageForm, SectionForm
|
||||||
|
|
||||||
|
|
||||||
class SectionView:
|
class SectionView:
|
||||||
'''Generic section view'''
|
"""Generic section view"""
|
||||||
template_name = 'cms/sections/section.html'
|
|
||||||
|
template_name = "cms/sections/section.html"
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
self.request = request
|
self.request = request
|
||||||
|
@ -20,14 +22,16 @@ class SectionView:
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class SectionFormView(SectionView):
|
class SectionFormView(SectionView):
|
||||||
'''Generic section with associated form'''
|
"""Generic section with associated form"""
|
||||||
|
|
||||||
form_class = None
|
form_class = None
|
||||||
success_url = None
|
success_url = None
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
if 'form' not in kwargs:
|
if "form" not in kwargs:
|
||||||
kwargs['form'] = self.get_form()
|
kwargs["form"] = self.get_form()
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
@ -37,56 +41,62 @@ class SectionFormView(SectionView):
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_form(self, method='get'):
|
def get_form(self, method="get"):
|
||||||
form_class = self.form_class
|
form_class = self.form_class
|
||||||
kwargs = self.get_form_kwargs()
|
kwargs = self.get_form_kwargs()
|
||||||
if method == 'post':
|
if method == "post":
|
||||||
kwargs.update({
|
kwargs.update(
|
||||||
'data': self.request.POST,
|
{
|
||||||
'files': self.request.FILES,
|
"data": self.request.POST,
|
||||||
})
|
"files": self.request.FILES,
|
||||||
|
}
|
||||||
|
)
|
||||||
return form_class(**kwargs)
|
return form_class(**kwargs)
|
||||||
|
|
||||||
class PageView(detail.DetailView):
|
|
||||||
'''View of a page with heterogeneous sections'''
|
|
||||||
model = registry.page_class
|
|
||||||
template_name = 'cms/page.html'
|
|
||||||
|
|
||||||
def setup(self, *args, slug='', **kwargs):
|
class PageView(detail.DetailView):
|
||||||
'''Supply a default argument for slug'''
|
"""View of a page with heterogeneous sections"""
|
||||||
|
|
||||||
|
model = registry.page_class
|
||||||
|
template_name = "cms/page.html"
|
||||||
|
|
||||||
|
def setup(self, *args, slug="", **kwargs):
|
||||||
|
"""Supply a default argument for slug"""
|
||||||
super().setup(*args, slug=slug, **kwargs)
|
super().setup(*args, slug=slug, **kwargs)
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
'''Instantiate section views and render final response'''
|
"""Instantiate section views and render final response"""
|
||||||
try:
|
try:
|
||||||
page = self.object = self.get_object()
|
page = self.object = self.get_object()
|
||||||
except Http404:
|
except Http404:
|
||||||
app_label = registry.page_class._meta.app_label
|
app_label = registry.page_class._meta.app_label
|
||||||
model_name = registry.page_class._meta.model_name
|
model_name = registry.page_class._meta.model_name
|
||||||
if self.kwargs['slug'] == '':
|
if self.kwargs["slug"] == "":
|
||||||
page = registry.page_class(title='Homepage', slug='')
|
page = registry.page_class(title="Homepage", slug="")
|
||||||
page.save()
|
page.save()
|
||||||
self.object = page
|
self.object = page
|
||||||
|
|
||||||
# Special case: Don't serve 404 pages to authorized users,
|
# Special case: Don't serve 404 pages to authorized users,
|
||||||
# but redirect to the edit page form with the slug pre-filled
|
# but redirect to the edit page form with the slug pre-filled
|
||||||
elif (self.request.user.has_perm(f'{app_label}.change_{model_name}')):
|
elif self.request.user.has_perm(f"{app_label}.change_{model_name}"):
|
||||||
return redirect('cms:updatepage', slug=self.kwargs['slug'])
|
return redirect("cms:updatepage", slug=self.kwargs["slug"])
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
context = self.get_context_data(**kwargs)
|
context = self.get_context_data(**kwargs)
|
||||||
sections = page.sections.all()
|
sections = page.sections.all()
|
||||||
context.update({
|
context.update(
|
||||||
'page': page,
|
{
|
||||||
'sections': sections,
|
"page": page,
|
||||||
})
|
"sections": sections,
|
||||||
|
}
|
||||||
|
)
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
||||||
def post(self, request, **kwargs):
|
def post(self, request, **kwargs):
|
||||||
'''Call the post() method of the correct section view'''
|
"""Call the post() method of the correct section view"""
|
||||||
try:
|
try:
|
||||||
pk = int(self.request.POST.get('section'))
|
pk = int(self.request.POST.get("section"))
|
||||||
except:
|
except Exception:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
page = self.object = self.get_object()
|
page = self.object = self.get_object()
|
||||||
|
@ -95,65 +105,73 @@ class PageView(detail.DetailView):
|
||||||
for section in sections:
|
for section in sections:
|
||||||
if section.pk == pk:
|
if section.pk == pk:
|
||||||
view = registry.get_view(section, request)
|
view = registry.get_view(section, request)
|
||||||
form = view.get_form(method='post')
|
form = view.get_form(method="post")
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
return view.form_valid(form)
|
return view.form_valid(form)
|
||||||
section.invalid_form = form
|
section.invalid_form = form
|
||||||
|
|
||||||
context.update({
|
context.update(
|
||||||
'page': page,
|
{
|
||||||
'sections': sections,
|
"page": page,
|
||||||
})
|
"sections": sections,
|
||||||
|
}
|
||||||
|
)
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
pages = registry.page_class.objects.filter(menu=True)
|
pages = registry.page_class.objects.filter(menu=True)
|
||||||
context.update({
|
context.update(
|
||||||
'pages': pages,
|
{
|
||||||
})
|
"pages": pages,
|
||||||
|
}
|
||||||
|
)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@method_decorator(never_cache, name='dispatch')
|
|
||||||
class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View):
|
@method_decorator(never_cache, name="dispatch")
|
||||||
'''Base view with nested forms for editing the page and all its sections'''
|
class EditPage(
|
||||||
|
UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View
|
||||||
|
):
|
||||||
|
"""Base view with nested forms for editing the page and all its sections"""
|
||||||
|
|
||||||
model = registry.page_class
|
model = registry.page_class
|
||||||
form_class = PageForm
|
form_class = PageForm
|
||||||
template_name = 'cms/edit.html'
|
template_name = "cms/edit.html"
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
'''Only allow users with the correct permissions'''
|
"""Only allow users with the correct permissions"""
|
||||||
app_label = registry.page_class._meta.app_label
|
app_label = registry.page_class._meta.app_label
|
||||||
model_name = registry.page_class._meta.model_name
|
model_name = registry.page_class._meta.model_name
|
||||||
return self.request.user.has_perm(f'{app_label}.change_{model_name}')
|
return self.request.user.has_perm(f"{app_label}.change_{model_name}")
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
'''Set the default slug to the current URL for new pages'''
|
"""Set the default slug to the current URL for new pages"""
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
if 'slug' in self.kwargs:
|
if "slug" in self.kwargs:
|
||||||
kwargs.update({'initial': {'slug': self.kwargs['slug']}})
|
kwargs.update({"initial": {"slug": self.kwargs["slug"]}})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
'''Populate the fields_per_type dict for use in javascript'''
|
"""Populate the fields_per_type dict for use in javascript"""
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['fields_per_type'] = json.dumps(registry.get_fields_per_type())
|
context["fields_per_type"] = json.dumps(registry.get_fields_per_type())
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
'''Prevent 404 by serving the new object form'''
|
"""Prevent 404 by serving the new object form"""
|
||||||
try:
|
try:
|
||||||
return super().get_object()
|
return super().get_object()
|
||||||
except Http404:
|
except Http404:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
'''Handle GET requests'''
|
"""Handle GET requests"""
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
return self.render_to_response(self.get_context_data(**kwargs))
|
return self.render_to_response(self.get_context_data(**kwargs))
|
||||||
|
|
||||||
def post(self, *args, **kwargs):
|
def post(self, *args, **kwargs):
|
||||||
'''Handle POST requests'''
|
"""Handle POST requests"""
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
|
|
||||||
|
@ -161,51 +179,59 @@ class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMi
|
||||||
page = form.save()
|
page = form.save()
|
||||||
if page:
|
if page:
|
||||||
return HttpResponseRedirect(page.get_absolute_url())
|
return HttpResponseRedirect(page.get_absolute_url())
|
||||||
return HttpResponseRedirect('/')
|
return HttpResponseRedirect("/")
|
||||||
return self.render_to_response(self.get_context_data(form=form, **kwargs))
|
return self.render_to_response(self.get_context_data(form=form, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
class CreatePage(EditPage):
|
class CreatePage(EditPage):
|
||||||
'''View for creating new pages'''
|
"""View for creating new pages"""
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
return registry.page_class()
|
return registry.page_class()
|
||||||
|
|
||||||
class UpdatePage(EditPage):
|
|
||||||
'''View for editing existing pages'''
|
|
||||||
|
|
||||||
@method_decorator(never_cache, name='dispatch')
|
class UpdatePage(EditPage):
|
||||||
class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View):
|
"""View for editing existing pages"""
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(never_cache, name="dispatch")
|
||||||
|
class EditSection(
|
||||||
|
UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View
|
||||||
|
):
|
||||||
model = registry.section_class
|
model = registry.section_class
|
||||||
form_class = SectionForm
|
form_class = SectionForm
|
||||||
template_name = 'cms/edit.html'
|
template_name = "cms/edit.html"
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
'''Only allow users with the correct permissions'''
|
"""Only allow users with the correct permissions"""
|
||||||
app_label = registry.section_class._meta.app_label
|
app_label = registry.section_class._meta.app_label
|
||||||
model_name = registry.section_class._meta.model_name
|
model_name = registry.section_class._meta.model_name
|
||||||
return self.request.user.has_perm(f'{app_label}.change_{model_name}')
|
return self.request.user.has_perm(f"{app_label}.change_{model_name}")
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super().get_form_kwargs()
|
kwargs = super().get_form_kwargs()
|
||||||
kwargs.update({
|
kwargs.update(
|
||||||
'prefix': 'section',
|
{
|
||||||
})
|
"prefix": "section",
|
||||||
|
}
|
||||||
|
)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['fields_per_type'] = json.dumps(registry.get_fields_per_type())
|
context["fields_per_type"] = json.dumps(registry.get_fields_per_type())
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
try:
|
try:
|
||||||
self.page = registry.page_class.objects.get(slug=self.kwargs['slug'])
|
self.page = registry.page_class.objects.get(slug=self.kwargs["slug"])
|
||||||
except registry.page_class.DoesNotExist:
|
except registry.page_class.DoesNotExist:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
return self.get_section()
|
return self.get_section()
|
||||||
|
|
||||||
def get_section(self):
|
def get_section(self):
|
||||||
try:
|
try:
|
||||||
section = self.page.sections.get(number=self.kwargs['number'])
|
section = self.page.sections.get(number=self.kwargs["number"])
|
||||||
except self.page.sections.DoesNotExist:
|
except self.page.sections.DoesNotExist:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
return section
|
return section
|
||||||
|
@ -225,12 +251,14 @@ class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateRespons
|
||||||
elif self.page.sections.exists():
|
elif self.page.sections.exists():
|
||||||
return HttpResponseRedirect(self.page.get_absolute_url())
|
return HttpResponseRedirect(self.page.get_absolute_url())
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect('/')
|
return HttpResponseRedirect("/")
|
||||||
return self.render_to_response(self.get_context_data(form=form, **kwargs))
|
return self.render_to_response(self.get_context_data(form=form, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
class CreateSection(EditSection):
|
class CreateSection(EditSection):
|
||||||
def get_section(self):
|
def get_section(self):
|
||||||
return registry.section_class(page=self.page)
|
return registry.section_class(page=self.page)
|
||||||
|
|
||||||
|
|
||||||
class UpdateSection(EditSection):
|
class UpdateSection(EditSection):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,26 +1,33 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from cms.models import BasePage, BaseSection
|
|
||||||
from cms.decorators import page_model, section_model
|
from cms.decorators import page_model, section_model
|
||||||
|
from cms.models import BasePage, BaseSection
|
||||||
|
|
||||||
|
|
||||||
@page_model
|
@page_model
|
||||||
class Page(BasePage):
|
class Page(BasePage):
|
||||||
'''Add custom fields here. Already existing fields: title, slug,
|
"""Add custom fields here. Already existing fields: title, slug,
|
||||||
number, menu
|
number, menu
|
||||||
|
|
||||||
'''
|
"""
|
||||||
|
|
||||||
|
|
||||||
@section_model
|
@section_model
|
||||||
class Section(BaseSection):
|
class Section(BaseSection):
|
||||||
'''Add custom fields here. Already existing fields: title, type,
|
"""Add custom fields here. Already existing fields: title, type,
|
||||||
number, content, image, video, href
|
number, content, image, video, href
|
||||||
|
|
||||||
'''
|
"""
|
||||||
page = models.ForeignKey(Page, related_name='sections', on_delete=models.PROTECT)
|
|
||||||
|
page = models.ForeignKey(Page, related_name="sections", on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
|
||||||
class SectionImage(models.Model):
|
class SectionImage(models.Model):
|
||||||
section = models.ForeignKey(Section, related_name='images', on_delete=models.CASCADE)
|
section = models.ForeignKey(
|
||||||
image = models.ImageField(_('Image'))
|
Section, related_name="images", on_delete=models.CASCADE
|
||||||
|
)
|
||||||
|
image = models.ImageField(_("Image"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['pk']
|
ordering = ["pk"]
|
||||||
|
|
|
@ -5,95 +5,95 @@ import sys
|
||||||
|
|
||||||
PROJECT_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
PROJECT_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
DEBUG = 'runserver' in sys.argv
|
DEBUG = "runserver" in sys.argv
|
||||||
KEYFILE = f'/tmp/{PROJECT_NAME}.secret'
|
KEYFILE = f"/tmp/{PROJECT_NAME}.secret"
|
||||||
ADMINS = [('JJ Vens', 'jj@rtts.eu')]
|
ADMINS = [("JJ Vens", "jj@rtts.eu")]
|
||||||
DEFAULT_FROM_EMAIL = 'noreply@rtts.eu'
|
DEFAULT_FROM_EMAIL = "noreply@rtts.eu"
|
||||||
DEFAULT_TO_EMAIL = ['jj@rtts.eu']
|
DEFAULT_TO_EMAIL = ["jj@rtts.eu"]
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ["*"]
|
||||||
ROOT_URLCONF = PROJECT_NAME + '.urls'
|
ROOT_URLCONF = PROJECT_NAME + ".urls"
|
||||||
WSGI_APPLICATION = PROJECT_NAME + '.wsgi.application'
|
WSGI_APPLICATION = PROJECT_NAME + ".wsgi.application"
|
||||||
LANGUAGE_CODE = 'nl'
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
TIME_ZONE = 'Europe/Amsterdam'
|
LANGUAGE_CODE = "nl"
|
||||||
|
TIME_ZONE = "Europe/Amsterdam"
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
STATIC_ROOT = '/srv/' + PROJECT_NAME + '/static'
|
STATIC_ROOT = "/srv/" + PROJECT_NAME + "/static"
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = "/media/"
|
||||||
MEDIA_ROOT = '/srv/' + PROJECT_NAME + '/media'
|
MEDIA_ROOT = "/srv/" + PROJECT_NAME + "/media"
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = "/"
|
||||||
LOGOUT_REDIRECT_URL = '/'
|
LOGOUT_REDIRECT_URL = "/"
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
CACHE_MIDDLEWARE_SECONDS = 0
|
CACHE_MIDDLEWARE_SECONDS = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(KEYFILE) as f:
|
with open(KEYFILE) as f:
|
||||||
SECRET_KEY = f.read()
|
SECRET_KEY = f.read()
|
||||||
except IOError:
|
except IOError:
|
||||||
SECRET_KEY = ''.join(random.choice(string.printable) for x in range(50))
|
SECRET_KEY = "".join(random.choice(string.printable) for x in range(50))
|
||||||
with open(KEYFILE, 'w') as f:
|
with open(KEYFILE, "w") as f:
|
||||||
f.write(SECRET_KEY)
|
f.write(SECRET_KEY)
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
PROJECT_NAME,
|
PROJECT_NAME,
|
||||||
'django.contrib.admin',
|
"django.contrib.admin",
|
||||||
'django.contrib.auth',
|
"django.contrib.auth",
|
||||||
'django.contrib.contenttypes',
|
"django.contrib.contenttypes",
|
||||||
'django.contrib.sessions',
|
"django.contrib.sessions",
|
||||||
'django.contrib.messages',
|
"django.contrib.messages",
|
||||||
'cms',
|
"cms",
|
||||||
'embed_video',
|
"embed_video",
|
||||||
'easy_thumbnails',
|
"easy_thumbnails",
|
||||||
'django_extensions',
|
"django_extensions",
|
||||||
]
|
]
|
||||||
if not DEBUG:
|
if not DEBUG:
|
||||||
INSTALLED_APPS += ['django.contrib.staticfiles']
|
INSTALLED_APPS += ["django.contrib.staticfiles"]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.cache.UpdateCacheMiddleware',
|
"django.middleware.cache.UpdateCacheMiddleware",
|
||||||
'cms.middleware.SassMiddleware',
|
"cms.middleware.SassMiddleware",
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'django.middleware.common.CommonMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
'tidy.middleware.TidyMiddleware',
|
"tidy.middleware.TidyMiddleware",
|
||||||
'cms.middleware.FetchFromCacheMiddleware',
|
"cms.middleware.FetchFromCacheMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
'DIRS': [],
|
"DIRS": [],
|
||||||
'APP_DIRS': True,
|
"APP_DIRS": True,
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.contrib.auth.context_processors.auth',
|
"django.contrib.auth.context_processors.auth",
|
||||||
'django.contrib.messages.context_processors.messages',
|
"django.contrib.messages.context_processors.messages",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
"default": {
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
'USER': PROJECT_NAME,
|
"USER": PROJECT_NAME,
|
||||||
'NAME': PROJECT_NAME,
|
"NAME": PROJECT_NAME,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CACHES = {
|
CACHES = {
|
||||||
'default': {
|
"default": {
|
||||||
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
|
"BACKEND": "django.core.cache.backends.memcached.PyLibMCCache",
|
||||||
'LOCATION': '127.0.0.1:11211',
|
"LOCATION": "127.0.0.1:11211",
|
||||||
'KEY_PREFIX': PROJECT_NAME,
|
"KEY_PREFIX": PROJECT_NAME,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
|
||||||
from django.urls import path, include
|
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.views.generic import RedirectView
|
from django.contrib import admin
|
||||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
|
from django.urls import include, path
|
||||||
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
admin.site.site_header = admin.site.site_title = settings.PROJECT_NAME.replace('_', ' ').title()
|
admin.site.site_header = admin.site.site_title = settings.PROJECT_NAME.replace(
|
||||||
urlpatterns = staticfiles_urlpatterns() + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
"_", " "
|
||||||
|
).title()
|
||||||
|
urlpatterns = staticfiles_urlpatterns() + static(
|
||||||
|
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
|
||||||
|
)
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
path('admin/', admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path('accounts/', include('django.contrib.auth.urls')),
|
path("accounts/", include("django.contrib.auth.urls")),
|
||||||
path('login/', RedirectView.as_view(url='/accounts/login/')),
|
path("login/", RedirectView.as_view(url="/accounts/login/")),
|
||||||
path('logout/', RedirectView.as_view(url='/accounts/logout/')),
|
path("logout/", RedirectView.as_view(url="/accounts/logout/")),
|
||||||
path('', include('cms.urls', namespace='cms')),
|
path("", include("cms.urls", namespace="cms")),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,30 +1,35 @@
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from cms.views import SectionView, SectionFormView
|
|
||||||
from cms.decorators import section_view
|
from cms.decorators import section_view
|
||||||
from cms.forms import ContactForm
|
from cms.forms import ContactForm
|
||||||
|
from cms.views import SectionFormView, SectionView
|
||||||
|
|
||||||
|
|
||||||
@section_view
|
@section_view
|
||||||
class Text(SectionView):
|
class Text(SectionView):
|
||||||
verbose_name = _('Text')
|
verbose_name = _("Text")
|
||||||
fields = ['content']
|
fields = ["content"]
|
||||||
template_name = 'text.html'
|
template_name = "text.html"
|
||||||
|
|
||||||
|
|
||||||
@section_view
|
@section_view
|
||||||
class Images(SectionView):
|
class Images(SectionView):
|
||||||
verbose_name = _('Image(s)')
|
verbose_name = _("Image(s)")
|
||||||
fields = ['images']
|
fields = ["images"]
|
||||||
template_name = 'images.html'
|
template_name = "images.html"
|
||||||
|
|
||||||
|
|
||||||
@section_view
|
@section_view
|
||||||
class Video(SectionView):
|
class Video(SectionView):
|
||||||
verbose_name = _('Video')
|
verbose_name = _("Video")
|
||||||
fields = ['video']
|
fields = ["video"]
|
||||||
template_name = 'video.html'
|
template_name = "video.html"
|
||||||
|
|
||||||
|
|
||||||
@section_view
|
@section_view
|
||||||
class Contact(SectionFormView):
|
class Contact(SectionFormView):
|
||||||
verbose_name = _('Contact')
|
verbose_name = _("Contact")
|
||||||
fields = []
|
fields = []
|
||||||
form_class = ContactForm
|
form_class = ContactForm
|
||||||
success_url = '/thanks/'
|
success_url = "/thanks/"
|
||||||
template_name = 'contact.html'
|
template_name = "contact.html"
|
||||||
|
|
|
@ -11,6 +11,6 @@ import os
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
|
||||||
try:
|
try:
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
[tool.isort]
|
||||||
|
line_length = 88
|
61
setup.py
61
setup.py
|
@ -1,39 +1,40 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
import cms
|
from setuptools import find_packages, setup
|
||||||
from setuptools import setup, find_packages
|
|
||||||
|
|
||||||
with open('README.md', 'r') as fh:
|
import cms
|
||||||
|
|
||||||
|
with open("README.md", "r") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'django-simplecms',
|
name="django-simplecms",
|
||||||
description = 'Simple Django CMS',
|
description="Simple Django CMS",
|
||||||
version = cms.__version__,
|
version=cms.__version__,
|
||||||
author = 'Jaap Joris Vens',
|
author="Jaap Joris Vens",
|
||||||
author_email = 'jj+cms@rtts.eu',
|
author_email="jj+cms@rtts.eu",
|
||||||
url = 'https://github.com/rtts/django-simplecms',
|
url="https://github.com/rtts/django-simplecms",
|
||||||
long_description = long_description,
|
long_description=long_description,
|
||||||
long_description_content_type = 'text/markdown',
|
long_description_content_type="text/markdown",
|
||||||
packages = find_packages(),
|
packages=find_packages(),
|
||||||
entry_points = {
|
entry_points={
|
||||||
'console_scripts': ['simplecms=cms.__main__:main'],
|
"console_scripts": ["simplecms=cms.__main__:main"],
|
||||||
},
|
},
|
||||||
include_package_data = True,
|
include_package_data=True,
|
||||||
classifiers = [
|
classifiers=[
|
||||||
'Programming Language :: Python :: 3',
|
"Programming Language :: Python :: 3",
|
||||||
'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
|
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
|
||||||
'Operating System :: OS Independent',
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
python_requires = '>=3.8',
|
python_requires=">=3.8",
|
||||||
install_requires = [
|
install_requires=[
|
||||||
'django',
|
"django",
|
||||||
'django-extensions',
|
"django-extensions",
|
||||||
'django-embed-video',
|
"django-embed-video",
|
||||||
'django-tidy',
|
"django-tidy",
|
||||||
'easy-thumbnails',
|
"easy-thumbnails",
|
||||||
'libsass',
|
"libsass",
|
||||||
'markdown',
|
"markdown",
|
||||||
'psycopg2',
|
"psycopg2",
|
||||||
'pylibmc',
|
"pylibmc",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
Ładowanie…
Reference in New Issue