Jelajahi Sumber

Enhancing project template (#58)

* Enhancing coderedcms command and project template
Vince Salvino 6 tahun lalu
induk
melakukan
b5135f3588

+ 3 - 1
README.md

@@ -21,7 +21,9 @@
 ## Quick start
 1. Run `pip install coderedcms`
 
-2. Run `coderedcms start mysite`
+2. Run `coderedcms start mysite --sitename "My Company Inc." --domain example.com`
+
+    *Note: `--sitename` and `--domain` are optional to pre-populate settings of your website.*
 
 3. Enter the project `cd mysite/`
 

+ 63 - 55
coderedcms/bin/coderedcms.py

@@ -1,9 +1,10 @@
 #!/usr/bin/env python
 import os
 import sys
-from argparse import ArgumentParser
 
 from django.core.management import ManagementUtility
+from django.core.management.templates import TemplateCommand
+from django.core.management.utils import get_random_secret_key
 
 
 CURRENT_PYTHON = sys.version_info[:2]
@@ -14,44 +15,23 @@ if CURRENT_PYTHON < REQUIRED_PYTHON:
     sys.exit(1)
 
 
-class Command:
-    description = None
-
-    def create_parser(self, command_name=None):
-        if command_name is None:
-            prog = None
-        else:
-            # hack the prog name as reported to ArgumentParser to include the command
-            prog = "%s %s" % (prog_name(), command_name)
-
-        parser = ArgumentParser(
-            description=getattr(self, 'description', None), add_help=False, prog=prog
-        )
-        self.add_arguments(parser)
-        return parser
+class CreateProject(TemplateCommand):
+    """
+    Based on django.core.management.startproject
+    """
+    help = "Creates the directory structure for a new CodeRed CMS project."
+    missing_args_message = "You must provide a project name."
 
     def add_arguments(self, parser):
-        pass
-
-    def print_help(self, command_name):
-        parser = self.create_parser(command_name=command_name)
-        parser.print_help()
-
-    def execute(self, argv):
-        parser = self.create_parser()
-        options = parser.parse_args(sys.argv[2:])
-        options_dict = vars(options)
-        self.run(**options_dict)
-
+        parser.add_argument('--sitename', help='Human readable name of your website or brand, e.g. "Mega Corp Inc."')
+        parser.add_argument('--domain', help='Domain that will be used for your website in production, e.g. "www.example.com"')
+        super().add_arguments(parser)
 
-class CreateProject(Command):
-    description = "Creates the directory structure for a new CodeRed CMS project."
+    def handle(self, **options):
+        # pop standard args
+        project_name = options.pop('name')
+        target = options.pop('directory')
 
-    def add_arguments(self, parser):
-        parser.add_argument('project_name', help="Name for your CodeRed CMS project")
-        parser.add_argument('dest_dir', nargs='?', help="Destination directory inside which to create the project")
-
-    def run(self, project_name=None, dest_dir=None):
         # Make sure given name is not already in use by another python package/module.
         try:
             __import__(project_name)
@@ -62,32 +42,60 @@ class CreateProject(Command):
                      "Python module and cannot be used as a project "
                      "name. Please try another name." % project_name)
 
-        print("Creating a CodeRed CMS project called %(project_name)s" % {'project_name': project_name})  # noqa
-
-        # Create the project from the Wagtail template using startapp
+        # Create a random SECRET_KEY to put it in the main settings.
+        options['secret_key'] = get_random_secret_key()
 
-        # First find the path to Wagtail
+        # Add custom args
         import coderedcms
         codered_path = os.path.dirname(coderedcms.__file__)
         template_path = os.path.join(codered_path, 'project_template')
+        options['template'] = template_path
+        options['extensions'] = ['py', 'html', 'rst', 'md']
+        options['files'] = ['Dockerfile']
 
