├── .coveragerc ├── .gitignore ├── .travis.yml ├── CHANGELOG.rst ├── CONTRIBUTING.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── docs └── screenshots │ ├── index1.png │ └── node1.png ├── manage.py ├── ninecms ├── __init__.py ├── admin.py ├── apps.py ├── checks.py ├── forms.py ├── locale │ └── el │ │ └── LC_MESSAGES │ │ └── django.po ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ ├── cache_clear.py │ │ └── check_updates.py ├── migrations │ ├── 0001_squashed_0024_auto_20150416_1551.py │ ├── 0002_auto_20150519_1102.py │ ├── 0003_auto_20150623_1731.py │ ├── 0004_auto_20150624_1131.py │ ├── 0005_auto_20150624_1841.py │ ├── 0006_auto_20150701_1401.py │ ├── 0007_auto_20150727_1833.py │ ├── 0008_auto_20150819_1516.py │ ├── 0009_auto_20150924_1456.py │ ├── 0010_auto_20150924_1850.py │ ├── 0011_auto_20151202_1400.py │ ├── 0012_auto_20151218_1637.py │ ├── 0013_auto_20160117_1209.py │ └── __init__.py ├── models.py ├── settings.py ├── signals.py ├── static │ └── ninecms │ │ ├── admin.js │ │ ├── ckeditor │ │ └── build-config.js │ │ ├── images │ │ ├── favicon.ico │ │ ├── flags │ │ │ ├── af.png │ │ │ ├── ar.png │ │ │ ├── be.png │ │ │ ├── bg.png │ │ │ ├── bo.png │ │ │ ├── ca.png │ │ │ ├── cs.png │ │ │ ├── da.png │ │ │ ├── de.png │ │ │ ├── el.png │ │ │ ├── en.png │ │ │ ├── eo.png │ │ │ ├── es.png │ │ │ ├── et.png │ │ │ ├── eu.png │ │ │ ├── fa.png │ │ │ ├── fi.png │ │ │ ├── fil.png │ │ │ ├── fo.png │ │ │ ├── fr.png │ │ │ ├── ga.png │ │ │ ├── gl.png │ │ │ ├── he.png │ │ │ ├── hi.png │ │ │ ├── hr.png │ │ │ ├── hu.png │ │ │ ├── id.png │ │ │ ├── is.png │ │ │ ├── it.png │ │ │ ├── ja.png │ │ │ ├── km.png │ │ │ ├── ko.png │ │ │ ├── lb.png │ │ │ ├── lt.png │ │ │ ├── lv.png │ │ │ ├── mn.png │ │ │ ├── ms.png │ │ │ ├── nb.png │ │ │ ├── nl.png │ │ │ ├── nn.png │ │ │ ├── pl.png │ │ │ ├── pt-br.png │ │ │ ├── pt-pt.png │ │ │ ├── ro.png │ │ │ ├── ru.png │ │ │ ├── sco.png │ │ │ ├── se.png │ │ │ ├── sk.png │ │ │ ├── sl.png │ │ │ ├── so.png │ │ │ ├── sq.png │ │ │ ├── sr.png │ │ │ ├── sv.png │ │ │ ├── tg.png │ │ │ ├── th.png │ │ │ ├── tl.png │ │ │ ├── tr.png │ │ │ ├── uk.png │ │ │ ├── vi.png │ │ │ ├── zh-hans.png │ │ │ └── zh-hant.png │ │ └── toplink.png │ │ ├── layout.js │ │ ├── masonry.js │ │ └── style.css ├── templates │ ├── admin │ │ └── ninecms │ │ │ ├── image │ │ │ └── stacked.html │ │ │ ├── index.html │ │ │ ├── node │ │ │ ├── change_form.html │ │ │ └── change_list.html │ │ │ └── pagetype │ │ │ ├── change_form.html │ │ │ └── perms_form.html │ └── ninecms │ │ ├── base.html │ │ ├── block_contact.html │ │ ├── block_content.html │ │ ├── block_language.html │ │ ├── block_login.html │ │ ├── block_menu.html │ │ ├── block_menu_breadcrumbs.html │ │ ├── block_menu_header.html │ │ ├── block_search.html │ │ ├── block_search_results.html │ │ ├── block_signal.html │ │ ├── block_signal_terms.html │ │ ├── block_static.html │ │ ├── block_user_menu.html │ │ ├── ckeditor.html │ │ ├── field.html │ │ ├── fieldset.html │ │ ├── form_confirm.html │ │ ├── form_logout.html │ │ ├── form_non_field_errors.html │ │ ├── glyphicon.html │ │ ├── index.html │ │ ├── mail_contact.txt │ │ ├── mail_updates.txt │ │ ├── messages.html │ │ ├── pagination.html │ │ └── robots.txt ├── templatetags │ ├── __init__.py │ └── ninecms_extras.py ├── tests │ ├── __init__.py │ ├── setup.py │ ├── tests_content.py │ ├── tests_content_i18n.py │ ├── tests_content_login.py │ ├── tests_content_login_simple.py │ └── tests_no_content.py ├── urls.py ├── utils │ ├── __init__.py │ ├── manytomany.py │ ├── media.py │ ├── nodes.py │ ├── perms.py │ ├── render.py │ ├── sanitize.py │ ├── status.py │ └── transliterate.py └── views.py ├── requirements.txt ├── setup.py └── tests ├── __init__.py ├── media └── ninecms │ └── basic │ └── image │ ├── test_big.jpg │ ├── test_big_portrait.jpg │ └── test_small.png ├── settings_test.py ├── templates └── ninecms │ ├── page_basic.html │ └── page_front.html └── urls.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = */settings*.py,setup.py,manage.py 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Python 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # Distribution / packaging 8 | .Python 9 | env/ 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Unit test / coverage reports 26 | htmlcov/ 27 | .tox/ 28 | .coverage 29 | .coverage.* 30 | .cache 31 | nosetests.xml 32 | coverage.xml 33 | *,cover 34 | 35 | ### IDE 36 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 37 | .idea/ 38 | 39 | ### Fish vf 40 | .venv 41 | 42 | ### Django 43 | # Exclude all static files such as front-end libraries 44 | ninecms/static/ninecms/* 45 | 46 | # except ckeditor recommended build config 47 | !ninecms/static/ninecms/ckeditor/ 48 | ninecms/static/ninecms/ckeditor/* 49 | !ninecms/static/ninecms/ckeditor/build-config.js 50 | 51 | # except NineCMS own images, js and css 52 | !ninecms/static/ninecms/images/ 53 | !ninecms/static/ninecms/admin.js 54 | !ninecms/static/ninecms/layout.js 55 | !ninecms/static/ninecms/masonry.js 56 | !ninecms/static/ninecms/style.css 57 | tests/media/ninecms/basic/image/*/ 58 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # http://docs.travis-ci.com/user/languages/python/ 2 | 3 | language: python 4 | 5 | python: 6 | - 3.4 7 | 8 | install: 9 | - pip install -r requirements.txt 10 | - pip install coveralls 11 | 12 | script: 13 | coverage run --source='.' manage.py test ninecms 14 | 15 | after_success: 16 | coveralls 17 | 18 | notifications: 19 | email: 20 | on_success: change 21 | on_failure: change 22 | 23 | sudo: false 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Any contribution to the project is highly appreciated and the best will be done to respond to it. 6 | 7 | Authors 8 | ------- 9 | 10 | 1. George Karakostas (gckarakostas@gmail.com) 11 | 2. Panayiotis Broumis (pbroumis@gmail.com) 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) George Karakostas and individual contributors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of django-ninecms (Nine CMS, 9cms) nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | include CONTRIBUTING.rst 4 | include CHANGELOG.rst 5 | recursive-include ninecms * 6 | recursive-include docs * 7 | recursive-include tests * 8 | -------------------------------------------------------------------------------- /docs/screenshots/index1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/docs/screenshots/index1.png -------------------------------------------------------------------------------- /docs/screenshots/node1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/docs/screenshots/node1.png -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings_test") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /ninecms/__init__.py: -------------------------------------------------------------------------------- 1 | """ NineCMS package """ 2 | __version__ = '0.6.0' 3 | __author__ = 'George Karakostas' 4 | __copyright__ = 'Copyright 2015, George Karakostas' 5 | __licence__ = 'BSD-3' 6 | 7 | default_app_config = 'ninecms.apps.NineCMSConfig' 8 | -------------------------------------------------------------------------------- /ninecms/apps.py: -------------------------------------------------------------------------------- 1 | """ Application name of Nine CMS for Admin """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | from django.apps import AppConfig 8 | 9 | 10 | # noinspection PyUnresolvedReferences 11 | class NineCMSConfig(AppConfig): 12 | name = 'ninecms' 13 | verbose_name = "Nine CMS" 14 | 15 | def ready(self): 16 | import ninecms.signals 17 | import ninecms.checks 18 | -------------------------------------------------------------------------------- /ninecms/checks.py: -------------------------------------------------------------------------------- 1 | """ NineCMS system checks """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | 6 | from django.core.checks import register, Tags, Info 7 | from django.conf import settings 8 | 9 | 10 | # noinspection PyUnusedLocal 11 | @register(Tags.compatibility) 12 | def check_settings(app_configs, **kwargs): 13 | """ Check that settings are implemented properly for 9cms 14 | :param app_configs: a list of apps to be checks or None for all 15 | :param kwargs: keyword arguments 16 | :return: a list of errors 17 | """ 18 | checks = [] 19 | if not settings.MEDIA_ROOT: 20 | msg = ("No media root is specified in settings. A media folder is necessary for the user to upload images. " 21 | "You can specify one in the settings file as eg: `MEDIA_ROOT = os.path.join(BASE_DIR, 'media')`.") 22 | checks.append(Info(msg, id='ninecms.I001')) 23 | if not settings.MEDIA_URL: 24 | msg = ("No media url is specified in settings. A media url is necessary for 9cms to display uploaded images. " 25 | "You can specify one in the settings file as eg: `MEDIA_URL = '/media/'`.") 26 | checks.append(Info(msg, id='ninecms.I002')) 27 | if not settings.ADMINS: 28 | msg = ("No administrator emails are specified in settings. These are necessary for 9cms to send information " 29 | "on updates if a cron is setup. You can specify them in the settings file as eg: " 30 | "`ADMINS = (('Webmaster', 'web@9-dev.com'),)`.") 31 | checks.append(Info(msg, id='ninecms.I003')) 32 | if not settings.MANAGERS: 33 | msg = ("No manager emails are specified in settings. These are necessary for 9cms to messages through the " 34 | "contact form. You can specify them in the settings file as eg: " 35 | "`MANAGERS = (('Webmaster', 'web@9-dev.com'),)`.") 36 | checks.append(Info(msg, id='ninecms.I004')) 37 | if settings.SESSION_COOKIE_NAME == 'sessionid': 38 | msg = ("It is advised that you specify a session cookie name other than the default, especially in shared " 39 | "hosting environments. You can specify this in the settings file as eg: " 40 | "`SESSION_COOKIE_NAME = 'myapp_sessionid'`.") 41 | checks.append(Info(msg, id='ninecms.I005')) 42 | if settings.CACHES['default']['BACKEND'] == 'django.core.cache.backends.memcached.MemcachedCache': 43 | if not settings.CACHES['default']['KEY_PREFIX']: 44 | msg = ("It is advised that you specify a cache key prefix for the default memcached, especially in shared " 45 | "hosting environments. You can specify this in the settings file with " 46 | "``settings.CACHES['default']['KEY_PREFIX']`.") 47 | checks.append(Info(msg, id='ninecms.I006')) 48 | return checks 49 | -------------------------------------------------------------------------------- /ninecms/forms.py: -------------------------------------------------------------------------------- 1 | """ Form definition for Nine CMS """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | from django import forms 8 | from django.forms.models import inlineformset_factory 9 | from django.contrib.auth.models import Group 10 | from django.utils.translation import ugettext_lazy as _ 11 | from ninecms.models import Node, Image, File, Video, ContentBlock, PageType, TaxonomyTerm 12 | from ninecms.utils.sanitize import sanitize, ModelSanitizeForm 13 | from ninecms.utils.manytomany import ManyToManyModelForm, ModelBiMultipleChoiceField 14 | 15 | 16 | class PageTypeForm(ManyToManyModelForm): 17 | """ Override default page type form to show related blocks """ 18 | blocks = ModelBiMultipleChoiceField(ContentBlock.objects.all(), double_list="Blocks") 19 | 20 | class Meta: 21 | """ Meta class """ 22 | model = PageType 23 | fields = ['name', 'description', 'guidelines', 'url_pattern'] 24 | 25 | 26 | class ContentTypePermissionsForm(forms.Form): 27 | """ Content type permissions form """ 28 | add_node = forms.ModelMultipleChoiceField( 29 | queryset=Group.objects.all(), 30 | widget=forms.CheckboxSelectMultiple, 31 | required=False 32 | ) 33 | change_node = forms.ModelMultipleChoiceField( 34 | queryset=Group.objects.all(), 35 | widget=forms.CheckboxSelectMultiple, 36 | required=False 37 | ) 38 | delete_node = forms.ModelMultipleChoiceField( 39 | queryset=Group.objects.all(), 40 | widget=forms.CheckboxSelectMultiple, 41 | required=False 42 | ) 43 | 44 | 45 | class ContentNodeEditForm(ManyToManyModelForm): 46 | """ Node edit or create form """ 47 | terms = ModelBiMultipleChoiceField(TaxonomyTerm.objects.all(), double_list="Terms") 48 | 49 | def __init__(self, *args, **kwargs): 50 | """ Get user object to check if has full_html permission 51 | Checks if current_user is already set (eg from ModelAdmin) 52 | :param args: default arguments 53 | :param kwargs: default keywords, expecting user 54 | :return: None 55 | """ 56 | try: 57 | self.current_user = kwargs.pop('user', self.current_user) 58 | except AttributeError: 59 | self.current_user = kwargs.pop('user', None) 60 | super(ContentNodeEditForm, self).__init__(*args, **kwargs) 61 | 62 | def clean(self): 63 | """ Override clean form to bleach 64 | :return: cleaned data 65 | """ 66 | cleaned_data = super(ContentNodeEditForm, self).clean() 67 | full_html = self.current_user and self.current_user.has_perm('ninecms.use_full_html') 68 | for field in ('title', 'highlight', 'alias'): 69 | if field in cleaned_data: 70 | cleaned_data[field] = sanitize(cleaned_data[field], allow_html=False) 71 | for field in ('summary', 'body'): 72 | if field in cleaned_data: 73 | cleaned_data[field] = sanitize(cleaned_data[field], full_html=full_html) 74 | return cleaned_data 75 | 76 | class Meta: 77 | """ Form model and fields """ 78 | model = Node 79 | fields = ['page_type', 'language', 'title', 'user', 'status', 'promote', 'sticky', 'created', 80 | 'original_translation', 'summary', 'body', 'highlight', 'link', 'weight', 'alias', 'redirect'] 81 | 82 | 83 | class ImageForm(ModelSanitizeForm): 84 | """ Explicitly define image form in order to sanitize input """ 85 | class Meta: 86 | """ Form meta """ 87 | model = Image 88 | fields = ['title', 'group', 'image'] 89 | sanitize = ['title', 'group'] 90 | 91 | ImageInlineFormset = inlineformset_factory(Node, Image, form=ImageForm, extra=0, min_num=0) 92 | 93 | 94 | class FileForm(ModelSanitizeForm): 95 | """ Explicitly define file form in order to sanitize input """ 96 | class Meta: 97 | """ Form meta """ 98 | model = File 99 | fields = ['title', 'group', 'file'] 100 | sanitize = ['title', 'group'] 101 | 102 | FileInlineFormset = inlineformset_factory(Node, File, form=FileForm, extra=0, min_num=0) 103 | 104 | 105 | class VideoForm(ModelSanitizeForm): 106 | """ Explicitly define video form in order to sanitize input """ 107 | class Meta: 108 | """ Form meta """ 109 | model = Video 110 | fields = ['title', 'group', 'video', 'type', 'media'] 111 | sanitize = ['title', 'group', 'type', 'media'] 112 | 113 | VideoInlineFormset = inlineformset_factory(Node, Video, form=VideoForm, extra=0, min_num=0) 114 | 115 | 116 | class RedirectForm(forms.Form): 117 | """ General purpose form with a hidden redirect field, used in contact form, login form and as a logout form """ 118 | attr = {'class': 'form-control'} 119 | redirect = forms.CharField(widget=forms.HiddenInput()) 120 | 121 | 122 | class ContactForm(RedirectForm): 123 | """ Contact form """ 124 | sender_name = forms.CharField( 125 | max_length=100, 126 | label=_("Your name"), 127 | widget=forms.TextInput(attrs=RedirectForm.attr) 128 | ) 129 | sender_email = forms.EmailField( 130 | max_length=100, 131 | label=_("Your email"), 132 | widget=forms.TextInput(attrs=RedirectForm.attr) 133 | ) 134 | subject = forms.CharField(max_length=255, widget=forms.TextInput(attrs=RedirectForm.attr)) 135 | message = forms.CharField(widget=forms.Textarea(attrs=RedirectForm.attr)) 136 | 137 | def clean(self): 138 | """ Additionally to Django clean() (https://docs.djangoproject.com/en/1.7/ref/forms/validation/) 139 | Sanitize HTML from form data (http://stackoverflow.com/questions/5641901/sanitizing-html-in-submitted-form-data) 140 | Otherwise the template will escape without stripping if not so specified 141 | :return: cleaned data 142 | """ 143 | cleaned_data = super(ContactForm, self).clean() 144 | for field in ('sender_name', 'sender_email', 'message', 'redirect'): 145 | if field in cleaned_data: 146 | cleaned_data[field] = sanitize(cleaned_data[field], allow_html=False) 147 | if 'subject' in cleaned_data: 148 | cleaned_data['subject'] = "[Website Feedback] " + sanitize(cleaned_data['subject'], allow_html=False) 149 | return cleaned_data 150 | 151 | 152 | class LoginForm(RedirectForm): 153 | """ Login form """ 154 | username = forms.CharField(max_length=255, label=_("Username"), widget=forms.TextInput(attrs=RedirectForm.attr)) 155 | password = forms.CharField(max_length=255, label=_("Password"), widget=forms.PasswordInput(attrs=RedirectForm.attr)) 156 | 157 | 158 | class SearchForm(forms.Form): 159 | """ Search form """ 160 | q = forms.CharField(max_length=255, label=_("Search"), widget=forms.TextInput(attrs={'class': 'form-control'})) 161 | 162 | def clean(self): 163 | """ Override clean function to sanitize data 164 | :return: cleaned data 165 | """ 166 | cleaned_data = super(forms.Form, self).clean() 167 | if 'q' in cleaned_data: 168 | cleaned_data['q'] = sanitize(cleaned_data['q'], allow_html=False) 169 | return cleaned_data 170 | -------------------------------------------------------------------------------- /ninecms/management/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'gkarak' 2 | -------------------------------------------------------------------------------- /ninecms/management/commands/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'gkarak' 2 | -------------------------------------------------------------------------------- /ninecms/management/commands/cache_clear.py: -------------------------------------------------------------------------------- 1 | """ Management command for clearing cache """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | from django.core.management import BaseCommand 8 | from ninecms.utils.status import cache_clear 9 | 10 | 11 | class Command(BaseCommand): 12 | help = "Clears the cache." 13 | 14 | def handle(self, *args, **options): 15 | """ Core function 16 | :param args: None 17 | :param options: None 18 | :return: None 19 | """ 20 | cache_clear() 21 | self.stdout.write("Cache cleared.") 22 | -------------------------------------------------------------------------------- /ninecms/management/commands/check_updates.py: -------------------------------------------------------------------------------- 1 | """ Management command for checking updates """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | from django.core.management import BaseCommand 8 | from django.core.cache import caches 9 | from django.core.mail import mail_admins 10 | from django.template import loader 11 | from django.utils.translation import ugettext as _ 12 | from ninecms.utils.status import Capturing 13 | # noinspection PyPackageRequirements 14 | import pip 15 | 16 | 17 | class Command(BaseCommand): 18 | help = "Check for updates, store the results to cache and send email to admins." 19 | 20 | def handle(self, *args, **options): 21 | """ Core function 22 | :param args: None 23 | :param options: None 24 | :return: None 25 | """ 26 | with Capturing() as updates: 27 | pip.main(['list', '--outdated', '--retries', '1']) 28 | cache = caches['default'] 29 | if not updates: # pragma: nocover 30 | cache.delete('updates') 31 | else: # pragma: nocover 32 | cache.set('updates', updates, 7 * 24 * 60 * 60) # 1wk 33 | t = loader.get_template('ninecms/mail_updates.txt') 34 | mail_admins(_("New updates available"), t.render({'updates': updates})) 35 | -------------------------------------------------------------------------------- /ninecms/migrations/0002_auto_20150519_1102.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0001_squashed_0024_auto_20150416_1551'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='menuitem', 16 | name='title', 17 | field=models.CharField(max_length=255), 18 | ), 19 | migrations.AlterField( 20 | model_name='taxonomyterm', 21 | name='name', 22 | field=models.CharField(max_length=50), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /ninecms/migrations/0003_auto_20150623_1731.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0002_auto_20150519_1102'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='node', 16 | name='language', 17 | field=models.CharField(max_length=2, choices=[('el', 'Greek'), ('en', 'English')], blank=True), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /ninecms/migrations/0004_auto_20150624_1131.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0003_auto_20150623_1731'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterModelOptions( 15 | name='node', 16 | options={'permissions': (('access_toolbar', 'Can access the CMS toolbar'), ('use_full_html', 'Can use Full HTML in node body and summary'), ('list_nodes', 'Can list nodes'))}, 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /ninecms/migrations/0005_auto_20150624_1841.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0004_auto_20150624_1131'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterModelOptions( 15 | name='pagetype', 16 | options={'permissions': (('list_nodes_pagetype', 'List nodes of a specific page type'), ('add_node_pagetype', 'Add node of a specific page type'), ('change_node_pagetype', 'Change node of a specific page type'), ('delete_node_pagetype', 'Delete node of a specific page type')), 'ordering': ['id']}, 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /ninecms/migrations/0006_auto_20150701_1401.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0005_auto_20150624_1841'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='pagelayoutelement', 16 | name='hidden', 17 | field=models.BooleanField(db_index=True, default=False), 18 | ), 19 | migrations.AlterField( 20 | model_name='node', 21 | name='language', 22 | field=models.CharField(max_length=2, blank=True, choices=[('el', 'Greek')]), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /ninecms/migrations/0007_auto_20150727_1833.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0006_auto_20150701_1401'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='contentblock', 16 | name='type', 17 | field=models.CharField(default='static', choices=[('static', 'Static: link to node'), ('menu', 'Menu: render a menu or submenu'), ('signal', 'Signal: call site-specific custom render'), ('language', 'Language: switch menu'), ('user-menu', 'User menu: render a menu with login/register and logout links'), ('login', 'Login: render login form'), ('search', 'Search: render search form'), ('search-results', 'Search: render search results'), ('contact', 'Contact: render contact form')], max_length=50), 18 | ), 19 | migrations.AlterField( 20 | model_name='node', 21 | name='language', 22 | field=models.CharField(choices=[('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian 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'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmal'), ('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'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-cn', 'Simplified Chinese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese'), ('zh-tw', 'Traditional Chinese')], max_length=2, blank=True), 23 | ), 24 | migrations.AlterUniqueTogether( 25 | name='pagelayoutelement', 26 | unique_together=set([]), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /ninecms/migrations/0008_auto_20150819_1516.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0007_auto_20150727_1833'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='taxonomyterm', 16 | name='description_node', 17 | field=models.ForeignKey(related_name='term_described', blank=True, to='ninecms.Node', null=True), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /ninecms/migrations/0009_auto_20150924_1456.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Custom migration for fixing page type name issue 3 | from __future__ import unicode_literals 4 | 5 | # noinspection PyUnresolvedReferences 6 | from django.db import models, migrations 7 | from django.conf import settings 8 | from ninecms.utils.transliterate import transliterate 9 | import os 10 | 11 | 12 | def transliterate_folder(field): # pragma: nocover 13 | """ Utility function to transliterate a path_file_name 14 | :param field: string with path_file_name 15 | :return: transliterated path_file_name 16 | """ 17 | return '/'.join(list(transliterate(folder, True, True) for folder in field.split('/'))) 18 | 19 | 20 | # noinspection PyUnusedLocal 21 | # noinspection PyPep8Naming 22 | def migrate_path_file_name(apps, schema_editor): # pragma: nocover 23 | """ Transliterate the directories of all saved files 24 | Transliterate the corresponding field values 25 | :param app registry 26 | :param schema_editor 27 | :return: None 28 | """ 29 | basedir = os.path.join(settings.MEDIA_ROOT, 'ninecms') 30 | for folder in os.listdir(basedir): 31 | os.rename(os.path.join(basedir, folder), os.path.join(basedir, transliterate(folder, True, True))) 32 | 33 | Image = apps.get_model('ninecms', 'Image') 34 | for image in Image.objects.all(): 35 | image.image.name = transliterate_folder(image.image.name) 36 | image.save() 37 | 38 | File = apps.get_model('ninecms', 'File') 39 | for file in File.objects.all(): 40 | file.file.name = transliterate_folder(file.file.name) 41 | file.save() 42 | 43 | Video = apps.get_model('ninecms', 'Video') 44 | for video in Video.objects.all(): 45 | video.video.name = transliterate_folder(video.video.name) 46 | video.save() 47 | 48 | 49 | # noinspection PyUnusedLocal 50 | def reverse(apps, schema_editor): # pragma: nocover 51 | """ 52 | Reverse the above operation 53 | Nothing to do here, transliterated folder names remain 54 | :param apps: app registry 55 | :param schema_editor 56 | :return: None 57 | """ 58 | pass 59 | 60 | 61 | class Migration(migrations.Migration): 62 | 63 | dependencies = [ 64 | ('ninecms', '0008_auto_20150819_1516'), 65 | ] 66 | 67 | operations = [ 68 | migrations.RunPython(migrate_path_file_name, reverse), 69 | ] 70 | -------------------------------------------------------------------------------- /ninecms/migrations/0010_auto_20150924_1850.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ninecms', '0009_auto_20150924_1456'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterModelOptions( 15 | name='node', 16 | options={'permissions': (('access_toolbar', 'Can access the CMS toolbar'), ('use_full_html', 'Can use Full HTML in node body and summary'), ('list_nodes', 'Can list nodes'), ('view_unpublished', 'Can view unpublished content'))}, 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /ninecms/migrations/0011_auto_20151202_1400.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import migrations, models 5 | import mptt.fields 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('ninecms', '0010_auto_20150924_1850'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='node', 17 | options={'permissions': (('use_full_html', 'Can use Full HTML in node body and summary'), ('view_unpublished', 'Can view unpublished content'))}, 18 | ), 19 | migrations.AlterModelOptions( 20 | name='pagetype', 21 | options={'ordering': ['id'], 'permissions': (('add_node_pagetype', 'Add node of a specific page type'), ('change_node_pagetype', 'Change node of a specific page type'), ('delete_node_pagetype', 'Delete node of a specific page type'))}, 22 | ), 23 | migrations.AlterField( 24 | model_name='contentblock', 25 | name='classes', 26 | field=models.CharField(max_length=255, blank=True, help_text='Additional CSS classes to append to block.'), 27 | ), 28 | migrations.AlterField( 29 | model_name='contentblock', 30 | name='menu_item', 31 | field=mptt.fields.TreeForeignKey(blank=True, null=True, to='ninecms.MenuItem', help_text='The related parent menu item related (block type: menu only).'), 32 | ), 33 | migrations.AlterField( 34 | model_name='contentblock', 35 | name='node', 36 | field=models.ForeignKey(blank=True, null=True, to='ninecms.Node', help_text='The related node with this block (block type: static only).'), 37 | ), 38 | migrations.AlterField( 39 | model_name='contentblock', 40 | name='signal', 41 | field=models.CharField(max_length=100, blank=True, help_text='The signal name to trigger for a custom view (block type: signal only).'), 42 | ), 43 | migrations.AlterField( 44 | model_name='contentblock', 45 | name='type', 46 | field=models.CharField(max_length=50, choices=[('static', 'Static: link to node'), ('menu', 'Menu: render a menu or submenu'), ('signal', 'Signal: call site-specific custom render'), ('language', 'Language: switch menu'), ('user-menu', 'User menu: render a menu with login/register and logout links'), ('login', 'Login: render login form'), ('search', 'Search: render search form'), ('search-results', 'Search: render search results'), ('contact', 'Contact: render contact form')], help_text='How to render the block.', default='static'), 47 | ), 48 | migrations.AlterField( 49 | model_name='menuitem', 50 | name='language', 51 | # field=models.CharField(max_length=2, blank=True, choices=[('el', 'Greek')]), 52 | field=models.CharField(choices=[('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian 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'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmal'), ('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'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-cn', 'Simplified Chinese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese'), ('zh-tw', 'Traditional Chinese')], max_length=2, blank=True), 53 | ), 54 | # migrations.AlterField( 55 | # model_name='node', 56 | # name='language', 57 | # field=models.CharField(max_length=2, blank=True, choices=[('el', 'Greek')]), 58 | # ), 59 | migrations.AlterField( 60 | model_name='pagelayoutelement', 61 | name='region', 62 | field=models.CharField(max_length=50, help_text='A hard coded region name that is rendered in template index and also used in theme suggestions.', db_index=True), 63 | ), 64 | migrations.AlterField( 65 | model_name='pagelayoutelement', 66 | name='weight', 67 | field=models.IntegerField(help_text='Elements with greater number in the same region sink to the bottom of the page.', default=0, db_index=True), 68 | ), 69 | migrations.AlterField( 70 | model_name='pagetype', 71 | name='description', 72 | field=models.CharField(max_length=255, help_text='Describe the page type.'), 73 | ), 74 | migrations.AlterField( 75 | model_name='pagetype', 76 | name='guidelines', 77 | field=models.CharField(max_length=255, blank=True, help_text='Provide content submission guidelines for this page type.'), 78 | ), 79 | migrations.AlterField( 80 | model_name='pagetype', 81 | name='name', 82 | field=models.CharField(max_length=100, unique=True, help_text='Specify a unique page type name. A machine name is recommended if to be used in code.'), 83 | ), 84 | migrations.AlterField( 85 | model_name='pagetype', 86 | name='template', 87 | field=models.CharField(max_length=255, blank=True, help_text='Custom template name (deprecated).'), 88 | ), 89 | migrations.AlterField( 90 | model_name='pagetype', 91 | name='url_pattern', 92 | field=models.CharField(max_length=255, blank=True, help_text='Default pattern for page type, if no alias is specified in node edit. More info.'), 93 | ), 94 | ] 95 | -------------------------------------------------------------------------------- /ninecms/migrations/0013_auto_20160117_1209.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.1 on 2016-01-17 10:09 3 | 4 | # Overridden migration to prepare default value for block name 5 | # and to transfer elements to new m2m field 6 | 7 | # Several lines excluded from tests with pragma nocover 8 | # Haven't found a working way to test migrations, the following have been tested: 9 | # https://micknelson.wordpress.com/2013/03/01/testing-django-migrations/ 10 | # https://www.caktusgroup.com/blog/2016/02/02/writing-unit-tests-django-migrations/ 11 | # Other migrations include 0009 12 | 13 | from __future__ import unicode_literals 14 | from django.db import migrations, models 15 | 16 | 17 | def str_block(block): # pragma: nocover 18 | """ Get title based on block type 19 | The default `__str__` methods do not operate within migrations 20 | :return: model title 21 | """ 22 | if block.type == 'static': 23 | return '-'.join((block.type, block.node.title)) 24 | elif block.type == 'menu': 25 | return '-'.join((block.type, block.menu_item.title)) 26 | elif block.type == 'signal': 27 | return '-'.join((block.type, block.signal)) 28 | return block.type 29 | 30 | 31 | # noinspection PyUnusedLocal 32 | # noinspection PyPep8Naming 33 | def provide_block_name_default(apps, schema_editor): 34 | """ Provide a default block name in order for the next migration to establish field unique 35 | :param apps: app registry 36 | :param schema_editor 37 | :return: None 38 | """ 39 | Block = apps.get_model('ninecms', 'ContentBlock') 40 | for block in Block.objects.all(): # pragma: nocover 41 | block.name = '%s-%d' % (str_block(block), block.pk) 42 | block.save() 43 | 44 | 45 | # noinspection PyUnusedLocal 46 | # noinspection PyPep8Naming 47 | def transfer_elements(apps, schema_editor): 48 | """ Transfer records from deprecated PageLayoutElements to new page_types block field 49 | :param apps 50 | :param schema_editor 51 | :return: None 52 | """ 53 | PageLayoutElement = apps.get_model('ninecms', 'PageLayoutElement') 54 | for element in PageLayoutElement.objects.all(): # pragma: nocover 55 | element.block.page_types.add(element.page_type) 56 | 57 | 58 | # noinspection PyUnusedLocal 59 | def reverse(apps, schema_editor): # pragma: nocover 60 | """ 61 | Reverse the above operations 62 | Nothing to do here, data in fields will be removed anyway 63 | :param apps: app registry 64 | :param schema_editor 65 | :return: None 66 | """ 67 | pass 68 | 69 | 70 | class Migration(migrations.Migration): 71 | """ Migration class """ 72 | 73 | dependencies = [ 74 | ('ninecms', '0012_auto_20151218_1637'), 75 | ] 76 | 77 | operations = [ 78 | migrations.AddField( 79 | model_name='contentblock', 80 | name='name', 81 | field=models.CharField( 82 | help_text='Specify a unique block machine name.', 83 | max_length=100, 84 | null=True, 85 | verbose_name='name' 86 | ), 87 | ), 88 | migrations.AddField( 89 | model_name='contentblock', 90 | name='page_types', 91 | field=models.ManyToManyField( 92 | blank=True, 93 | related_name='blocks', 94 | to='ninecms.PageType', 95 | verbose_name='page types' 96 | ), 97 | ), 98 | migrations.AlterField( 99 | model_name='menuitem', 100 | name='language', 101 | field=models.CharField( 102 | blank=True, 103 | choices=[('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('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'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmal'), ('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'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')], max_length=2, verbose_name='language'), 104 | ), 105 | migrations.AlterField( 106 | model_name='node', 107 | name='language', 108 | field=models.CharField( 109 | blank=True, 110 | choices=[('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('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'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmal'), ('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'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')], max_length=2, verbose_name='language'), 111 | ), 112 | migrations.RemoveField( 113 | model_name='pagetype', 114 | name='template', 115 | ), 116 | migrations.RunPython(provide_block_name_default, reverse), 117 | migrations.RunPython(transfer_elements, reverse), 118 | ] 119 | -------------------------------------------------------------------------------- /ninecms/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/migrations/__init__.py -------------------------------------------------------------------------------- /ninecms/settings.py: -------------------------------------------------------------------------------- 1 | """ Settings default definition for Nine CMS """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | """ Default recommended settings """ 8 | # INSTALLED_APPS = ( 9 | # 'admin_bootstrapped_plus', 10 | # # 'bootstrap3', 11 | # 'django_admin_bootstrapped', 12 | # 'django.contrib.admin', 13 | # 'django.contrib.auth', 14 | # 'django.contrib.contenttypes', 15 | # 'django.contrib.sessions', 16 | # 'django.contrib.messages', 17 | # 'django.contrib.staticfiles', 18 | # 'mptt', 19 | # 'debug_toolbar', 20 | # 'guardian', 21 | # 'ninecms', 22 | # 'myproject_core' 23 | # ) 24 | # 25 | # MIDDLEWARE_CLASSES = ( 26 | # 'django.middleware.cache.UpdateCacheMiddleware', 27 | # 'django.contrib.sessions.middleware.SessionMiddleware', 28 | # 'django.middleware.locale.LocaleMiddleware', 29 | # 'django.middleware.common.CommonMiddleware', 30 | # 'django.middleware.cache.FetchFromCacheMiddleware', 31 | # 'django.middleware.csrf.CsrfViewMiddleware', 32 | # 'django.contrib.auth.middleware.AuthenticationMiddleware', 33 | # 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 34 | # 'django.contrib.messages.middleware.MessageMiddleware', 35 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 36 | # 'django.middleware.security.SecurityMiddleware', 37 | # ) 38 | 39 | # ROOT_URLCONF = 'myproject.urls' 40 | 41 | # TEMPLATES = [ 42 | # { 43 | # 'BACKEND': 'django.template.backends.django.DjangoTemplates', 44 | # 'DIRS': [ 45 | # os.path.join(BASE_DIR, 'templates'), 46 | # ], 47 | # 'APP_DIRS': True, 48 | # 'OPTIONS': { 49 | # 'context_processors': [ 50 | # 'django.template.context_processors.debug', 51 | # 'django.template.context_processors.request', 52 | # 'django.contrib.auth.context_processors.auth', 53 | # 'django.contrib.messages.context_processors.messages', 54 | # ], 55 | # 'debug': True, 56 | # }, 57 | # }, 58 | # ] 59 | 60 | # WSGI_APPLICATION = 'myproject.wsgi.application' 61 | 62 | 63 | # DATABASES = { 64 | # 'default': { 65 | # 'ENGINE': 'django.db.backends.sqlite3', 66 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 67 | # } 68 | # } 69 | 70 | 71 | # LANGUAGE_CODE = 'el' 72 | # 73 | # LANGUAGES = ( 74 | # ('el', 'Greek'), 75 | # # ('en', 'English'), 76 | # ) 77 | # 78 | # TIME_ZONE = 'Europe/Athens' 79 | 80 | # USE_I18N = True 81 | # 82 | # USE_L10N = True 83 | # 84 | # USE_TZ = True 85 | 86 | # STATIC_URL = '/static/' 87 | # 88 | # # Following remains for PyCharm code inspections in templates; deprecated in Django 1.8 89 | # TEMPLATE_DIRS = ( 90 | # os.path.join(BASE_DIR, 'templates'), 91 | # ) 92 | 93 | # STATICFILES_DIRS = ( 94 | # os.path.join(BASE_DIR, "static"), 95 | # ) 96 | 97 | # MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 98 | # 99 | # MEDIA_URL = '/media/' 100 | 101 | # LOGIN_URL = '/admin/login/' 102 | 103 | # # Error reporting 104 | # 105 | # ADMINS = ( 106 | # ("Webmaster", "web@9-dev.com"), 107 | # ) 108 | # 109 | # MANAGERS = ( 110 | # ("Webmaster", "web@9-dev.com"), 111 | # ) 112 | # 113 | # EMAIL_HOST = 'mail.9-dev.com' 114 | # 115 | # EMAIL_HOST_USER = 'ninecms@9-dev.com' 116 | # 117 | # EMAIL_HOST_PASSWORD = '' 118 | # 119 | # EMAIL_USE_SSL = True 120 | # 121 | # EMAIL_PORT = 465 122 | # 123 | # EMAIL_SUBJECT_PREFIX = '[9cms] ' 124 | # 125 | # SERVER_EMAIL = 'ninecms@9-dev.com' 126 | # 127 | # DEFAULT_FROM_EMAIL = 'ninecms@9-dev.com' 128 | # 129 | # 130 | # # Security 131 | # # http://django-secure.readthedocs.org/en/latest/settings.html 132 | # 133 | # SECURE_CONTENT_TYPE_NOSNIFF = True 134 | # 135 | # SECURE_BROWSER_XSS_FILTER = True 136 | # 137 | # X_FRAME_OPTIONS = 'DENY' 138 | # 139 | # CSRF_COOKIE_HTTPONLY = True 140 | # 141 | # # SSL only 142 | # # SECURE_SSL_REDIRECT = True 143 | # 144 | # # SECURE_HSTS_SECONDS = 31536000 145 | # 146 | # # SECURE_HSTS_INCLUDE_SUBDOMAINS = True 147 | # 148 | # # SESSION_COOKIE_SECURE = True 149 | # 150 | # # CSRF_COOKIE_SECURE = True 151 | 152 | # # Add unique session cookie name for concurrent logins with other sites 153 | # SESSION_COOKIE_NAME = 'myapp_sessionid' 154 | # 155 | # # Caches 156 | # # https://docs.djangoproject.com/en/1.8/topics/cache/ 157 | # 158 | # CACHES = { 159 | # 'default': { 160 | # 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', 161 | # } 162 | # } 163 | # 164 | # CACHE_MIDDLEWARE_SECONDS = 3 * 60 * 60 165 | 166 | # # Guardian 167 | # # https://django-guardian.readthedocs.org/en/v1.2/configuration.html 168 | # 169 | # AUTHENTICATION_BACKENDS = ( 170 | # 'django.contrib.auth.backends.ModelBackend', # this is default 171 | # 'guardian.backends.ObjectPermissionBackend', 172 | # ) 173 | # 174 | # ANONYMOUS_USER_ID = -1 175 | 176 | # # Django admin 177 | # DAB_FIELD_RENDERER = 'django_admin_bootstrapped.renderers.BootstrapFieldRenderer' 178 | # 179 | # MESSAGE_TAGS = { 180 | # messages.SUCCESS: 'alert-success success', 181 | # messages.WARNING: 'alert-warning warning', 182 | # messages.ERROR: 'alert-danger error' 183 | # } 184 | 185 | 186 | """ Test """ 187 | # from myapp.settings import * 188 | # 189 | # DEBUG = True 190 | # 191 | # PASSWORD_HASHERS = ( 192 | # 'django.contrib.auth.hashers.MD5PasswordHasher', 193 | # ) 194 | # 195 | # TEMPLATES = [ 196 | # { 197 | # 'BACKEND': 'django.template.backends.django.DjangoTemplates', 198 | # 'DIRS': [ # disable overriden templates 199 | # ], 200 | # 'APP_DIRS': True, 201 | # 'OPTIONS': { 202 | # 'context_processors': [ 203 | # 'django.template.context_processors.debug', 204 | # 'django.template.context_processors.request', 205 | # 'django.contrib.auth.context_processors.auth', 206 | # 'django.contrib.messages.context_processors.messages', 207 | # ], 208 | # 'debug': True, 209 | # }, 210 | # }, 211 | # ] 212 | # 213 | # DATABASES = { 214 | # 'default': { 215 | # 'ENGINE': 'django.db.backends.sqlite3', 216 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 217 | # } 218 | # } 219 | # 220 | # LANGUAGES = ( 221 | # ('el', 'Greek'), 222 | # ('en', 'English'), 223 | # ) 224 | # 225 | # IMAGE_STYLES.update({ 226 | # 'thumbnail-upscale': { 227 | # 'type': 'thumbnail-upscale', 228 | # 'size': (150, 150) 229 | # }, 230 | # }) 231 | 232 | """ Live """ 233 | # # noinspection PyUnresolvedReferences 234 | # from myapp.settings import * 235 | # 236 | # DEBUG = False 237 | # 238 | # ALLOWED_HOSTS = [ 239 | # '', 240 | # ] 241 | # 242 | # TEMPLATE_DIRS = None 243 | # 244 | # TEMPLATES = [ 245 | # { 246 | # 'BACKEND': 'django.template.backends.django.DjangoTemplates', 247 | # 'DIRS': [ 248 | # os.path.join(BASE_DIR, 'templates'), 249 | # ], 250 | # 'APP_DIRS': True, 251 | # 'OPTIONS': { 252 | # 'context_processors': [ 253 | # 'django.template.context_processors.debug', 254 | # 'django.template.context_processors.request', 255 | # 'django.contrib.auth.context_processors.auth', 256 | # 'django.contrib.messages.context_processors.messages', 257 | # ], 258 | # }, 259 | # }, 260 | # ] 261 | # 262 | # STATIC_ROOT = '/var/www' 263 | # 264 | # STATICFILES_DIRS = [] 265 | # 266 | # CACHES = { 267 | # 'default': { 268 | # 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 269 | # 'LOCATION': '127.0.0.1:11211', 270 | # 'TIMEOUT': 3 * 60 * 60, # 3h 271 | # 'KEY_PREFIX': 'rabelvideo_', 272 | # 'VERSION': 1, 273 | # } 274 | # } 275 | 276 | 277 | """ CMS """ 278 | 279 | # Site name to display in title etc. 280 | SITE_NAME = "9cms" 281 | 282 | # Meta author tag 283 | SITE_AUTHOR = "9cms" 284 | 285 | # Meta keywords 286 | SITE_KEYWORDS = "" 287 | 288 | # Define image styles 289 | IMAGE_STYLES = { 290 | 'thumbnail': { 291 | 'type': 'thumbnail', 292 | 'size': (150, 1000) 293 | }, 294 | 'thumbnail_crop': { 295 | 'type': 'thumbnail-crop', 296 | 'size': (150, 150) 297 | }, 298 | 'thumbnail_upscale': { 299 | 'type': 'thumbnail-upscale', 300 | 'size': (150, 150) 301 | }, 302 | 'gallery_style': { 303 | 'type': 'thumbnail', 304 | 'size': (400, 1000) 305 | }, 306 | 'blog_style': { 307 | 'type': 'thumbnail-crop', 308 | 'size': (350, 226) 309 | }, 310 | 'large': { 311 | 'type': 'thumbnail', 312 | 'size': (1280, 1280) 313 | }, 314 | } 315 | 316 | # Update image styles in project settings such as: 317 | # IMAGE_STYLES.update({}) 318 | 319 | # Define characters to remove at transliteration 320 | TRANSLITERATE_REMOVE = '"\'`,:;|{[}]+=*&%^$#@!~()?<>' 321 | 322 | # Define characters to replace at transliteration 323 | TRANSLITERATE_REPLACE = (' .-_/', '-----') 324 | 325 | # Define language menu labels 326 | # Possible values: name, code, flag 327 | LANGUAGE_MENU_LABELS = 'name' 328 | 329 | # Enable i18n urls for 9cms 330 | I18N_URLS = True 331 | -------------------------------------------------------------------------------- /ninecms/signals.py: -------------------------------------------------------------------------------- 1 | """ Signal definitions for Nine CMS """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | from django import dispatch 8 | from django.db.models.signals import pre_delete 9 | from django.contrib.contenttypes.models import ContentType 10 | # noinspection PyPackageRequirements 11 | from guardian.models import GroupObjectPermission 12 | from ninecms.models import TaxonomyTerm, Node, PageType, Video, Image, File 13 | from ninecms.utils.media import delete_all 14 | 15 | 16 | # noinspection PyUnusedLocal 17 | @dispatch.receiver(pre_delete) 18 | def pre_delete_tasks(sender, instance, **kwargs): 19 | """ Delete all relevant permissions from guardian as there is no foreign key to the object 20 | http://django-guardian.readthedocs.org/en/stable/userguide/caveats.html 21 | Delete the respective file when an image, a video or a file record is to be deleted 22 | :param sender: the model to be deleted 23 | :param instance: the page type object to be deleted 24 | :param kwargs: other arguments 25 | :return: None 26 | """ 27 | if sender == PageType: 28 | content_type = ContentType.objects.get_for_model(instance) 29 | GroupObjectPermission.objects.filter(content_type=content_type, object_pk=instance.pk).delete() 30 | elif sender == Image: 31 | delete_all(instance.image.path) 32 | elif sender == Video: 33 | delete_all(instance.video.path) 34 | elif sender == File: 35 | delete_all(instance.file.path) 36 | 37 | 38 | block_signal = dispatch.Signal(providing_args=['view', 'request']) 39 | 40 | 41 | @dispatch.receiver(block_signal) 42 | def render_view(**kwargs): 43 | """ Example of custom views 44 | :param kwargs: 'view' contains the CMS view to render 45 | :return: None 46 | """ 47 | if kwargs['view'] == 'terms': 48 | return TaxonomyTerm.objects.all() 49 | -------------------------------------------------------------------------------- /ninecms/static/ninecms/admin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file admin.js 3 | * Provide ajax operations for 9cms admin 4 | * 5 | * @author 6 | * George Karakostas 7 | * 8 | * @copyright 9 | * (c) 2015 George Karakostas 10 | * 11 | * @license 12 | * BSD-3 13 | * 14 | * @email 15 | * gkarak@9-dev.com 16 | */ 17 | 18 | (function($) { 19 | /** 20 | * Add a css class on element for a specified time 21 | * Combine with css transition for a nice effect 22 | * Alternatively use jQueryUI addClass 23 | * 24 | * @param css: the class to add 25 | * @param time: for how long 26 | */ 27 | $.fn.addClassTemp = function(css, time) { 28 | return this 29 | .addClass(css) 30 | .delay(time) 31 | .queue(function() { 32 | $(this) 33 | .removeClass(css) 34 | .dequeue(); 35 | }); 36 | }; 37 | 38 | $(document).ready(function() { 39 | /******************* 40 | * Ajax edit inline 41 | ******************/ 42 | $(this).djangoAjaxSetup({csrf_cookie_httponly: true}); 43 | $('.edit-inline').on('click', function(e) { 44 | var t = $(this); 45 | /** 46 | * Ajax success callback function (see below) 47 | * Parse the serialized data returned in form eg. id=1&status=True 48 | * then find the row, then the a element and set value and glyphicon 49 | * 50 | * @param json: data returned 51 | */ 52 | var ajaxSuccess = function(json) { 53 | var data = this.data.match(/id=([-_\w\d]+)&([-_\w\d]+)=([-_\w\d]+)/); 54 | $('tr[data-id="' + data[1] + '"]') 55 | .find('a[data-field="' + data[2] + '"]') 56 | .each(function() { 57 | if (json.result) { 58 | var value = data[3]; 59 | if ($(this).data('type') == 'bool') { 60 | value = (value == 'True')? 'ok': 'remove'; 61 | value = '' 62 | } 63 | $(this) 64 | .data('value', data[3]).html(value) 65 | .addClassTemp('text-success', 4000); 66 | } 67 | else $(this).addClassTemp('text-danger', 4000); 68 | console.log(json); 69 | }); 70 | }; 71 | // construct the post data 72 | var data = {id: t.parents('tr').data('id')}; 73 | var value = t.data('value'); 74 | if (t.data('type') == 'bool') { 75 | if (value == 'True') value = 'False'; 76 | else value = 'True'; 77 | } 78 | data[t.data('field')] = value; 79 | $.ajax({ 80 | url: t.parents('tr').data('edit-inline-url'), 81 | type: 'POST', 82 | data: data, 83 | success: ajaxSuccess 84 | }); 85 | e.preventDefault(); 86 | }); 87 | }); 88 | })(jQuery); 89 | -------------------------------------------------------------------------------- /ninecms/static/ninecms/ckeditor/build-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved. 3 | * For licensing, see LICENSE.md or http://ckeditor.com/license 4 | */ 5 | 6 | /** 7 | * This file was added automatically by CKEditor builder. 8 | * You may re-use it at any time to build CKEditor again. 9 | * 10 | * If you would like to build CKEditor online again 11 | * (for example to upgrade), visit one the following links: 12 | * 13 | * (1) http://ckeditor.com/builder 14 | * Visit online builder to build CKEditor from scratch. 15 | * 16 | * (2) http://ckeditor.com/builder/0f20eddcb7463a55558fc4f293ca0dda 17 | * Visit online builder to build CKEditor, starting with the same setup as before. 18 | * 19 | * (3) http://ckeditor.com/builder/download/0f20eddcb7463a55558fc4f293ca0dda 20 | * Straight download link to the latest version of CKEditor (Optimized) with the same setup as before. 21 | * 22 | * NOTE: 23 | * This file is not used by CKEditor, you may remove it. 24 | * Changing this file will not change your CKEditor configuration. 25 | */ 26 | 27 | var CKBUILDER_CONFIG = { 28 | skin: 'moono', 29 | preset: 'basic', 30 | ignore: [ 31 | '.bender', 32 | 'bender.js', 33 | 'bender-err.log', 34 | 'bender-out.log', 35 | 'dev', 36 | '.DS_Store', 37 | '.editorconfig', 38 | '.gitattributes', 39 | '.gitignore', 40 | 'gruntfile.js', 41 | '.idea', 42 | '.jscsrc', 43 | '.jshintignore', 44 | '.jshintrc', 45 | 'less', 46 | '.mailmap', 47 | 'node_modules', 48 | 'package.json', 49 | 'README.md', 50 | 'tests' 51 | ], 52 | plugins : { 53 | 'basicstyles' : 1, 54 | 'blockquote' : 1, 55 | 'clipboard' : 1, 56 | 'codeTag' : 1, 57 | 'div' : 1, 58 | 'elementspath' : 1, 59 | 'enterkey' : 1, 60 | 'entities' : 1, 61 | 'filebrowser' : 1, 62 | 'find' : 1, 63 | 'floatingspace' : 1, 64 | 'format' : 1, 65 | 'horizontalrule' : 1, 66 | 'htmlwriter' : 1, 67 | 'image' : 1, 68 | 'indentblock' : 1, 69 | 'indentlist' : 1, 70 | 'justify' : 1, 71 | 'link' : 1, 72 | 'list' : 1, 73 | 'magicline' : 1, 74 | 'maximize' : 1, 75 | 'newpage' : 1, 76 | 'pagebreak' : 1, 77 | 'pastefromword' : 1, 78 | 'pastetext' : 1, 79 | 'pbckcode' : 1, 80 | 'quicktable' : 1, 81 | 'removeformat' : 1, 82 | 'resize' : 1, 83 | 'scayt' : 1, 84 | 'selectall' : 1, 85 | 'showblocks' : 1, 86 | 'showborders' : 1, 87 | 'sourcearea' : 1, 88 | 'specialchar' : 1, 89 | 'stylescombo' : 1, 90 | 'tab' : 1, 91 | 'tabletools' : 1, 92 | 'toolbar' : 1, 93 | 'undo' : 1, 94 | 'widget' : 1, 95 | 'wordcount' : 1, 96 | 'wsc' : 1, 97 | 'wysiwygarea' : 1, 98 | 'youtube' : 1 99 | }, 100 | languages : { 101 | 'el' : 1, 102 | 'en' : 1 103 | } 104 | }; -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/favicon.ico -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/af.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/af.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ar.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/be.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/be.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/bg.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/bo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/bo.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ca.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/cs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/cs.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/da.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/da.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/de.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/el.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/el.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/en.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/eo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/eo.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/es.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/et.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/et.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/eu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/eu.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/fa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/fa.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/fi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/fi.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/fil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/fil.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/fo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/fo.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/fr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/fr.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ga.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/gl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/gl.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/he.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/he.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/hi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/hi.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/hr.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/hu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/hu.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/id.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/is.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/is.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/it.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ja.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/km.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/km.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ko.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/lb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/lb.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/lt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/lt.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/lv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/lv.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/mn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/mn.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ms.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/nb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/nb.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/nl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/nl.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/nn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/nn.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/pl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/pl.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/pt-br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/pt-br.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/pt-pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/pt-pt.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ro.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/ru.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/sco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/sco.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/se.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/se.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/sk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/sk.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/sl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/sl.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/so.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/so.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/sq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/sq.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/sr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/sr.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/sv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/sv.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/tg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/tg.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/th.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/th.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/tl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/tl.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/tr.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/uk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/uk.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/vi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/vi.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/zh-hans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/zh-hans.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/flags/zh-hant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/flags/zh-hant.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/images/toplink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wtower/django-ninecms/e500010fb11f06c8dfe8d8c9c4d2aab0b15bc127/ninecms/static/ninecms/images/toplink.png -------------------------------------------------------------------------------- /ninecms/static/ninecms/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file layout.js 3 | * Provide js-level formatting 4 | * 5 | * @author 6 | * George Karakostas 7 | * 8 | * @copyright 9 | * (c) 2015 George Karakostas 10 | * 11 | * @license 12 | * BSD-3 13 | * 14 | * @email 15 | * gkarak@9-dev.com 16 | */ 17 | 18 | (function ($) { 19 | jQuery.fn.topLink = function(settings) { 20 | settings = jQuery.extend({ 21 | min: 1, 22 | fadeSpeed: 200 23 | }, settings); 24 | return this.each(function() { 25 | //listen for scroll 26 | var el = jQuery(this); 27 | el.hide(); //in case the user forgot 28 | jQuery(window).scroll(function() { 29 | if(jQuery(window).scrollTop() >= settings.min) { 30 | el.fadeIn(settings.fadeSpeed); 31 | } 32 | else { 33 | el.fadeOut(settings.fadeSpeed); 34 | } 35 | }); 36 | }); 37 | }; 38 | 39 | $(document).ready(function () { 40 | // Loader 41 | // hide scroll and show on window.load 42 | var loader = $('#loader'); 43 | if (loader.length && loader.css('display') != 'none') $('body').css({overflow: 'hidden'}); 44 | 45 | // Page top 46 | $('#top-link') 47 | // set the link 48 | .topLink({ 49 | min: 400, 50 | fadeSpeed: 500 51 | }) 52 | // smooth scroll 53 | .click(function(e) { 54 | e.preventDefault(); 55 | $.scrollTo(0,300); 56 | }); 57 | 58 | // Show/hide toolbar 59 | $('.toolbar-handler').on('click', 'a', function(e) { 60 | $('body').toggleClass('toolbar').find('.toolbar').toggleClass('hide'); 61 | e.preventDefault(); 62 | }); 63 | 64 | // Shrink 65 | if ($('.shrinkable').length) { 66 | $(window).scroll(function() { 67 | if ($(this).scrollTop() > 50) 68 | $('.shrinkable').addClass('shrink'); 69 | else $('.shrinkable').removeClass('shrink'); 70 | }); 71 | } 72 | 73 | // Bookmark smooth scroll 74 | $('.nav a[href*="#"]').each(function() { 75 | var bookmark = $(this).attr('href').match(/(#.*)$/g)[0]; 76 | if (bookmark == '#') return; 77 | if (!$(bookmark).length) return; 78 | $(this).on('click', function() { 79 | $.scrollTo(bookmark, 300, {offset: {top: -50, left: 0}}); 80 | }); 81 | }); 82 | 83 | // bootstrap 84 | $('input[type="text"], input[type="number"], input[type="email"], input[type="url"], select') 85 | .addClass('form-control'); 86 | 87 | }); 88 | 89 | $(window).load(function () { 90 | // Loader 91 | // hide loader and show scrollbars (hidden in document.ready) 92 | $('#loader, #loader-container').fadeOut('slow'); 93 | $('body').css({'overflow': 'visible'}); 94 | }); 95 | 96 | }(jQuery)); 97 | -------------------------------------------------------------------------------- /ninecms/static/ninecms/masonry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file layout.js 3 | * Provide js-level formatting 4 | * 5 | * @author 6 | * George Karakostas 7 | * 8 | * @copyright 9 | * (c) 2015 George Karakostas 10 | * 11 | * @license 12 | * BSD-3 13 | * 14 | * @email 15 | * gkarak@9-dev.com 16 | */ 17 | 18 | (function($) { 19 | 20 | var $container = $('.masonry-container'); 21 | $container.imagesLoaded( function () { 22 | $container.masonry({ 23 | columnWidth: '.item', 24 | itemSelector: '.item' 25 | }); 26 | }); 27 | 28 | //Reinitialize masonry inside each panel after the relative tab link is clicked - 29 | $('a[data-toggle=tab]').each(function () { 30 | var $this = $(this); 31 | 32 | $this.on('shown.bs.tab', function () { 33 | 34 | $container.imagesLoaded( function () { 35 | $container.masonry({ 36 | columnWidth: '.item', 37 | itemSelector: '.item' 38 | }); 39 | }); 40 | 41 | }); //end shown 42 | }); //end each 43 | 44 | })(jQuery); -------------------------------------------------------------------------------- /ninecms/static/ninecms/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | NineCMS styling 3 | 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | */ 9 | 10 | /******* 11 | * Base 12 | *******/ 13 | .padding-80 { padding: 80px; } 14 | .padding-top-80 { padding-top: 80px; } 15 | .padding-bottom-80 { padding-bottom: 80px; } 16 | .padding-left-80 { padding-left: 80px; } 17 | .padding-right-80 { padding-right: 80px; } 18 | .padding-vertical-80 { padding-top: 80px; padding-bottom: 80px; } 19 | .padding-horizontal-80 { padding-left: 80px; padding-right: 80px; } 20 | 21 | .padding-40 { padding: 40px; } 22 | .padding-top-40 { padding-top: 40px; } 23 | .padding-bottom-40 { padding-bottom: 40px; } 24 | .padding-left-40 { padding-left: 40px; } 25 | .padding-right-40 { padding-right: 40px; } 26 | .padding-vertical-40 { padding-top: 40px; padding-bottom: 40px; } 27 | .padding-horizontal-40 { padding-left: 40px; padding-right: 40px; } 28 | 29 | .padding-20 { padding: 20px; } 30 | .padding-top-20 { padding-top: 20px; } 31 | .padding-bottom-20 { padding-bottom: 20px; } 32 | .padding-left-20 { padding-left: 20px; } 33 | .padding-right-20 { padding-right: 20px; } 34 | .padding-vertical-20 { padding-top: 20px; padding-bottom: 20px; } 35 | .padding-horizontal-20 { padding-left: 20px; padding-right: 20px; } 36 | .padding-0 { padding: 0; } 37 | .margin-0 { margin: 0 !important; } 38 | 39 | .font-300 { font-weight: 300; } 40 | .font-400 { font-weight: 400; } 41 | .font-500 { font-weight: 500; } 42 | .font-700 { font-weight: 700; } 43 | .font-italic { font-style: italic; } 44 | 45 | .font-size-12 { font-size: 12px !important; } 46 | .font-size-16 { font-size: 16px !important; } 47 | .font-size-18 { font-size: 18px !important; } 48 | .font-size-24 { font-size: 24px !important; } 49 | 50 | .text-upper { text-transform: uppercase !important; } 51 | .text-no-transform { text-transform: none !important; } 52 | 53 | .inline-block { display: inline-block !important; } 54 | .vertical-middle { vertical-align: middle; } 55 | .position-relative { position: relative; } 56 | .overflow-hidden { overflow: hidden; } 57 | 58 | /********* 59 | * Layout 60 | *********/ 61 | /* Loader */ 62 | #loader { 63 | overflow-x: hidden; 64 | overflow-y: hidden; 65 | vertical-align: middle; 66 | background: #fdfdfd; /* Old browsers */ 67 | /* IE9 SVG, needs conditional override of 'filter' to 'none' */ 68 | background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZkZmRmZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmN2Y3ZjciIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+); 69 | background: -moz-linear-gradient(top, #fdfdfd 0%, #f7f7f7 100%); /* FF3.6+ */ 70 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fdfdfd), color-stop(100%, #f7f7f7)); /* Chrome,Safari4+ */ 71 | background: -webkit-linear-gradient(top, #fdfdfd 0%, #f7f7f7 100%); /* Chrome10+,Safari5.1+ */ 72 | background: -o-linear-gradient(top, #fdfdfd 0%, #f7f7f7 100%); /* Opera 11.10+ */ 73 | background: -ms-linear-gradient(top, #fdfdfd 0%, #f7f7f7 100%); /* IE10+ */ 74 | background: linear-gradient(to bottom, #fdfdfd 0%, #f7f7f7 100%); /* W3C */ 75 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdfdfd', endColorstr='#f7f7f7', GradientType=0); /* IE6-8 */ 76 | position: fixed; 77 | display: table; 78 | width: 100%; 79 | top: 0; 80 | height: 100%; 81 | min-height: 100%; 82 | z-index: 100000; 83 | } 84 | 85 | .loader-container { 86 | position: relative; 87 | display: table-cell; 88 | vertical-align: middle; 89 | z-index: 12; 90 | text-align: center; 91 | } 92 | 93 | body { overflow: hidden; } 94 | 95 | /* Debug toolbar */ 96 | #djDebug #djDebugToolbarHandle { top: 52px !important; } 97 | 98 | /* Navbars */ 99 | .navbar.affix { 100 | width: 100%; 101 | top: 0; 102 | right: 0; 103 | padding: 0; 104 | margin: 0; 105 | position: fixed; 106 | z-index: 10000; 107 | -webkit-transition: all 0.8s; 108 | -moz-transition: all 0.8s; 109 | transition: all 0.8s; 110 | } 111 | 112 | .navbar.affix-top { margin: 0; } 113 | body.toolbar #header.navbar.affix { top: 50px; } 114 | 115 | 116 | /* Top link */ 117 | #top-link { 118 | display: none; 119 | position: fixed; 120 | right: 20px; 121 | bottom: 60px; 122 | padding: 12px 12px 8px; 123 | background: url('images/toplink.png') no-repeat center; 124 | color: #fff; 125 | font-size: 18px; 126 | font-weight: 400; 127 | text-decoration: none; 128 | z-index: 100; 129 | } 130 | 131 | .page-unpublished #content { background: #e4b9b9; } 132 | 133 | /******* 134 | * Menu 135 | *******/ 136 | .language.menu button { 137 | border: none; 138 | background: none; 139 | color: #fff; 140 | padding: 15px; 141 | } 142 | 143 | .language.menu.flag button { padding: 15px 5px; } 144 | .language.menu { padding-left: 15px; } 145 | -------------------------------------------------------------------------------- /ninecms/templates/admin/ninecms/image/stacked.html: -------------------------------------------------------------------------------- 1 | {% load i18n admin_urls admin_static bootstrapped_goodies_tags ninecms_extras %} 2 | {% comment %} 3 | 4 | Template for inline form of Node images 5 | Most of the template is the same as /admin/edit_inline/stacked.html except for a row with two columns added 6 | 7 | Author: George Karakostas 8 | Copyright: Copyright 2015, George Karakostas 9 | Licence: BSD-3 10 | Email: gkarak@9-dev.com 11 | 12 | {% endcomment %} 13 |
14 |

