Initial commit

as generated from: pcreate -t websauna_app hotcooler

https://websauna.org/docs/tutorials/gettingstarted/tutorial_03.html
This commit is contained in:
Lance Edgar 2017-04-01 15:17:32 -05:00
commit e036abd313
26 changed files with 512 additions and 0 deletions

37
.gitignore vendored Normal file
View file

@ -0,0 +1,37 @@
# Never commit our secrets files
*secrets.ini
# Default .gitignore with common Pythonic web ignores
venv
build/
dist/
*.pyc
__pycache__
*.egg
*.egg-info
# Logs
*.log
# Database dumbs
*.sql
*.sqlite
# If somebody does npm local installs
node_modules
# Created by running a celery
celerybeat*
# pytest-splinter creates screenshots from failed browsers tests.
# let's not pollute source tree with them by accient.
/*.tests.*
# Static asset cache busting
cache-manifest.json
perma-asset
# pytest and tox cache
.cache
.tox
.eggs

4
CHANGES.rst Normal file
View file

@ -0,0 +1,4 @@
0.0
---
- Initial version

2
MANIFEST.in Normal file
View file

@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include hotcooler *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.ini *.yml *.yaml

57
README.rst Normal file
View file

@ -0,0 +1,57 @@
This is a Websauna application package for hotcooler.
To run this package you need Python 3.4+, PostgresSQL and Redis.
Installation
============
This installation method assumes you the author of the hotcooler application and wish to develop it. Below are instructions to to install the package to a Python virtual environment using pip command in an editable mode.
Example::
cd hotcooler # This is the folder with setup.py file
virtualenv venv
source venv/bin/activate
# Make sure pip itself is up-to-date
pip install -U pip
# Install the package and its dependencies to a currently
# activated virtualenv from the folder with setup.py file
pip install -e "."
Running the website
===================
Local development machine
-------------------------
Example (OSX / Homebrew)::
# Create PostgreSQL database
psql create hotcooler_dev
# Write table schemas for models
ws-sync-db hotcooler/conf/development.ini
# Start web server
ws-pserve hotcooler/conf/development.ini --reload
Running the test suite
======================
Example::
# Install testing dependencies
pip install ".[dev,test]"
# Create database used for unit testing
psql create hotcooler_test
# Run test suite using py.test running
py.test
More information
================
Please see https://websauna.org/

3
alembic/env.py Normal file
View file

@ -0,0 +1,3 @@
from websauna.system.devop import alembic
alembic.run_alembic(package="hotcooler")

28
alembic/script.py.mako Normal file
View file

@ -0,0 +1,28 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
import datetime
import websauna.system.model.columns
from sqlalchemy.types import Text # Needed from proper creation of JSON fields as Alembic inserts astext_type=Text() row
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

View file

@ -0,0 +1,3 @@
This is a placeholder.
ws-alembic command will place generated scripts here.

57
hotcooler/__init__.py Normal file
View file

@ -0,0 +1,57 @@
"""App entry point and configuration."""
import websauna.system
class Initializer(websauna.system.Initializer):
"""An initialization configuration used for starting hotcooler.
Override parent class methods to customize application behavior.
"""
def configure_static(self):
"""Configure static asset serving and cache busting."""
super(Initializer, self).configure_static()
self.config.registry.static_asset_policy.add_static_view('hotcooler-static', 'hotcooler:static')
def configure_templates(self):
"""Include our package templates folder in Jinja 2 configuration."""
super(Initializer, self).configure_templates()
self.config.add_jinja2_search_path('hotcooler:templates', name='.html', prepend=True) # HTML templates for pages
self.config.add_jinja2_search_path('hotcooler:templates', name='.txt', prepend=True) # Plain text email templates (if any)
self.config.add_jinja2_search_path('hotcooler:templates', name='.xml', prepend=True) # Sitemap and misc XML files (if any)
def configure_views(self):
"""Configure views for your application.
Let the config scanner to pick ``@simple_route`` definitions from scanned modules. Alternative you can call ``config.add_route()`` and ``config.add_view()`` here.
"""
# We override this method, so that we route home to our home screen, not Websauna default one
from . import views
self.config.scan(views)
def configure_models(self):
"""Register the models of this application."""
from . import models
self.config.scan(models)
def configure_model_admins(self):
"""Register the models of this application."""
# Call parent which registers user and group admins
super(Initializer, self).configure_model_admins()
# Scan our admins
from . import admins
self.config.scan(admins)
def run(self):
super(Initializer, self).run()
def main(global_config, **settings):
init = Initializer(global_config)
init.run()
return init.make_wsgi_app()

1
hotcooler/admins.py Normal file
View file

@ -0,0 +1 @@
"""Place your admin resources in this file."""

39
hotcooler/conf/base.ini Normal file
View file

@ -0,0 +1,39 @@
# Definition of hotcooler name and properties shared among development, testing and production instances
#
# WSGI entry point and websauna INI settings
#
[app:main]
use = egg:hotcooler
websauna.init = hotcooler.Initializer
#
# Websauna settings
#
# Page/email title
websauna.site_name = hotcooler
# HTML title tag for the browser address bar
websauna.site_title = hotcooler
# Branding slogan
websauna.site_tag_line = Your site goes here
websauna.site_url = http://localhost:6543
# Your name
websauna.site_author = hotcooler team
# Used internally with databases/backups/etc.
websauna.site_id = hotcooler
# pyramid_mailer settings
mail.default_sender = no-reply@example.com
mail.default_sender_name = hotcooler team

View file

@ -0,0 +1,15 @@
# pserve and command line configuration for a local development machine
[includes]
include_ini_files =
resource://websauna/conf/development.ini
resource://hotcooler/conf/base.ini
resource://websauna/conf/base.ini
[app:main]
websauna.site_id = hotcooler_dev
websauna.site_email_prefix = [hotcooler DEV]
sqlalchemy.url = postgresql://localhost/hotcooler_dev
websauna.secrets_file = resource://hotcooler/conf/development-secrets.ini

View file

@ -0,0 +1,16 @@
# pserve and command line configuration for a production server
[includes]
include_ini_files =
resource://websauna/conf/production.ini
resource://hotcooler/conf/base.ini
resource://websauna/conf/base.ini
[app:main]
use = egg:hotcooler
websauna.init = hotcooler.Initializer
websauna.site_id = hotcooler_prod
websauna.site_email_prefix = [hotcooler]
sqlalchemy.url = postgresql://localhost/hotcooler_prod
websauna.secrets_file = resource://hotcooler/conf/production-secrets.ini

View file

@ -0,0 +1,13 @@
# pserve and command line configuration for a staging server
[includes]
include_ini_files =
resource://hotcooler/conf/production.ini
resource://websauna/conf/production.ini
resource://hotcooler/conf/base.ini
resource://websauna/conf/base.ini
[app:main]
websauna.site_id = hotcooler_staging
sqlalchemy.url = postgresql://localhost/hotcooler_staging
websauna.secrets_file = resource://hotcooler/conf/staging-secrets.ini

14
hotcooler/conf/test.ini Normal file
View file

@ -0,0 +1,14 @@
# py.test --ini configuration for running the hotcooler test suite
[includes]
include_ini_files =
resource://websauna/conf/test.ini
resource://hotcooler/conf/base.ini
resource://websauna/conf/base.ini
[app:main]
websauna.site_id = hotcooler_test
websauna.site_email_prefix = [hotcooler TEST]
sqlalchemy.url = postgresql://localhost/hotcooler_test
websauna.secrets_file = resource://hotcooler/conf/test-secrets.ini
websauna.test_web_server_port = 8533

1
hotcooler/models.py Normal file
View file

@ -0,0 +1 @@
"""Place your SQLAlchemy models in this file."""

BIN
hotcooler/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,4 @@
/* Don't let the logo image to grow too big */
.navbar-brand img {
max-height: 26px;
}