-        # Call django-admin startproject
-        utility_args = ['django-admin.py',
-                        'startproject',
-                        '--template=' + template_path,
-                        '--ext=html,rst',
-                        '--name=Dockerfile',
-                        project_name]
+        # Set options
+        message = "Creating a CodeRed CMS project called %(project_name)s"
 
-        if dest_dir:
-            utility_args.append(dest_dir)
+        if options.get('sitename'):
+            message += " for %(sitename)s"
+        else:
+            options['sitename'] = project_name
+
+        if options.get('domain'):
+            message += " (%(domain)s)"
+            # Stip protocol out of domain if it is present.
+            options['domain'] = options['domain'].split('://')[-1]
+            # Figure out www logic.
+            if options['domain'].startswith('www.'):
+                options['domain_nowww'] = options['domain'].split('www.')[-1]
+            else:
+                options['domain_nowww'] = options['domain']
+        else:
+            options['domain'] = 'localhost'
+            options['domain_nowww'] = options['domain']
 
-        utility = ManagementUtility(utility_args)
-        utility.execute()
+        # Print a friendly message
+        print(message % {
+            'project_name': project_name,
+            'sitename': options.get('sitename'),
+            'domain': options.get('domain'),
+        })
 
-        print("Success! %(project_name)s has been created" % {'project_name': project_name})  # noqa
+        # Run command
+        super().handle('project', project_name, target, **options)
 
+        # Be a friend once again.
+        print("Success! %(project_name)s has been created" % {'project_name': project_name})
 