{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}

15 | {{ inline_admin_formset.formset.management_form }} 16 | {% if inline_admin_formset.formset.non_form_errors %} 17 |
18 | {{ inline_admin_formset.formset.non_form_errors }} 19 |
20 | {% endif %} 21 | 22 |
23 | {% for inline_admin_form in inline_admin_formset %} 24 |
25 | 26 | {% if not forloop.last %} 27 | 28 | {% endif %} 29 | {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% trans "Change" %}{% endif %}{% else %}#{{ forloop.counter }}{% endif %} ({{ inline_admin_formset.opts.verbose_name|capfirst }}) 30 | {% if not forloop.last %} 31 | 32 | {% if inline_admin_formset.opts.sortable_field_name %} 33 | 34 | {% endif %} 35 | 36 | {% endif %} 37 | {% if inline_admin_form.show_url %}{% trans "View on site" %}{% endif %} 38 |
39 | {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}
{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}
{% endif %} 40 |
41 |
42 | {% for fieldset in inline_admin_form %}{% for line in fieldset %} 43 | {% if line.errors %} 44 | {% for field in line %} 45 |
{{ field.field.label }}: {{ field.errors|striptags }}
46 | {% endfor %} 47 | {% endif %} 48 | {% endfor %}{% endfor %} 49 | 50 |
51 |
52 |
53 | {% if inline_admin_form.form.non_field_errors %} 54 |
55 | {{ inline_admin_form.form.non_field_errors }} 56 |
57 | {% endif %} 58 | {% with stacked_prefix=forloop.counter %} 59 | {% for fieldset in inline_admin_form %} 60 | {% include "admin/includes/fieldset.html" with group_column_width=fieldset|fieldset_column_width %} 61 | {% endfor %} 62 | {% endwith %} 63 | {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} 64 | {{ inline_admin_form.fk_field.field }} 65 |
66 |
67 |
68 | {% if inline_admin_form.form.image.value %} 69 |
70 | 71 |
72 | {% endif %} 73 |
74 |
75 |
76 | {% endfor %} 77 |
78 |
79 | 80 | -------------------------------------------------------------------------------- /ninecms/templates/admin/ninecms/node/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load i18n admin_urls admin_static admin_modify %} 3 | 4 | {% comment %} 5 | Template for Node edit form: add CKEditor 6 | Author: George Karakostas 7 | Copyright: Copyright 2015, George Karakostas 8 | Licence: BSD-3 9 | Email: gkarak@9-dev.com 10 | {% endcomment %} 11 | 12 | {% block admin_change_form_document_ready %} 13 | {{ block.super }} 14 | {% include 'ninecms/ckeditor.html' %} 15 | {% endblock %} -------------------------------------------------------------------------------- /ninecms/templates/admin/ninecms/node/change_list.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_list.html" %} 2 | {% load ninecms_extras %} 3 | 4 | {% comment %} 5 | Template for Node list: add clear cache action 6 | Author: George Karakostas 7 | Copyright: Copyright 2015, George Karakostas 8 | Licence: BSD-3 9 | Email: gkarak@9-dev.com 10 | {% endcomment %} 11 | 12 | {% block object-tools-items %} 13 | {{ block.super }} 14 | {% if user.is_superuser %} 15 |
  •  
  • 16 |
  • 17 |
    18 | {% csrf_token %} 19 | 22 |
    23 |
  • 24 | {% endif %} 25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /ninecms/templates/admin/ninecms/pagetype/change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/change_form.html" %} 2 | {% load i18n admin_urls admin_static admin_modify %} 3 | 4 | {% comment %} 5 | Template for Page type form: add action link to edit permissions 6 | Author: George Karakostas 7 | Copyright: Copyright 2015, George Karakostas 8 | Licence: BSD-3 9 | Email: gkarak@9-dev.com 10 | {% endcomment %} 11 | 12 | {% block object-tools-items %} 13 |
  • {% trans "Permissions" %}
  • 14 | {{ block.super }} 15 | {% endblock %} -------------------------------------------------------------------------------- /ninecms/templates/admin/ninecms/pagetype/perms_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/base_site.html' %} 2 | {% load i18n ninecms_extras %} 3 | 4 | {% comment %} 5 | Edit Page type permissions 6 | Author: George Karakostas 7 | Copyright: Copyright 2015, George Karakostas 8 | Licence: BSD-3 9 | Email: gkarak@9-dev.com 10 | {% endcomment %} 11 | 12 | {% block title %}{% trans "Edit permissions for page type" %} {{ page_type.name }}{% endblock %} 13 | 14 | {% if not is_popup %} 15 | {% block breadcrumbs %} 16 | 22 | {% endblock %} 23 | {% endif %} 24 | 25 | {% block object-tools %} 26 | {% if not is_popup %} 27 | 35 | {% endif %} 36 | {% endblock %} 37 | 38 | {% block content %} 39 |
    40 | {% csrf_token %} 41 |
    42 | {% trans "Permissions" as permissions_label %} 43 | {% fieldset permissions_label %} 44 |
    45 |
    {% field permissions_form.add_node %}
    46 |
    {% field permissions_form.change_node %}
    47 |
    {% field permissions_form.delete_node %}
    48 |
    49 | {% if not groups %} 50 |

    No user groups available.

    51 | {% endif %} 52 | {% endfieldset %} 53 |
    54 |
    55 |
    56 | 57 |
    58 |
    59 |
    60 | {% endblock content %} 61 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/base.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% load ninecms_extras %} 3 | {% load i18n %} 4 | {% get_current_language as LANGUAGE_CODE %} 5 | {% comment %} 6 | 7 | Base template 8 | Author: George Karakostas 9 | Copyright: Copyright 2015, George Karakostas 10 | Licence: BSD-3 11 | Email: gkarak@9-dev.com 12 | 13 | {% endcomment %} 14 | 15 | {# #} 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% block title %}{{ title }}{% endblock %} 23 | {% block meta %} 24 | {% if node.summary %}{% endif %} 25 | 26 | 27 | 28 | {% endblock %} 29 | {% block head %} 30 | 31 | 32 | {% endblock head %} 33 | 34 | 35 | 36 | {# #} 37 | {% block body_top %}^{% endblock %} 38 | 39 | {% block body_loader %} 40 |
    41 |
    42 |
    43 | {% block site_name %}{% endblock %} 44 |
    45 |
    46 |
    47 | {% endblock %} 48 | 49 | 50 | 51 |
    52 | {% block content %}{% endblock %} 53 |
    54 | 55 | {# #} 56 | {% block body_bottom %}{% endblock %} 57 | {% block body_scripts %} 58 | 59 | {% endblock %} 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_contact.html: -------------------------------------------------------------------------------- 1 | {% load i18n ninecms_extras %} 2 | {% comment %} 3 | Block template for contact 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 |
    10 |
    11 |

    {% trans "Contact" %}

    12 |
    13 |
    14 | {% csrf_token %} 15 | {% include 'ninecms/form_non_field_errors.html' with errors=form.non_field_errors only %} 16 | {% field form.sender_name %} 17 | {% field form.sender_email %} 18 | {% field form.subject %} 19 | {% field form.message %} 20 | 21 | 22 |
    23 |
    24 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_content.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Block template for content 3 | Author: George Karakostas 4 | Copyright: Copyright 2015, George Karakostas 5 | Licence: BSD-3 6 | Email: gkarak@9-dev.com 7 | {% endcomment %} 8 |
    9 | {% include 'ninecms/block_static.html' %} 10 |
    11 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_language.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load staticfiles %} 3 | {% comment %} 4 | 5 | Block template for language menu 6 | Author: George Karakostas 7 | Copyright: Copyright 2015, George Karakostas 8 | Licence: BSD-3 9 | Email: gkarak@9-dev.com 10 | 11 | http://stackoverflow.com/a/30779618/940098 12 | {% endcomment %} 13 |
    14 | {% csrf_token %} 15 | 16 | 46 |
    47 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_login.html: -------------------------------------------------------------------------------- 1 | {% load i18n ninecms_extras %} 2 | {% comment %} 3 | 4 | Block template for login 5 | Author: George Karakostas 6 | Copyright: Copyright 2015, George Karakostas 7 | Licence: BSD-3 8 | Email: gkarak@9-dev.com 9 | 10 | {% endcomment %} 11 | {% if not user.is_authenticated %} 12 |
    13 |
    14 |

    {% trans "Login" %}

    15 |
    16 |
    17 | {% csrf_token %} 18 | {% include 'ninecms/form_non_field_errors.html' with errors=form.non_field_errors only %} 19 | {% field form.username %} 20 | {% field form.password %} 21 | 22 | 23 |
    24 |
    25 |

    {% trans "Create new account" %}

    26 |

    {% trans "Recover password" %}

    27 |
    28 | {% else %} 29 |
    30 | {% include 'ninecms/form_logout.html' %} 31 |
    32 | {% endif %} 33 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_menu.html: -------------------------------------------------------------------------------- 1 | {% load mptt_tags %} 2 | {% load i18n %} 3 | {% get_current_language as LANGUAGE_CODE %} 4 | {% comment %} 5 | Block template for menu 6 | Author: George Karakostas 7 | Copyright: Copyright 2015, George Karakostas 8 | Licence: BSD-3 9 | Email: gkarak@9-dev.com 10 | {% endcomment %} 11 | 31 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_menu_breadcrumbs.html: -------------------------------------------------------------------------------- 1 | {% load mptt_tags %} 2 | {% load ninecms_extras %} 3 | {% comment %} 4 | 5 | Block template for menu as breadcrumbs 6 | The menu is expected to be the children of a menu item, of a menu block. 7 | 8 | Author: George Karakostas 9 | Copyright: Copyright 2015, George Karakostas 10 | Licence: BSD-3 11 | Email: gkarak@9-dev.com 12 | 13 | {% endcomment %} 14 | 33 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_menu_header.html: -------------------------------------------------------------------------------- 1 | {% load mptt_tags %} 2 | {% load i18n %} 3 | {% load ninecms_extras %} 4 | {% get_current_language as LANGUAGE_CODE %} 5 | {% comment %} 6 | 7 | Block template for menu in header region 8 | The menu is expected to be the children of a menu item, of a menu block. 9 | 10 | Author: George Karakostas 11 | Copyright: Copyright 2015, George Karakostas 12 | Licence: BSD-3 13 | Email: gkarak@9-dev.com 14 | 15 | {% endcomment %} 16 | 50 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_search.html: -------------------------------------------------------------------------------- 1 | {% load ninecms_extras %} 2 | {% comment %} 3 | 4 | Block template for search 5 | Author: George Karakostas 6 | Copyright: Copyright 2015, George Karakostas 7 | Licence: BSD-3 8 | Email: gkarak@9-dev.com 9 | 10 | {% endcomment %} 11 | 17 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_search_results.html: -------------------------------------------------------------------------------- 1 | {% load ninecms_extras %} 2 | {% comment %} 3 | 4 | Block template for search results 5 | Author: George Karakostas 6 | Copyright: Copyright 2015, George Karakostas 7 | Licence: BSD-3 8 | Email: gkarak@9-dev.com 9 | 10 | {% endcomment %} 11 |
    12 | {% if results.q %}

    Search results for {{ results.q }}

    {% endif %} 13 | {% if results.nodes %} 14 | {% for result in results.nodes %} 15 |

    {{ result }}

    16 | {% if result.summary %}{{ result.summary|safe }}{% else %}{{ result.body|safe }}{% endif %} 17 | {% endfor %} 18 | {% else %} 19 |

    No results found.

    20 | {% endif %} 21 |
    22 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_signal.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Block template for signal 3 | If this is shown then a signal template is missing. 4 | 5 | Author: George Karakostas 6 | Copyright: Copyright 2015, George Karakostas 7 | Licence: BSD-3 8 | Email: gkarak@9-dev.com 9 | {% endcomment %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_signal_terms.html: -------------------------------------------------------------------------------- 1 | {% load mptt_tags %} 2 | {% comment %} 3 | Block template for view: terms 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 |
  • Terms 10 | 22 |
  • -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_static.html: -------------------------------------------------------------------------------- 1 | {% load ninecms_extras %} 2 | {% comment %} 3 | Block template for static content 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 |
    10 |
    {{ node.body|safe }}
    11 | {% if node.image_set.all %} 12 |
    13 | {% for img in node.image_set.all %} 14 |
    15 | {{ img.title }} 16 |
    17 | {% endfor %} 18 |
    19 | {% endif %} 20 | {# Attention: it is recommended that this is disabled and added on particular templates only (causes db hit) #} 21 | {% if node.video_set.all %} 22 | 37 | {% endif %} 38 |
    39 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/block_user_menu.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% comment %} 3 | Block template for user menu 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 | 17 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/ckeditor.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% comment %} 3 | CKEditor template 4 | 5 | For toolbar layout edit ckeditor/config.js 6 | http://docs.ckeditor.com/#!/guide/dev_toolbarconcepts 7 | http://docs.ckeditor.com/#!/guide/dev_howtos_styles 8 | 9 | Author: George Karakostas 10 | Copyright: Copyright 2015, George Karakostas 11 | Licence: BSD-3 12 | Email: gkarak@9-dev.com 13 | 14 | {% endcomment %} 15 | 16 | 45 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/field.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Field template 3 | Author: George Karakostas 4 | Copyright: Copyright 2015, George Karakostas 5 | Licence: BSD-3 6 | Email: gkarak@9-dev.com 7 | {% endcomment %} 8 |
    9 | {{ field.label_tag }} 10 | {% if field.field.required %}*{% endif %} 11 | {{ field }} 12 |
    {{ field.help_text }}
    13 | {% if field.errors %}{% endif %} 14 |
    15 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/fieldset.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Fieldset template 3 | Author: George Karakostas 4 | Copyright: Copyright 2015, George Karakostas 5 | Licence: BSD-3 6 | Email: gkarak@9-dev.com 7 | {% endcomment %} 8 |
    9 |
    {{ name }}
    10 |
    {{ var }}
    11 |
    12 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/form_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends 'ninecms/base.html' %} 2 | {% comment %} 3 | Data manipulation confirm generic form 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | 9 | {% endcomment %} 10 | 11 | {% block title %}{{ title|striptags }} | 9cms{% endblock %} 12 | 13 | {% block content %} 14 |
    15 | 16 | {% include 'ninecms/messages.html' %} 17 |

    {{ prompt }}

    18 |
    19 | {% csrf_token %} 20 | 21 | Cancel 22 |
    23 |
    24 | {% endblock content %} 25 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/form_logout.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Form template for logout 3 | Author: George Karakostas 4 | Copyright: Copyright 2015, George Karakostas 5 | Licence: BSD-3 6 | Email: gkarak@9-dev.com 7 | {% endcomment %} 8 |
    9 | {% csrf_token %} 10 | 11 | {% include 'ninecms/form_non_field_errors.html' with errors=form.non_field_errors only %} 12 | 13 |
    14 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/form_non_field_errors.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Messages template for non-field errors 3 | 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 | 10 | {% if errors %} 11 |
    12 | {% for error in errors %} 13 | 14 | {% endfor %} 15 |
    16 | {% endif %} 17 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/glyphicon.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'ninecms/base.html' %} 2 | 3 | {% comment %} 4 | Content page 5 | Author: George Karakostas 6 | Copyright: Copyright 2015, George Karakostas 7 | Licence: BSD-3 8 | Email: gkarak@9-dev.com 9 | {% endcomment %} 10 | 11 | {% block content %} 12 | 31 | 34 |
    35 | 38 | {% include 'ninecms/messages.html' %} 39 |
    40 | {% block main %}{% endblock %} 41 |
    42 |
    43 | 44 | {% block content_below %}{% endblock %} 45 | 46 | 51 | {% endblock content %} 52 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/mail_contact.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% comment %} 3 | Mail template for contact 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 | {{ sender_name|striptags }} <{{ sender_email|striptags }}> {% trans "sent a message using the contact form" %}. 10 | 11 | {{ message|striptags }} 12 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/mail_updates.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% comment %} 3 | Mail template for contact 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | {% endcomment %} 9 | {% trans "There are security updates available for your web site" %}. 10 | {% trans "To ensure the security of your server, you should update" %}. 11 | {% trans "The following updates are available" %}: 12 | 13 | {% for update in updates %}{{ update }} 14 | {% endfor %} 15 | {% trans "See the status page for more information" %}. 16 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/messages.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Messages template 3 | 4 | Author: George Karakostas 5 | Copyright: Copyright 2015, George Karakostas 6 | Licence: BSD-3 7 | Email: gkarak@9-dev.com 8 | 9 | {% endcomment %} 10 | {% if messages %} 11 |
    12 | {% for message in messages %} 13 | 19 | {% endfor %} 20 |
    21 | {% endif %} 22 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/pagination.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Paginator template 3 | Author: George Karakostas 4 | Copyright: Copyright 2015, George Karakostas 5 | Licence: BSD-3 6 | Email: gkarak@9-dev.com 7 | {% endcomment %} 8 | {% if is_paginated %} 9 | 42 | {% endif %} 43 | -------------------------------------------------------------------------------- /ninecms/templates/ninecms/robots.txt: -------------------------------------------------------------------------------- 1 | # 2 | # robots.txt 3 | # 4 | # This file is to prevent the crawling and indexing of certain parts 5 | # of the site by web crawlers and spiders run by sites like Google. 6 | # By telling these "robots" where not to go on the site, bandwidth 7 | # and server resources are saved. 8 | # 9 | # This file will be ignored unless it is at the root of the host: 10 | # Used: http://example.com/robots.txt 11 | # Ignored: http://example.com/site/robots.txt 12 | # 13 | # For more information about the robots.txt standard, see: 14 | # http://www.robotstxt.org/robotstxt.html 15 | 16 | User-agent: * 17 | Crawl-delay: 10 18 | # Paths 19 | Disallow: /admin/ 20 | -------------------------------------------------------------------------------- /ninecms/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | """ NineCMS custom template filters and tags """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | -------------------------------------------------------------------------------- /ninecms/templatetags/ninecms_extras.py: -------------------------------------------------------------------------------- 1 | """ NineCMS custom template filters and tags """ 2 | __author__ = 'George Karakostas' 3 | __copyright__ = 'Copyright 2015, George Karakostas' 4 | __licence__ = 'BSD-3' 5 | __email__ = 'gkarak@9-dev.com' 6 | 7 | from django import template 8 | from django.template.defaultfilters import stringfilter 9 | from django.template import Context 10 | from ninecms.utils.media import image_style as util_image 11 | from ninecms.utils.transliterate import upper_no_intonation as util_upper 12 | from ninecms.utils.nodes import get_clean_url 13 | from ninecms.utils import status 14 | 15 | 16 | register = template.Library() 17 | 18 | 19 | @register.filter 20 | def image_style(image, style): 21 | """ Return the url of different image style 22 | :param image: An image url 23 | :param style: Specify style to return image 24 | :return: image url of specified style 25 | """ 26 | return util_image(image, style) 27 | 28 | 29 | class FieldsetNode(template.Node): # pragma: nocover 30 | """ Fieldset renderer for 'fieldset' tag (see below) """ 31 | def __init__(self, nodelist, fieldset_name): 32 | """ Initialize renderer class 33 | https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#writing-the-renderer 34 | https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#passing-template-variables-to-the-tag 35 | :param nodelist: a list of the template nodes inside a block of 'fieldset' 36 | :param fieldset_name: the name of the fieldset 37 | :return: None 38 | """ 39 | self.nodelist = nodelist 40 | # if not in quotes, get variable from context 41 | if not (fieldset_name[0] == fieldset_name[-1] and fieldset_name[0] in ('"', "'")): # pragma: nocover 42 | self.fieldset_name = template.Variable(fieldset_name) 43 | self.fieldset_id = fieldset_name 44 | self.resolve = True 45 | else: 46 | self.fieldset_name = fieldset_name[1:-1] 47 | self.fieldset_id = self.fieldset_name 48 | self.resolve = False 49 | 50 | def render(self, context): 51 | """ Render the inside of a fieldset block based on template file 52 | https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#auto-escaping-considerations 53 | :param context: the previous template context 54 | :return: HTML string 55 | """ 56 | t = context.template.engine.get_template('ninecms/fieldset.html') 57 | return t.render(Context({ 58 | 'var': self.nodelist.render(context), 59 | 'name': self.fieldset_name.resolve(context) if self.resolve else self.fieldset_name, 60 | 'id': self.fieldset_id, 61 | }, autoescape=context.autoescape)) 62 | 63 | 64 | @register.tag 65 | def fieldset(parser, token): # pragma: nocover 66 | """ Compilation function for fieldset block tag 67 | Render a form fieldset 68 | *This is an aux tag that is not used and excluded from coverage tests* 69 | https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#writing-the-compilation-function 70 | https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#parsing-until-another-block-tag 71 | http://stackoverflow.com/a/30097784/940098 72 | :param parser: template parser 73 | :param token: tag name and variables 74 | :return: HTML string 75 | """ 76 | try: 77 | tag_name, fieldset_name = token.split_contents() 78 | except ValueError: # pragma: nocover 79 | raise template.TemplateSyntaxError("%r tag requires a single argument" % token.contents.split()[0]) 80 | nodelist = parser.parse(('endfieldset',)) 81 | parser.delete_first_token() 82 | return FieldsetNode(nodelist, fieldset_name) 83 | 84 | 85 | @register.inclusion_tag('ninecms/field.html') 86 | def field(field_var): 87 | """ Render a field based on template 88 | https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#inclusion-tags 89 | Possibly add parameter for custom classes 90 | :param field_var: the field variable 91 | :return: the template context 92 | """ 93 | return {'field': field_var} 94 | 95 | 96 | @register.filter 97 | def upper_no_intonation(s): 98 | """ Convert a string to uppercase, removing any intonation 99 | :param s: the string to convert 100 | :return: the converted string 101 | """ 102 | return util_upper(s) 103 | 104 | 105 | @register.filter 106 | def active_trail(menu, url): 107 | """ Get the active menu item based on url provided, and all of its ancestors 108 | To be used to check each individual node's path if in this list so to obtain the active trail 109 | Also remove language part from url if i18n urls are enabled 110 | :param menu: the parent menu 111 | :param url: the current url to check against for the active path (should be request.path) 112 | :return: a recordset of all active menu ancestors 113 | """ 114 | return menu.filter(path=get_clean_url(url)).get_ancestors(include_self=True) if menu else [] 115 | 116 | 117 | @register.filter 118 | def flatten(records, fld): 119 | """ Flatten a recordset to list of a particular field 120 | :param records: the recordset to flatten 121 | :param fld: the field from the records to include in list 122 | :return: a list 123 | """ 124 | return [path for fields in records.values_list(fld) for path in fields] if records else [] 125 | 126 | 127 | @register.filter 128 | @stringfilter 129 | def strip(string, char): # pragma: nocover 130 | """ Strip a specified character from a string 131 | Helper filter that should exist in Django, not currently used 132 | :param string: 133 | :param char: 134 | :return: stripped string 135 | """ 136 | return string.strip(char) 137 | 138 | @register.filter 139 | def check_path_active(node_path, request_path): 140 | """ Check that the two paths are equal, ignoring leading or trailing slashes 141 | Helper function for improving readability 142 | Mainly used in menu templates 143 | :param node_path: the menu item path 144 | :param request_path: the request path 145 | :return: boolean 146 | """ 147 | url = get_clean_url(request_path) 148 | return node_path == url or node_path == url.strip('/') 149 | 150 | @register.inclusion_tag('ninecms/glyphicon.html') 151 | def glyphicon(icon): 152 | """ Shorthand for bootstrap glyphicon markup 153 | :param icon: the icon to present, gets appended to glyphicon-{{ icon }} 154 | :return: the template context 155 | """ 156 | return {'icon': icon} 157 | 158 | @register.assignment_tag(takes_context=True) 159 | def get_status(context): 160 | return { 161 | 'version': status.version(), 162 | 'packages': status.packages(), 163 | 'updates': status.updates(), 164 | 'django_check': status.django_check(), 165 | 'migrations': status.django_migrations(), 166 | 'permissions': status.permissions_status(), 167 | 'imagemagick': status.imagemagick_status(), 168 | 'user_stats': status.user_stat(context['request'].user), 169 | } 170 | -------------------------------------------------------------------------------- /ninecms/tests/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'gkarak' 2 | -------------------------------------------------------------------------------- /ninecms/tests/tests_content_i18n.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests declaration for Nine CMS 3 | 4 | All tests assume settings.LANGUAGE_CODE is defined 5 | """ 6 | __author__ = 'George Karakostas' 7 | __copyright__ = 'Copyright 2015, George Karakostas' 8 | __licence__ = 'BSD-3' 9 | __email__ = 'gkarak@9-dev.com' 10 | 11 | from django.test import TestCase 12 | from django.core.urlresolvers import reverse 13 | from django.utils import translation 14 | from django.conf import settings 15 | from ninecms.tests.setup import get_second_language, create_front, create_basic, create_block_static, create_menu, \ 16 | create_block_menu, assert_front, assert_basic, assert_menu 17 | 18 | 19 | class ContentI18nTests(TestCase): 20 | """ Tests with default initial content, i18n, no login """ 21 | @classmethod 22 | def setUpTestData(cls): 23 | """ Setup initial data: 24 | Create 2 front pages 25 | Create 2 basic pages 26 | :return: None 27 | """ 28 | cls.second_lang = get_second_language() 29 | cls.node_rev_front_first = create_front('/', settings.LANGUAGE_CODE) 30 | cls.node_rev_front_sec = create_front('/', cls.second_lang) 31 | cls.node_rev_basic_first = create_basic('about', settings.LANGUAGE_CODE) 32 | cls.node_rev_basic_sec = create_basic('about', cls.second_lang) 33 | for i in range(0, 3): 34 | node_rev_basic_first = create_basic('block/' + str(i), settings.LANGUAGE_CODE, '1st lang ' + str(i)) 35 | node_rev_basic_second = create_basic('block/' + str(i), cls.second_lang, '2nd lang ' + str(i)) 36 | create_block_static(cls.node_rev_front_first.node.page_type, node_rev_basic_first.node) 37 | # same page type for both 38 | create_block_static(cls.node_rev_front_first.node.page_type, node_rev_basic_second.node) 39 | cls.menu_en = create_menu('en') 40 | cls.menu_el = create_menu('el') 41 | create_block_menu(cls.node_rev_front_first.node.page_type, cls.menu_en) 42 | create_block_menu(cls.node_rev_front_first.node.page_type, cls.menu_el) 43 | 44 | """ Node System """ 45 | def test_node_model_methods(self): 46 | """ Test model methods 47 | :return: None 48 | """ 49 | lang = '' 50 | if settings.I18N_URLS: # pragma: nocover 51 | lang = '/' + settings.LANGUAGE_CODE 52 | self.assertEqual(str(self.node_rev_front_first.node.get_absolute_url()), lang + '/') 53 | self.assertEqual(str(self.node_rev_basic_first.node.get_absolute_url()), lang + '/about/') 54 | 55 | def test_node_view_with_front_i18n(self): 56 | """ Test front page with multiple languages 57 | :return: None 58 | """ 59 | translation.activate(settings.LANGUAGE_CODE) 60 | assert_front(self, reverse('ninecms:index')) 61 | # translation.activate needs to happen before reverse for non-default language 62 | translation.activate(self.second_lang) 63 | assert_front(self, reverse('ninecms:index'), self.second_lang) 64 | 65 | def test_node_view_with_basic_i18n(self): 66 | """ Test basic page with multiple languages 67 | :return: None 68 | """ 69 | assert_basic(self, 'about/') 70 | assert_basic(self, 'about/', 'alias', self.second_lang) 71 | 72 | """ Block System """ 73 | def test_node_view_block_static_i18n(self): 74 | """ Test static block for i18n front view 75 | Change in v0.2: require block for each language 76 | :return: None 77 | """ 78 | translation.activate(settings.LANGUAGE_CODE) 79 | response = assert_front(self, reverse('ninecms:index')) 80 | for i in range(0, 3): 81 | self.assertContains(response, '
    1st lang ' + str(i) + ' page.
    ', html=True) 82 | if settings.I18N_URLS: # pragma: nocover 83 | self.assertNotContains(response, '
    2nd lang ' + str(i) + ' page.
    ', html=True) 84 | translation.activate(self.second_lang) 85 | response = assert_front(self, reverse('ninecms:index'), self.second_lang) 86 | for i in range(0, 3): 87 | if settings.I18N_URLS: # pragma: nocover 88 | self.assertNotContains(response, '
    1st lang ' + str(i) + ' page.
    ', html=True) 89 | self.assertContains(response, '
    2nd lang ' + str(i) + ' page.
    ', html=True) 90 | 91 | def test_node_view_block_menu_i18n(self): 92 | """ Test menu block for i18n front view 93 | :return: None 94 | """ 95 | translation.activate(settings.LANGUAGE_CODE) 96 | response = assert_front(self, reverse('ninecms:index')) 97 | assert_menu(self, response) 98 | translation.activate(self.second_lang) 99 | response = assert_front(self, reverse('ninecms:index'), self.second_lang) 100 | assert_menu(self, response, self.second_lang) 101 | -------------------------------------------------------------------------------- /ninecms/tests/tests_content_login_simple.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests declaration for Nine CMS 3 | 4 | All tests assume settings.LANGUAGE_CODE is defined 5 | """ 6 | __author__ = 'George Karakostas' 7 | __copyright__ = 'Copyright 2015, George Karakostas' 8 | __licence__ = 'BSD-3' 9 | __email__ = 'gkarak@9-dev.com' 10 | 11 | from django.test import TestCase 12 | from django.contrib.auth.models import Permission, Group 13 | from django.core.urlresolvers import reverse 14 | from ninecms.tests.setup import create_front, create_basic, create_simple_user, create_image, data_node 15 | from ninecms.utils.perms import set_perms 16 | from ninecms.forms import ContentTypePermissionsForm, ContentNodeEditForm 17 | 18 | 19 | class ContentLoginSimpleTests(TestCase): 20 | """ Tests for access, with content, with login from simple user 21 | The first page (front) is allowed to be edited by simple user 22 | The second is not. 23 | """ 24 | @classmethod 25 | def setUpTestData(cls): 26 | """ Setup initial data: 27 | Create front page 28 | Create basic page 29 | Create simple user 30 | Create image 31 | :return: None 32 | """ 33 | cls.node_rev_front = create_front('/') 34 | cls.node_rev_basic = create_basic('about') 35 | cls.simple_user = create_simple_user() 36 | cls.simple_group = Group.objects.create(name='editor') 37 | cls.simple_user.groups.add(cls.simple_group) 38 | perms = Permission.objects.filter(codename__in=['add_node', 'change_node']) 39 | cls.simple_user.user_permissions.add(*perms) 40 | cls.default_perms = { 41 | 'change_node': [cls.simple_group], 42 | 'delete_node': [], 43 | 'add_node': [cls.simple_group], 44 | } 45 | cls.fields = list(ContentTypePermissionsForm().fields.keys()) 46 | cls.img = create_image() 47 | 48 | def setUp(self): 49 | """ Setup each test: login 50 | :return: None 51 | """ 52 | self.client.login(username='editor', password='1234') 53 | 54 | """ Admin index """ 55 | def test_admin_index_page(self): 56 | """ Test status page 57 | :return: None 58 | """ 59 | response = self.client.get(reverse('admin:index')) 60 | self.assertContains(response, "administration") 61 | self.assertContains(response, '') 62 | self.assertContains(response, '') 63 | self.assertContains(response, '') 64 | self.assertContains(response, '') 65 | self.assertNotContains(response, '') 66 | self.assertNotContains(response, '') 67 | self.assertNotContains(response, "Utilities") 68 | 69 | """ Nodes """ 70 | def test_admin_node_changelist_page(self): 71 | """ Test view /admin/ninecms/node/ properly 72 | :return: None 73 | """ 74 | response = self.client.get(reverse('admin:ninecms_node_changelist')) 75 | self.assertEqual(response.status_code, 403) 76 | perms = {'add_node': [self.simple_group], 'change_node': [self.simple_group], 'delete_node': []} 77 | obj = self.node_rev_basic.node.page_type 78 | set_perms(obj, self.fields, '_pagetype', perms) 79 | response = self.client.get(reverse('admin:ninecms_node_changelist')) 80 | self.assertContains(response, "Basic Page") 81 | self.assertNotContains(response, "Clear cache") 82 | self.assertNotContains(response, '