View file

@ -0,0 +1,23 @@
{# HTML email header
.. note ::
If you wish to use the company logo here, so that it actually shows up in the opened email, don't serve it from your own server. Instead upload the logo to Google Drive and hot link it there. GMail and other email applications are little bit picky where they allow images come from.
For raw ``<img src>`` link translate the Google Drive sharing link. From::
https://drive.google.com/file/d/0B6nei6GpGxGsb1hnWHlBRFJhxxx/view?usp=sharing
To::
https://drive.google.com/uc?id=0B6nei6GpGxGsb1hnWHlBRFJhxxx
#}
<tr>
<td align="right">
<h2>
<a href="home">
<img class="logo" src="{{ 'hotcooler:static/logo.png'|static_url }}" alt="{{ site_name }}">
</a>
</h2>
</td>
</tr>

View file

@ -0,0 +1,24 @@
{# Template for home view #}
{% extends "site/base.html" %}
{% block content %}
<div class="jumbotron text-center">
<h1>{{ site_name }}</h1>
<p class="lead text-center">
{{ site_tag_line }}
</p>
</div>
{% if request.user %}
<p id="demo-text">
Welcome {{ request.user.friendly_name }}!
</p>
{% else %}
<p id="demo-text">
Welcome visitor!
</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,20 @@
{# Specify CSS section for in the site <head> #}
{# Include Bootstrap CSS from Websauna core package - http://getbootstrap.com/ #}
<link rel="stylesheet" href="{{ 'websauna.system:static/bootstrap.min.css'|static_url }}">
{# Include Font-Awesome icons from CDN - http://fontawesome.io/ #}
<link href="//netdna.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet">
{# Include some default Websauna styles #}
<link rel="stylesheet" href="{{ 'websauna.system:static/theme.css'|static_url }}">
{# Include hotcooler package theme #}
<link rel="stylesheet" href="{{ 'hotcooler:static/theme.css'|static_url }}">
{# Include CSS for widgets #}
{% if request.on_demand_resource_renderer %}
{% for css_url in request.on_demand_resource_renderer.get_resources("css") %}
<link rel="stylesheet" href="{{ css_url }}"></link>
{% endfor %}
{% endif %}

View file

@ -0,0 +1,6 @@
{# Override the default navigation bar logo from Websauna templates #}
{# Logo file taken from here https://openclipart.org/detail/1105/workman-ahead-roadsign #}
<a class="navbar-brand" href="{{'home'|route_url}}">
<img src="{{ 'hotcooler:static/logo.png'|static_url }}" alt="hotcooler">
</a>

View file

View file

@ -0,0 +1,47 @@
"""An example login test case."""
import transaction
from sqlalchemy.orm.session import Session
from splinter.driver import DriverAPI
from websauna.tests.utils import create_user
from websauna.tests.utils import EMAIL
from websauna.tests.utils import PASSWORD
from websauna.system import Initializer
def test_login(web_server:str, browser:DriverAPI, dbsession:Session, init:Initializer):
"""Login as a user to the site.
This is a functional test. Prepare the test by creating one user in the database. Then try to login as this user by using Splinter test browser.
:param web_server: Functional web server py.test fixture - this string points to a started web server with test.ini configuration.
:param browser: A Splinter web browser used to execute the tests. By default ``splinter.driver.webdriver.firefox.WebDriver``, but can be altered with py.test command line options for pytest-splinter.
:param dbsession: Active SQLAlchemy database session for the test run.
:param init: Websauna Initializer which ramps up the environment with the default ``test.ini`` and exposes the test config.
"""
with transaction.manager:
# Create a dummy example@example.com user we test
create_user(dbsession, init.config.registry, email=EMAIL, password=PASSWORD)
# Direct Splinter browser to the website
b = browser
b.visit(web_server)
# This link should be in the top navigation
b.find_by_css("#nav-sign-in").click()
# Link gives us the login form
assert b.is_element_present_by_css("#login-form")
b.fill("username", EMAIL)
b.fill("password", PASSWORD)
b.find_by_name("login_email").click()
# After login we see a profile link to our profile
assert b.is_element_present_by_css("#nav-logout")

9
hotcooler/views.py Normal file
View file

@ -0,0 +1,9 @@
from websauna.system.http import Request
from websauna.system.core.route import simple_route
# Configure view named home at path / using a template hotcooler/home.html
@simple_route("/", route_name="home", renderer='hotcooler/home.html')
def home(request: Request):
"""Render site homepage."""
return {"project": "hotcooler"}

26
setup.cfg Normal file
View file

@ -0,0 +1,26 @@
[tool:pytest]
addopts =
--strict
-p websauna.tests.fixtures
--splinter-make-screenshot-on-failure=false
--ini=hotcooler/conf/test.ini
hotcooler/tests
# E501: Line too long
# E128: continuation line under
# E731: http://stackoverflow.com/q/25010167/315168
pep8ignore = E501 E128 E731
# Don't let py.test scan py.files in these folders
norecursedirs = alembic .tox .cache .eggs venv
# Add some default py.test markers
# Slow marker is for tests taking > 15 seconds to complete.
# Fail marker signals the test is expected to fail.
markers =
slow
fail
[flake8]
ignore = E128 E731_
max-line-length = 999

63
setup.py Normal file
View file

@ -0,0 +1,63 @@
import os
import sys
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.rst')) as f:
README = f.read()
with open(os.path.join(here, 'CHANGES.rst')) as f:
CHANGES = f.read()
# trying to run python setup.py install or python setup.py develop
if len(sys.argv) >= 2:
if sys.argv[0] == "setup.py" and sys.argv[1] in ("install", "develop"):
# Otherwise so much stuff would be broken later...
# Namely, namespaced packages clash as pip, setup.py and easy_install handle namespaces differently
raise RuntimeError("It is not possible to install this package with setup.py. Use pip to install this package as instructed in Websauna tutorial.")
setup(name='hotcooler',
version='0.0',
description='hotcooler',
long_description=README + '\n\n' + CHANGES,
classifiers=[
"Programming Language :: Python",
"Framework :: Pyramid",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
],
author='',
author_email='',
url='',
keywords='web websauna pyramid',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
test_suite='hotcooler',
install_requires=['websauna'],
extras_require={
# Dependencies for running test suite
'test': [
"pytest",
"pytest-runner",
"pytest-splinter",
"webtest",
# Wait until Marionette matures
# http://stackoverflow.com/questions/37761668/cant-open-browser-with-selenium-after-firefox-update
"selenium==2.53.6",
],
# Dependencies to make releases
'dev': ['websauna[dev]'],
},
# Define where this application starts as referred by WSGI web servers
entry_points="""\
[paste.app_factory]
main = hotcooler:main
""",
)