+        nextsteps = """
+Next steps:
+    1. cd %(directory)s/
+    2. python manage.py migrate
+    3. python manage.py createsuperuser
+    4. python manage.py runserver
+    5. Go to http://localhost:8000/admin/ and start editing!
+"""
+        print(nextsteps % {'directory': target if target else project_name})
 
 
 COMMANDS = {
@@ -103,7 +111,7 @@ def help_index():
     print("Type '%s help <subcommand>' for help on a specific subcommand.\n" % prog_name())  # NOQA
     print("Available subcommands:\n")  # NOQA
     for name, cmd in sorted(COMMANDS.items()):
-        print("    %s%s" % (name.ljust(20), cmd.description))  # NOQA
+        print("    %s%s" % (name.ljust(20), cmd.help))  # NOQA
 
 
 def unknown_command(command):
@@ -132,7 +140,7 @@ def main():
             unknown_command(help_command_name)
             return
 
-        command.print_help(help_command_name)
+        command.print_help(prog_name(), help_command_name)
         return
 
     try:
@@ -141,8 +149,8 @@ def main():
         unknown_command(command_name)
         return
 
-    command.execute(sys.argv)
+    command.run_from_argv(sys.argv)
 
 
 if __name__ == "__main__":
-    main()
+    main()

+ 9 - 18
coderedcms/project_template/.gitattributes

@@ -1,18 +1,9 @@
-# Set the default line ending behavior.
-* text eol=lf
-
-# Explicitly declare text files you want to always be normalized and converted
-# to native line endings on checkout.
-*.py text
-*.html text
-*.js text
-*.css text
-*.json text
-
-# Denote all files that are truly binary and should not be modified.
-*.png binary
-*.jpg binary
-*.jpeg binary
-*.gif binary
-*.pdf binary
-*.sqlite3 binary
+# Explicitly declare text files that should always be normalized and converted
+# to unix line endings, to reduce cross-platform development issues.
+*.py text eol=lf
+*.html text eol=lf
+*.js text eol=lf
+*.css text eol=lf
+*.json text eol=lf
+*.md text eol=lf
+*.rst text eol=lf

+ 198 - 0
coderedcms/project_template/.gitignore

@@ -0,0 +1,198 @@
+# Created by https://www.gitignore.io, modified for use with CodeRed CMS.
+
+
+### Django ###
+
+*.log
+*.pot
+*.pyc
+__pycache__/
+local_settings.py
+db.sqlite3
+
+# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
+# in your Git repository. Update and uncomment the following line accordingly.
+# <django-project-name>/staticfiles/
+
+
+### Django.Python Stack ###
+
+# Byte-compiled / optimized / DLL files
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+
+### OSX ###
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Windows ###
+
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+#### CodeRed CMS defaults ###
+
+# Cache
+cache/
+
+# File uploads from forms
+protected/
+
+# if you want to store original uploaded media files in version control,
+# replace "media/" with "media/images/"
+media/
+#media/images/

+ 1 - 1
coderedcms/project_template/Dockerfile

@@ -1,5 +1,5 @@
 FROM python:3.6
-LABEL maintainer="info@coderedcorp.com"
+LABEL maintainer="{{ project_name }}"
 
 ENV PYTHONUNBUFFERED 1
 ENV DJANGO_ENV dev

+ 20 - 0
coderedcms/project_template/README.md

@@ -0,0 +1,20 @@
+# {{ sitename }} website
+
+## Getting started
+
+Make sure Python 3.4 or higher is installed on your system.
+Open this directory in a command prompt, then:
+
+1. Install the software: `pip install -r requirements.txt`
+2. Run the development server: `python manage.py runserver`
+3. Go to http://localhost:8000/ in your browser, or http://localhost:8000/admin/ to log in and get to work!
+
+## Documentation links
+
+* To customize the content, design, and features of the site see [CodeRed CMS](https://docs.coderedcorp.com/cms/).
+* For deeper customization of backend code see [Wagtail](http://docs.wagtail.io/) and [Django](https://docs.djangoproject.com/).
+* For HTML template design see [Bootstrap](https://getbootstrap.com/).
+
+---
+
+Made with ♥ using [CodeRed CMS](https://www.coderedcorp.com/cms/)

+ 4 - 4
coderedcms/project_template/project_name/settings/base.py

@@ -74,8 +74,8 @@ MIDDLEWARE = [
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.security.SecurityMiddleware',
 
-    # Error reporting
-    'django.middleware.common.BrokenLinkEmailsMiddleware',
+    # Error reporting. Uncomment this to recieve emails when a 404 is triggered.
+    #'django.middleware.common.BrokenLinkEmailsMiddleware',
 
     # CMS functionality
     'wagtail.core.middleware.SiteMiddleware',
@@ -170,13 +170,13 @@ LOGIN_REDIRECT_URL = 'wagtailadmin_home'
 
 # Wagtail settings
 
-WAGTAIL_SITE_NAME = "{{ project_name }}"
+WAGTAIL_SITE_NAME = "{{ sitename }}"
 
 WAGTAIL_ENABLE_UPDATE_CHECK = False
 
 # Base URL to use when referring to full URLs within the Wagtail admin backend -
 # e.g. in notification emails. Don't include '/admin' or a trailing slash
-BASE_URL = 'http://example.com'
+BASE_URL = 'http://{{ domain }}'
 
 
 # Bootstrap

+ 1 - 1
coderedcms/project_template/project_name/settings/dev.py

@@ -13,6 +13,6 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 WAGTAIL_CACHE = False
 
 try:
-    from .local import *
+    from .local_settings import *
 except ImportError:
     pass

+ 14 - 10
coderedcms/project_template/project_name/settings/prod.py

@@ -7,24 +7,27 @@ DEBUG = False
 SECRET_KEY = '{{ secret_key }}'
 
 # Add your site's domain name(s) here.
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ['{{ domain }}']
 
 # To send email from the server, we recommend django_sendmail_backend
 # Or specify your own email backend such as an SMTP server.
+# https://docs.djangoproject.com/en/{{ docs_version }}/ref/settings/#email-backend
 EMAIL_BACKEND = 'django_sendmail_backend.backends.EmailBackend'
 
+# Default email address used to send messages from the website.
+DEFAULT_FROM_EMAIL = '{{ sitename }} <info@{{ domain_nowww }}>'
+
 # A list of people who get error notifications.
-ADMINS = [('Admin Name', 'admin@localhost')]
+ADMINS = [
+    ('Administrator', 'admin@{{ domain_nowww }}'),
+]
 
 # A list in the same format as ADMINS that specifies who should get broken link
-# notifications when BrokenLinkEmailsMiddleware is enabled.
+# (404) notifications when BrokenLinkEmailsMiddleware is enabled.
 MANAGERS = ADMINS
 
 # Email address used to send error messages to ADMINS.
-SERVER_EMAIL = '{{ project_name }}@localhost'
-
-# Default email address used to send messages from the website.
-DEFAULT_FROM_EMAIL = '{{ project_name}}@localhost'
+SERVER_EMAIL = DEFAULT_FROM_EMAIL
 
 #DATABASES = {
 #    'default': {
@@ -33,6 +36,8 @@ DEFAULT_FROM_EMAIL = '{{ project_name}}@localhost'
 #        'NAME': '{{ project_name }}',
 #        'USER': '{{ project_name }}',
 #        'PASSWORD': '',
+#        # If using SSL to connect to a cloud mysql database, spedify the CA as so.
+#        'OPTIONS': { 'ssl': { 'ca': '/path/to/certificate-authority.pem' } },
 #    }
 #}
 
@@ -41,7 +46,6 @@ DEFAULT_FROM_EMAIL = '{{ project_name}}@localhost'
 TEMPLATES = [
     {
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
-        'APP_DIRS': True,
         'OPTIONS': {
             'context_processors': [
                 'django.template.context_processors.debug',
@@ -65,11 +69,11 @@ CACHES = {
         'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
         'LOCATION': os.path.join(BASE_DIR, 'cache'),
         'KEY_PREFIX': 'coderedcms',
-        'TIMEOUT': 3600, # in seconds
+        'TIMEOUT': 14400, # in seconds
     }
 }
 
 try:
-    from .local import *
+    from .local_settings import *
 except ImportError:
     pass

+ 1 - 1
coderedcms/project_template/project_name/urls.py

@@ -24,7 +24,7 @@ urlpatterns = [
 
     # Alternatively, if you want CMS pages to be served from a subpath
     # of your site, rather than the site root:
-    #    url(r'^pages/', include(codered_urls)),
+    #    re_path(r'^pages/', include(codered_urls)),
 ]
 
 

+ 3 - 3
coderedcms/project_template/website/migrations/0002_initial_data.py

@@ -36,8 +36,8 @@ def initial_data(apps, schema_editor):
 
     # Create a new default site
     Site.objects.create(
-        hostname='localhost',
-        site_name='My New Website',
+        hostname='{{ domain }}',
+        site_name='{{ sitename }}',
         root_page_id=homepage.id,
         is_default_site=True
     )
@@ -53,4 +53,4 @@ class Migration(migrations.Migration):
 
     operations = [
         migrations.RunPython(initial_data),
-    ]
+    ]

+ 3 - 0
docs/_static/docs.css

@@ -251,6 +251,9 @@ div.admonition {
     color: #248;
     padding: 1em;
 }
+div.admonition code {
+    background-color: #edeff2;
+}
 div.admonition.warning {
     background-color:#fffcfa;
     border-color:#f0e0d0;

+ 5 - 1
docs/getting_started/install.rst

@@ -2,7 +2,11 @@ Installation
 ============
 
 #. Run ``pip install coderedcms``
-#. Run ``coderedcms start mysite``
+#. Run ``coderedcms start mysite --sitename "My Company Inc." --domain example.com``
+
+    .. note::
+        ``--sitename`` and ``--domain`` are optional to pre-populate settings of your website.
+
 #. Enter the mysite project with ``cd mysite/``.
 #. Run ``python manage.py migrate`` to create the core models.
 #. Run ``python manage.py createsuperuser`` to create the initial admin user.