add deployment and etc

master
fefa4ka 11 years ago
parent d6fabb78ca
commit d03d77a66a
  1. 0
      app/__init__.py
  2. 210
      app/conf/newrelic.ini
  3. 22
      app/conf/nginx.conf.template
  4. 15
      app/conf/uwsgi_params
  5. 14
      app/conf/uwsgi_zuykov.conf.template
  6. 0
      app/deploy/__init__.py
  7. 107
      app/deploy/debian.py
  8. 24
      app/deploy/django.py
  9. 17
      app/deploy/hosts.py
  10. 26
      app/deploy/service.py
  11. 167
      app/deploy/tasks.py
  12. 88
      app/deploy/zuykov.py
  13. 20
      app/settings.py
  14. 3
      app/urls.py
  15. 54
      blog/migrations/0009_auto_20150726_2021.py
  16. 4
      blog/urls.py
  17. 30
      deploy.py
  18. 2
      manage.py
  19. 2
      requirements.txt
  20. 0
      service/__init__.py
  21. 15
      service/cms_app.py
  22. 75
      service/cms_appconfig.py
  23. 58
      service/cms_plugins.py
  24. 10
      service/urls.py
  25. 52
      service/views.py
  26. BIN
      zsite/static/imgs/phone.png
  27. 4
      zsite/static/js/app.js
  28. 52
      zsite/static/js/forms.js
  29. 18
      zsite/static/less/about.less
  30. 40
      zsite/static/less/consultation.less
  31. 1
      zsite/static/less/main.less
  32. 2
      zsite/static/less/people.less
  33. 2
      zsite/templates/aldryn_people/plugins/feature/people_list.html
  34. 23
      zsite/templates/base.html
  35. 70
      zsite/templates/form_template/consultation.html
  36. 9
      zsite/templates/menu.html
  37. 14
      zsite/templates/menu_header.html
  38. 5
      zsite/templates/sub_section.html

@ -0,0 +1,210 @@
# ---------------------------------------------------------------------------
#
# This file configures the New Relic Python Agent.
#
# The path to the configuration file should be supplied to the function
# newrelic.agent.initialize() when the agent is being initialized.
#
# The configuration file follows a structure similar to what you would
# find for Microsoft Windows INI files. For further information on the
# configuration file format see the Python ConfigParser documentation at:
#
# http://docs.python.org/library/configparser.html
#
# For further discussion on the behaviour of the Python agent that can
# be configured via this configuration file see:
#
# http://newrelic.com/docs/python/python-agent-configuration
#
# ---------------------------------------------------------------------------
# Here are the settings that are common to all environments.
[newrelic]
# You must specify the license key associated with your New
# Relic account. This key binds the Python Agent's data to your
# account in the New Relic service.
license_key = 7a0c5c3cda7e345c16a596d31a7f1fe8dc9c2ee7
# The appplication name. Set this to be the name of your
# application as you would like it to show up in New Relic UI.
# The UI will then auto-map instances of your application into a
# entry on your home dashboard page.
app_name = Transcribe.ninja
# When "true", the agent collects performance data about your
# application and reports this data to the New Relic UI at
# newrelic.com. This global switch is normally overridden for
# each environment below.
monitor_mode = true
# Sets the name of a file to log agent messages to. Useful for
# debugging any issues with the agent. This is not set by
# default as it is not known in advance what user your web
# application processes will run as and where they have
# permission to write to. Whatever you set this to you must
# ensure that the permissions for the containing directory and
# the file itself are correct, and that the user that your web
# application runs as can write to the file. If not able to
# write out a log file, it is also possible to say "stderr" and
# output to standard error output. This would normally result in
# output appearing in your web server log.
#log_file = /tmp/newrelic-python-agent.log
# Sets the level of detail of messages sent to the log file, if
# a log file location has been provided. Possible values, in
# increasing order of detail, are: "critical", "error", "warning",
# "info" and "debug". When reporting any agent issues to New
# Relic technical support, the most useful setting for the
# support engineers is "debug". However, this can generate a lot
# of information very quickly, so it is best not to keep the
# agent at this level for longer than it takes to reproduce the
# problem you are experiencing.
log_level = info
# The Python Agent communicates with the New Relic service using
# SSL by default. Note that this does result in an increase in
# CPU overhead, over and above what would occur for a non SSL
# connection, to perform the encryption involved in the SSL
# communication. This work is though done in a distinct thread
# to those handling your web requests, so it should not impact
# response times. You can if you wish revert to using a non SSL
# connection, but this will result in information being sent
# over a plain socket connection and will not be as secure.
ssl = true
# High Security Mode enforces certain security settings, and
# prevents them from being overridden, so that no sensitive data
# is sent to New Relic. Enabling High Security Mode means that
# SSL is turned on, request parameters are not collected, and SQL
# can not be sent to New Relic in its raw form. To activate High
# Security Mode, it must be set to 'true' in this local .ini
# configuration file AND be set to 'true' in the server-side
# configuration in the New Relic user interface. For details, see
# https://docs.newrelic.com/docs/subscriptions/high-security
high_security = false
# The Python Agent will attempt to connect directly to the New
# Relic service. If there is an intermediate firewall between
# your host and the New Relic service that requires you to use a
# HTTP proxy, then you should set both the "proxy_host" and
# "proxy_port" settings to the required values for the HTTP
# proxy. The "proxy_user" and "proxy_pass" settings should
# additionally be set if proxy authentication is implemented by
# the HTTP proxy. The "proxy_scheme" setting dictates what
# protocol scheme is used in talking to the HTTP proxy. This
# would normally always be set as "http" which will result in the
# agent then using a SSL tunnel through the HTTP proxy for end to
# end encryption.
# proxy_scheme = http
# proxy_host = hostname
# proxy_port = 8080
# proxy_user =
# proxy_pass =
# Tells the transaction tracer and error collector (when
# enabled) whether or not to capture the query string for the
# URL and send it as the request parameters for display in the
# UI. When "true", it is still possible to exclude specific
# values from being captured using the "ignored_params" setting.
capture_params = false
# Space separated list of variables that should be removed from
# the query string captured for display as the request
# parameters in the UI.
ignored_params =
# The transaction tracer captures deep information about slow
# transactions and sends this to the UI on a periodic basis. The
# transaction tracer is enabled by default. Set this to "false"
# to turn it off.
transaction_tracer.enabled = true
# Threshold in seconds for when to collect a transaction trace.
# When the response time of a controller action exceeds this
# threshold, a transaction trace will be recorded and sent to
# the UI. Valid values are any positive float value, or (default)
# "apdex_f", which will use the threshold for a dissatisfying
# Apdex controller action - four times the Apdex T value.
transaction_tracer.transaction_threshold = apdex_f
# When the transaction tracer is on, SQL statements can
# optionally be recorded. The recorder has three modes, "off"
# which sends no SQL, "raw" which sends the SQL statement in its
# original form, and "obfuscated", which strips out numeric and
# string literals.
transaction_tracer.record_sql = obfuscated
# Threshold in seconds for when to collect stack trace for a SQL
# call. In other words, when SQL statements exceed this
# threshold, then capture and send to the UI the current stack
# trace. This is helpful for pinpointing where long SQL calls
# originate from in an application.
transaction_tracer.stack_trace_threshold = 0.5
# Determines whether the agent will capture query plans for slow
# SQL queries. Only supported in MySQL and PostgreSQL. Set this
# to "false" to turn it off.
transaction_tracer.explain_enabled = true
# Threshold for query execution time below which query plans
# will not not be captured. Relevant only when "explain_enabled"
# is true.
transaction_tracer.explain_threshold = 0.5
# Space separated list of function or method names in form
# 'module:function' or 'module:class.function' for which
# additional function timing instrumentation will be added.
transaction_tracer.function_trace =
# The error collector captures information about uncaught
# exceptions or logged exceptions and sends them to UI for
# viewing. The error collector is enabled by default. Set this
# to "false" to turn it off.
error_collector.enabled = true
# To stop specific errors from reporting to the UI, set this to
# a space separated list of the Python exception type names to
# ignore. The exception name should be of the form 'module:class'.
error_collector.ignore_errors =
# Browser monitoring is the Real User Monitoring feature of the UI.
# For those Python web frameworks that are supported, this
# setting enables the auto-insertion of the browser monitoring
# JavaScript fragments.
browser_monitoring.auto_instrument = true
# A thread profiling session can be scheduled via the UI when
# this option is enabled. The thread profiler will periodically
# capture a snapshot of the call stack for each active thread in
# the application to construct a statistically representative
# call tree.
thread_profiler.enabled = true
# ---------------------------------------------------------------------------
#
# The application environments. These are specific settings which
# override the common environment settings. The settings related to a
# specific environment will be used when the environment argument to the
# newrelic.agent.initialize() function has been defined to be either
# "development", "test", "staging" or "production".
#
[newrelic:development]
monitor_mode = false
[newrelic:test]
monitor_mode = false
[newrelic:staging]
app_name = Zuykov.com
monitor_mode = true
[newrelic:production]
monitor_mode = true
# ---------------------------------------------------------------------------

@ -0,0 +1,22 @@
upstream django_zuykov {
server unix:///home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/wsgi_transcribe_ninja.sock;
}
server {
listen 80;
server_name dev.zuykov.com;
charset utf-8;
client_max_body_size 1024M;
location /static {
alias /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/static;
}
location / {
uwsgi_pass django_zuykov;
include /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/uwsgi_params;
}
}

@ -0,0 +1,15 @@
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;

@ -0,0 +1,14 @@
[uwsgi]
uid=%(SERVER_USERNAME)s
gid=%(SERVER_USERNAME)s
chdir = /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s
module = app.wsgi_zuykov
home = /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/env
eval = import newrelic.agent, wsgi_zuykov; application = newrelic.agent.wsgi_application()(wsgi_zuykov.application)
master = true
processes = 4
socket = /home/%(EC2_SERVER_USERNAME)s/%(PROJECT_NAME)s/app/wsgi_zuykov.sock
chmod-socket = 666
vacuum = true

@ -0,0 +1,107 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import settings
from deployer.node import Node
from deployer.utils import esc1
class Debian(Node):
def _configure_instance(self, tasks):
# Configure the instance that was just created
for item in tasks:
try:
print item['message']
except KeyError:
pass
getattr(self, "_" + item['action'])(item['params'])
# Actions
# def _virtualenv(params):
# """
# Allows running commands on the server
# with an active virtualenv
# """
# with cd(fabconf['APPS_DIR']):
# _virtualenv_command(_render(params))
def _apt(self, params):
"""
Runs apt-get install commands
"""
for pkg in params:
self._sudo("apt-get install -y -qq %s" % pkg)
def _pip(self, params):
"""
Runs pip install commands
"""
for pkg in params:
self._sudo("pip install %s" % pkg)
def _run(self, params):
"""
Runs command with active user
"""
command = self._render(params)
self.hosts.run(command)
def _sudo(self, params):
"""
Run command as root
"""
command = self._render(params)
self.hosts.sudo(command)
def _put(self, params):
"""
Moves a file from local computer to server
"""
for host in self.hosts.get_hosts():
host = host()
host.put_file(
self._render(params['file']),
self._render(params['destination'])
)
def _put_template(self, params, context=settings.__dict__):
"""
Same as _put() but it loads a file and does variable replacement
"""
f = open(self._render(params['template']), 'r')
template = f.read()
self.hosts.run(
self._write_to(
self._render(template, context),
self._render(params['destination'])
)
)
def _render(self, template, context=settings.__dict__):
"""
Does variable replacement
"""
return template % context
def _write_to(self, string, path):
"""
Writes a string to a file on the server
"""
return "echo '" + string + "' > " + path
def _append_to(self, string, path):
"""
Appends to a file on the server
"""
return "echo '" + string + "' >> " + path
def _virtualenv(self, command):
"""
Activates virtualenv and runs command
"""
with self.hosts.prefix(settings.ACTIVATE):
with self.hosts.cd(settings.PROJECT_DIR, expand=True):
self.hosts.run(self._render(command))

@ -0,0 +1,24 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# from app import settings
# from deployer.node import Node
from deployer.utils import esc1
from app.deploy.debian import Debian
class DjangoDeployment(Debian):
def run_management_command(self, command):
""" Run Django management command in virtualenv. """
self._virtualenv('./manage.py %s' % esc1(command))
def django_shell(self):
""" Open interactive Django shell. """
self.run_management_command('shell')
def python_packages_install(self):
""" Run Django management command in virtualenv. """
# Activate the virtualenv.
self._virtualenv('pip install --upgrade pip && pip install -r %(PROJECT_DIR)s/requirements.txt --upgrade' % settings.__dict__)

@ -0,0 +1,17 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Deploy
from deployer.host import SSHHost
from zsite import settings
class WebHost(SSHHost):
slug = 'web'
address = 'dev.zuykov.com'
username = 'web'
password = '9oijffDf2vi@D!'
class DatabaseHost(WebHost):
slug = 'database'

@ -0,0 +1,26 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from deployer.node import Node, required_property
from deployer.utils import esc1
class UpstartService(Node):
"""
Abstraction for any upstart service with start/stop/status methods.
"""
name = required_property()
def start(self):
self.hosts.sudo('service %s start' % esc1(self.name))
def stop(self):
self.hosts.sudo('service %s stop' % esc1(self.name))
def restart(self):
self.stop()
self.start()
def status(self):
self.hosts.sudo('service %s status' % esc1(self.name))

@ -0,0 +1,167 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
--------------------------------------------------------------------------------------
tasks.py
--------------------------------------------------------------------------------------
A set of tasks to manage your AWS Django deployment.
author : Ashok Fernandez (github.com/ashokfernandez/)
credit : Derived from files in https://github.com/gcollazo/Fabulous
date : 11 / 3 / 2014
Tasks include:
- configure_instance : Configures a new EC2 instance (as definied in settings.py) and return's it's public dns
This takes around 8 minutes to complete.
- update_packages : Updates the python packages on the server to match those found in requirements/common.txt and
requirements/prod.txt
- deploy : Pulls the latest commit from the master branch on the server, collects the static files, syncs the db and
restarts the server
- reload_gunicorn : Pushes the gunicorn startup script to the servers and restarts the gunicorn process, use this if you
have made changes to templates/start_gunicorn.bash
- reload_nginx : Pushes the nginx config files to the servers and restarts the nginx, use this if you
have made changes to templates/nginx-app-proxy or templates/nginx.conf
- reload_supervisor : Pushes the supervisor config files to the servers and restarts the supervisor, use this if you
have made changes to templates/supervisord-init or templates/supervisord.conf
'''
# Spawns a new EC2 instance (as definied in djangofab_conf.py) and return's it's public dns
# This takes around 8 minutes to complete.
common_configure = [
# First command as regular user
{"action": "run", "params": "whoami"},
# List of APT packages to install
{"action": "apt",
"params": ["libpq-dev", "git",
"python-setuptools", "python-dev", "build-essential", "python-pip", "redis-server",
"libmysqlclient-dev", "subversion"],
"message":"Installing apt-get packages" },
# List of pypi packages to install
{"action": "pip", "params": ["virtualenv"],
"message":"Installing virtualenv"},
#project directory
{"action": "run", "params": "mkdir -p %(PROJECT_DIR)s", "message": "Create project folder" },
{"action": "run", "params": "mkdir -p %(LOGS_DIR)s", "message": "Create logs folder" },
{"action": "sudo", "params": "chown -R %(SERVER_USERNAME)s: %(PROJECT_DIR)s"},
# git setup
{"action": "run", "params": "git config --global user.name '%(GIT_USERNAME)s'",
"message": "Configuring git"},
{"action": "run",
"params": "git config --global user.email '%(ADMIN_EMAIL)s'"},
{"action": "put", "params": {"file": "%(GIT_KEY_PATH)s",
"destination": "/home/%(SERVER_USERNAME)s/.ssh/%(GIT_KEY_NAME)s"}},
{"action": "run", "params":
"chmod 600 /home/%(SERVER_USERNAME)s/.ssh/%(GIT_KEY_NAME)s"},
{"action": "run", "params":
u"""echo 'IdentityFile /home/%(SERVER_USERNAME)s/.ssh/%(GIT_KEY_NAME)s' >> /home/%(SERVER_USERNAME)s/.ssh/config"""},
{"action": "run", "params":
"ssh-keyscan github.com >> /home/%(SERVER_USERNAME)s/.ssh/known_hosts"},
# Clone the git repo
{"action": "run",
"params": "git clone %(REPOSITORY)s %(PROJECT_DIR)s"},
# virtualenv
{"action": "run",
"params": "mkdir -p %(ENV_DIR)s", "message": "Create project folder" },
{"action": "run",
"params": "virtualenv %(ENV_DIR)s", "message": "Configuring virtualenv" },
{"action": "sudo", "params": "chown -R %(SERVER_USERNAME)s: %(ENV_DIR)s"},
# {"action": "run", "params":
# "echo 'expo WORKON_HOME=%(PRO_DIR)s' >> /home/%(SERVER_USERNAME)s/.profile"},
{"action": "run", "params":
u"echo 'source %(ENV_DIR)s/bin/activate' >> /home/%(SERVER_USERNAME)s/.profile"},
{"action": "run", "params": "source /home/%(SERVER_USERNAME)s/.profile"},
{"action": "virtualenv", "params":
"pip install -r %(PROJECT_DIR)s/requirements.txt --upgrade"},
]
web_configure = [
# List of APT packages to install
{"action": "apt",
"params": ["nginx", "uwsgi", "uwsgi-plugin-python", "nodejs", "npm"],
"message":"Installing nginx, uwsgi, nodejs packages"},
{"action": "sudo", "params": "npm install -g bower karma grunt grunt-cli"},
# Костыль с нодой
{"action": "run", "params": "ln -s /usr/bin/nodejs %(ENV_DIR)s/bin/node"},
{"action": "sudo", "params": "cd %(PROJECT_DIR)s/frontend/transcribe.ninja && npm install"},
{"action": "sudo", "params": "cd %(PROJECT_DIR)s/frontend/stenograph.us && npm install"},
{"action": "sudo", "params": "rm -rf /etc/nginx/sites-enabled/default"},
{"action": "sudo", "params": "rm -rf /etc/supervisor/conf.d/default"},
{"action": "sudo", "params": "rm -rf /etc/uwsgi/apps-enabled/default.ini"},
]
npm_install = [
{"action": "sudo", "params": "cd %(PROJECT_DIR)s/frontend/transcribe.ninja && npm install"},
{"action": "sudo", "params": "cd %(PROJECT_DIR)s/frontend/stenograph.us && npm install"},
]
# nginx
reload_nginx = [
{"action": "put_template", "params": {"template": "%(BASE_DIR)s/app/conf/nginx.conf.template",
"destination": "/home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/nginx.conf"}},
{"action": "sudo", "params": "service nginx restart",
"message": "Restarting nginx"},
]
create_nginx_links = [
{"action": "sudo", "params":
"ln -s /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/nginx.conf /etc/nginx/sites-enabled/%(PROJECT_NAME)s.conf"},
]
create_uwsgi_links = [
{"action": "sudo", "params":
"ln -s /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/uwsgi_stenograph_us.conf /etc/uwsgi/apps-enabled/%(PROJECT_NAME)s_stenograph_us.ini"},
{"action": "sudo", "params":
"ln -s /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/uwsgi_transcribe_ninja.conf /etc/uwsgi/apps-enabled/%(PROJECT_NAME)s_transcribe_ninja.ini"},
]
reload_uwsgi = [
{"action": "put_template", "params": {"template": "%(BASE_DIR)s/app/conf/uwsgi_stenograph_us.conf.template",
"destination": "/home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/uwsgi_stenograph_us.conf"}},
{"action": "put_template", "params": {"template": "%(BASE_DIR)s/app/conf/uwsgi_transcribe_ninja.conf.template",
"destination": "/home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/uwsgi_transcribe_ninja.conf"}},
{"action": "sudo", "params": "service uwsgi restart",
"message": "Restarting uwsgi"},
]
web_configure += reload_uwsgi + reload_nginx + create_uwsgi_links + create_nginx_links
engine_configure = [
# List of pypi packages to install
{"action": "run", "params": "cp -r ~/%(PROJECT_NAME)s/env/share/voiceid ~/%(PROJECT_NAME)s/env/local/share/",
"message":"Move voiceid"},
{"action": "apt", "params": ["supervisor"],
"message":"Installing supervisor"},
{"action": "put_template", "params": {"template": "%(BASE_DIR)s/app/conf/supervisor.conf.template",
"destination": "/home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/supervisor.conf"}},
{"action": "sudo", "params":
"ln -s /home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/supervisor.conf /etc/supervisor/conf.d/%(PROJECT_NAME)s.conf"},
{"action": "sudo", "params": "service supervisor restart",
"message": "Restarting supervisor"},
# Запстить очереди
# TODO: настроить редис как внешний сервер
]
reload_supervisor = [
{"action": "put_template", "params": {"template": "%(BASE_DIR)s/app/conf/supervisor.conf.template",
"destination": "/home/%(SERVER_USERNAME)s/%(PROJECT_NAME)s/app/conf/supervisor.conf"}},
{"action": "sudo", "params": "service supervisor restart",
"message": "Restarting supervisor"},
]

@ -0,0 +1,88 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# from django.db import connection
from deployer.node import Node, map_roles
from deployer.utils import esc1
from app.deploy.service import *
from app.deploy.django import *
import app.deploy.tasks as tasks
import os.path
from app import settings
class ZuykovWebSystem(Node):
"""
The base definition of our web system.
roles: web, engine, database
"""
# @map_roles(host='database')
# class Database(<):
# def create(self):
# host = settings.DATABASES['default']
# # Создаём группу безопасности
# security_group = self._ec2_mysql_security_group()
# # Создаём группу параметров
# # Запускаем инстанс
# self._rds_create_instance(
# 'database',
# host['NAME'],
# host['USER'],
# host['PASSWORD'])
@map_roles(host='web')
class Application(DjangoDeployment):
def configure_base(self):
self._configure_instance(tasks.common_configure)
def hello(self):
self.hosts.run('echo hello world')
def update(self):
self.checkout()
self.pull()
def checkout(self, commit="."):
with self.hosts.cd(settings.PROJECT_DIR, expand=True):
self.hosts.run("git checkout '%s'" % esc1(commit))
def pull(self):
with self.hosts.cd(settings.PROJECT_DIR, expand=True):
self.hosts.run('git pull')
def create(self):
self.Application.hello()
# Если созданы — удалить
# # Предварительно спросить
# self.Frontend.create()
# self.Engine.create()
def deploy(self):
pass
# self.Application.update()
# self.Application.python_packages_install()
# self.update_hosts()
# self.Engine.migrate()
# self.Frontend.restart()
# self.Engine.restart()

@ -36,6 +36,19 @@ ALLOWED_HOSTS = []
# Application definition # Application definition
PROJECT_NAME = 'zuykov'
SERVER_USERNAME = 'web'
PROJECT_DIR = '~/' + PROJECT_NAME
ENV_DIR = '%s/env' % PROJECT_DIR
LOGS_DIR = '~/logs'
ACTIVATE = '. %s/bin/activate' % ENV_DIR
REPOSITORY = 'git@github.com:fefa4ka/zuykov.git'
GIT_USERNAME = 'fefa4ka'
ADMIN_EMAIL = 'fefa4ka@gmail.com'
GIT_KEY_PATH = '/Users/fefa4ka/.ssh/deploy_rsa'
GIT_KEY_NAME = 'github_rsa'
@ -87,13 +100,17 @@ PIPELINE_JS = {
'main': { 'main': {
'source_filenames': ( 'source_filenames': (
'js/app.js', 'js/app.js',
'js/forms.js',
), ),
'output_filename': 'js/*.js', 'output_filename': 'js/*.js',
}, },
'vendor': { 'vendor': {
'source_filenames': ( 'source_filenames': (
'vendor/angular/angular.js', 'vendor/angular/angular.js',
'vendor/angular-bootstrap/ui-bootstrap.js' 'vendor/angular-bootstrap/ui-bootstrap.js',
'vendor/angular-bootstrap/ui-bootstrap-tpls.js',
'vendor/jquery/dist/jquery.js',
), ),
'output_filename': 'js/vendor.js', 'output_filename': 'js/vendor.js',
} }
@ -201,6 +218,7 @@ INSTALLED_APPS = (
'aldryn_bootstrap3', 'aldryn_bootstrap3',
'djangocms_forms',
# 'debug_toolbar', # 'debug_toolbar',
) )

@ -9,12 +9,15 @@ from django.conf import settings
admin.autodiscover() admin.autodiscover()
urlpatterns = i18n_patterns('', urlpatterns = i18n_patterns('',
url(r'^', include('djangocms_forms.urls')),
url(r'^admin/', include(admin.site.urls)), # NOQA url(r'^admin/', include(admin.site.urls)), # NOQA
url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap',
{'sitemaps': {'cmspages': CMSSitemap}}), {'sitemaps': {'cmspages': CMSSitemap}}),
url(r'^select2/', include('django_select2.urls')), url(r'^select2/', include('django_select2.urls')),
url(r'^', include('cms.urls')), url(r'^', include('cms.urls')),
url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')), url(r'^taggit_autosuggest/', include('taggit_autosuggest.urls')),
) )
# This is only needed when using runserver. # This is only needed when using runserver.

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('blog', '0008_auto_20150713_1609'),
]
operations = [
migrations.AlterModelOptions(
name='blogcategorytranslation',
options={'default_permissions': (), 'verbose_name': 'blog category Translation', 'managed': True},
),
migrations.AlterModelOptions(
name='posttranslation',
options={'default_permissions': (), 'verbose_name': 'blog article Translation', 'managed': True},
),
migrations.RemoveField(
model_name='latestpostsplugin',
name='tags',
),
migrations.AlterField(
model_name='blogcategorytranslation',
name='language_code',
field=models.CharField(max_length=15, verbose_name='Language', db_index=True),
preserve_default=True,
),
migrations.AlterField(
model_name='blogconfig',
name='category_slug',
field=models.CharField(help_text='Only category to display', max_length=255, verbose_name='Category slug', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='post',
name='enable_comments',
field=models.BooleanField(default=True, verbose_name='Enable comments on post'),
preserve_default=True,
),
migrations.AlterField(
model_name='posttranslation',
name='language_code',
field=models.CharField(max_length=15, verbose_name='Language', db_index=True),
preserve_default=True,
),
migrations.AlterUniqueTogether(
name='blogconfigtranslation',
unique_together=set([('language_code', 'master')]),
),
]

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf.urls import patterns, url from django.conf.urls import patterns, include, url
from .views import (PostListView, PostDetailView, TaggedListView, from .views import (PostListView, PostDetailView, TaggedListView,
AuthorEntriesView, PostArchiveView, CategoryEntriesView) AuthorEntriesView, PostArchiveView, CategoryEntriesView)
from .feeds import LatestEntriesFeed, TagFeed from .feeds import LatestEntriesFeed, TagFeed
from djangocms_forms.views import FormSubmission
urlpatterns = patterns( urlpatterns = patterns(
'', '',

@ -0,0 +1,30 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import connection
from deployer.client import start
from deployer.node import Node
from app.deploy import hosts
from app.deploy.zuykov import ZuykovWebSystem
import app.settings as settings
class RootNode(Node):
"""
The root node of our configuration, containing two 'instances' of
`WebSystem`,
"""
class ProductionSystem(ZuykovWebSystem):
class Hosts:
web = {hosts.WebHost}
database = {hosts.DatabaseHost}
if __name__ == '__main__':
start(RootNode)

@ -3,7 +3,7 @@ import os
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zsite.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line

@ -19,4 +19,6 @@ djangocms_video
mysql mysql
django-pipeline django-pipeline
django_debug_toolbar django_debug_toolbar
djangocms-forms
django-multipleformwizard
#export C_INCLUDE_PATH=/usr/local/Cellar/libxml2/2.9.2/include/libxml2:$C_INCLUDE_PATH #export C_INCLUDE_PATH=/usr/local/Cellar/libxml2/2.9.2/include/libxml2:$C_INCLUDE_PATH

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from aldryn_apphooks_config.app_base import CMSConfigApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
from .models import ServiceConfig
class BlogApp(CMSConfigApp):
app_config = ServiceConfig
name = _('Service')
urls = ['service.urls']
app_name = 'service'
apphook_pool.register(ServiceApp)

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django import forms
from django.conf import settings
from django.db import models
from django.utils.translation import ugettext_lazy as _
from aldryn_apphooks_config.utils import setup_config
from aldryn_apphooks_config.models import AppHookConfig
from app_data import AppDataForm
from parler.models import TranslatableModel
from parler.models import TranslatedFields
from cms.models.fields import PlaceholderField
class ServiceConfig(TranslatableModel, AppHookConfig):
"""Adds some translatable, per-app-instance fields."""
translations = TranslatedFields(
app_title=models.CharField(_('application title'), max_length=234),
)
category_slug = models.CharField(
_('Category slug'),
blank=True,
max_length=255,
help_text=_('Only category to display'))
placeholder_base_top = PlaceholderField(
'service_base_top',
related_name='service_base_top',
)
placeholder_base_sidebar = PlaceholderField(
'service_base_sidebar',
related_name='service_base_sidebar',
)
placeholder_list_top = PlaceholderField(
'service_list_top',
related_name='service_list_top',
)
placeholder_list_footer = PlaceholderField(
'service_list_footer',
related_name='service_list_footer',
)
placeholder_detail_top = PlaceholderField(
'service_detail_top',
related_name='service_detail_top',
)
placeholder_detail_bottom = PlaceholderField(
'service_detail_bottom',
related_name='service_detail_bottom',
)
placeholder_detail_footer = PlaceholderField(
'service_detail_footer',
related_name='service_detail_footer',
)
def get_app_title(self):
return getattr(self, 'app_title', _('untitled'))
class SeviceConfigForm(AppDataForm):
default_published = forms.BooleanField(
label=_(u'Post published by default'), required=False,
initial=getattr(settings, 'service_DEFAULT_PUBLISHED', True))
setup_config(ServiceConfigForm, ServiceConfig)

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
from django.utils.translation import ugettext_lazy as _
from cms.models.pluginmodel import CMSPlugin
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from .models import ContextServicePlugin
from .forms import ContextServiceForm
from .settings import get_setting
class SevicePlugin(CMSPluginBase):
module = 'Sevice'
class SeviceContextPlugin(SevicePlugin):
"""
Non cached plugin which returns the latest posts taking into account the
user / toolbar state
"""
render_template = 'sevice/plugins/context_services.html'
name = _('Context Services')
model = ContextServicePlugin
form = ContextServiceForm
filter_horizontal = ('categories',)
cache = False
def render(self, context, instance, placeholder):
context = super(SeviceContextPlugin, self).render(context, instance, placeholder)
context['services_list'] = instance.get_services(context['request'])
if instance.categories.exists():
context['category'] = instance.categories.all()[0].slug
else:
context['category'] = "all"
return context
class SeviceContextPluginCached(SevicePlugin):
"""
Cached plugin which returns the latest published posts
"""
render_template = 'sevice/plugins/context_services.html'
name = _('Context Services')
model = ContextServicePlugin
form = ContextServiceForm
filter_horizontal = ('categories',)
def render(self, context, instance, placeholder):
context = super(SeviceContextPluginCached, self).render(context, instance, placeholder)
context['posts_list'] = instance.get_posts()
return context
plugin_pool.register_plugin(SeviceContextPlugin)

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from .views import (ServiceDetailView)
urlpatterns = patterns(
'',
url(r'^(?P<service_slug>[\w\.@+-]+)/$', ServiceDetailView.as_view(), name='service-detail'),
)

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
from django.contrib.auth import get_user_model
from django.core.urlresolvers import resolve
from django.utils.timezone import now
from django.utils.translation import get_language
from django.views.generic import ListView, DetailView
from parler.views import ViewUrlMixin, TranslatableSlugMixin
from aldryn_apphooks_config.mixins import AppConfigMixin
from .models import Service, ServiceCategory, SERVICE_CURRENT_SERVICE_IDENTIFIER
from .settings import get_setting
User = get_user_model()
class BaseServiceView(ViewUrlMixin, AppConfigMixin):
def get_queryset(self):
language = get_language()
queryset = self.model._default_manager.active_translations(language_code=language)
print self.config
if self.config and self.config.category_slug:
self._category = ServiceCategory.objects.active_translations(get_language(), slug=self.config.category_slug).latest('pk')
queryset = queryset.filter(categories=self._category.pk)
if not getattr(self.request, 'toolbar', False) or not self.request.toolbar.edit_mode:
queryset = queryset.published()
return queryset.on_site()
def render_to_response(self, context, **response_kwargs):
response_kwargs['current_app'] = resolve(self.request.path).namespace
return super(BaseServiceView, self).render_to_response(context, **response_kwargs)
class ServiceDetailView(TranslatableSlugMixin, BaseServiceView, DetailView):
model = Service
context_object_name = 'post'
template_name = 'service/service_detail.html'
slug_field = 'slug'
view_url_name = 'service:service-detail'
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['meta'] = self.get_object().as_meta()
context['use_placeholder'] = get_setting('USE_PLACEHOLDER')
setattr(self.request, SERVICE_CURRENT_SERVICE_IDENTIFIER, self.get_object())
return context

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

@ -1 +1,3 @@
console.log('Yep'); angular.module('zuykov', ['ui.bootstrap']);
console.log('Yep');

@ -0,0 +1,52 @@
angular.module('zuykov').controller('ModalFormCtrl', function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.animationsEnabled = true;
$scope.open = function (form_id) {
console.log('open');
var modalInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'modalFormTemplate-' + form_id + '.html',
controller: 'ModalFormInstanceCtrl',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
})
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
.controller('ModalFormInstanceCtrl', function ($scope, $modalInstance, items, $log, $timeout) {
$log.info('opened modal');
$timeout(function () {
$('.forms').djangocms_forms();
}, 1000);
$scope.ok = function () {
$modalInstance.close("params");
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});

@ -1,10 +1,24 @@
.about-map { .about-map {
position: absolute; position: absolute;
z-index: 0; z-index: 0;
width: 65%;
margin-left: 35%;
margin-top: -16%; margin-top: -16%;
width: 65%;
@media (min-width: 0) {
display: none;
}
@media (min-width: @screen-md-min) {
display: block;
margin-left: 40%;
}
@media (min-width: @screen-lg-min) {
display: block;
margin-left: 35%;
}
img { img {
width: 100%; width: 100%;
} }

@ -0,0 +1,40 @@
.modal-consultation {
img {
float: left;
width: 30%; }
.forms {
padding-left: 35%;
h3 {
margin-top: 18px;
}
label {
width: 25%;
}
.help-text {
margin-top: 10px;
margin-bottom: 5px;
}
button {
margin-top: 15px;
}
.form-success {
margin-top: 20px;
font-size: 22px;
}
}
}
.consultation {
.btn-consultation:extend(.btn-default, .btn-xs) {}
}
.content {
.btn-consultation:extend(.btn-primary) {}
}

@ -18,6 +18,7 @@
@import 'blog.less'; @import 'blog.less';
@import 'consultation.less';
@import url(http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic,700italic|Roboto+Slab:700,400&subset=cyrillic-ext,latin); @import url(http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic,700italic|Roboto+Slab:700,400&subset=cyrillic-ext,latin);

@ -25,7 +25,7 @@
.people-description { .people-description {
width: 80%; width: 80%;
font-size: 16px; font-size: 15px;
padding-top: 25px; padding-top: 25px;
padding-left: 140px; padding-left: 140px;

@ -1,4 +1,4 @@
{% load i18n thumbnail shuffle %} {% load cms_tags i18n thumbnail shuffle %}
<div class="plugin plugin-people"> <div class="plugin plugin-people">
{% if people_groups %} {% if people_groups %}

@ -1,7 +1,7 @@
{% load cms_tags staticfiles sekizai_tags menu_tags i18n %} {% load cms_tags staticfiles sekizai_tags menu_tags i18n %}
{% load pipeline %} {% load pipeline %}
<!doctype html> <!doctype html>
<html> <html ng-app="zuykov">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>{% block title %}Zuykov and partners{% endblock title %}</title> <title>{% block title %}Zuykov and partners{% endblock title %}</title>
@ -14,8 +14,10 @@
{% render_block "css" %} {% render_block "css" %}
</head> </head>
<body> <body>
{% cms_toolbar %} {% cms_toolbar %}
<div class="container"> <div class="container">
<div class="wrapper"> <div class="wrapper">
<div class="header-logo"> <div class="header-logo">
<a href="/"> <a href="/">
@ -30,25 +32,18 @@
</ul> </ul>
<p class="city">{% trans 'Moscow' %}</p> <p class="city">{% trans 'Moscow' %}</p>
<div class="consultation"> <div class="consultation">
<h5>{% trans 'Free Consultation' %} </h5> {% static_placeholder 'consultation' %}
<h3><nobr>+7 800 700-16-37</nobr></h3>
<button type="button" class="btn btn-default btn-xs">{% trans 'Callback' %}</button>
<div class="email">
<a href="mailto:info@zuykov.{% if current_language == "ru" %}ru{% else %}com{% endif %}">info@zuykov.{% if current_language == "ru" %}ru{% else %}com{% endif %}</a>
</div>
</div> </div>
</div> </div>
</div> </div>
<h4 class="header-menu-font">{% trans 'Our Services' %}</h4> {% show_menu 0 1 100 100 "menu_header.html" %}
<div class="background-line-pattern"></div>
<ul class="list-unstyled list-inline header-menu header-menu-font">
{% show_menu 0 1 100 100 "menu.html" %}
</ul>
{% block content %}{% endblock content %} {% block content %}{% endblock content %}
<footer> <footer>
{% static_placeholder 'footer' %}
<div class="background-line-pattern"></div> <div class="background-line-pattern"></div>
<div class="about"> <div class="about">
<a href="/"> <a href="/">

@ -0,0 +1,70 @@
{% load cms_tags djangocms_forms_tags i18n sekizai_tags staticfiles %}
<div ng-controller="ModalFormCtrl">
<script type="text/ng-template" id="modalFormTemplate-{{ instance.id }}.html">
<div class="modal-body modal-consultation">
<img src="{% with 'imgs/phone.png' as image_static %}{% static image_static %}{% endwith %}">
<div class="forms" id="{{ instance.form_id }}">
{% if instance.title %}
<h3 class="title">{{ instance.title }}</h3>
{% endif %}
{% if instance.description %}
<div class="description">
{{ instance.description|safe }}
</div>
{% endif %}
<div class="form-wrapper">
<form action="{{ form.submission_url }}" method="POST" enctype="multipart/form-data">
<div class="form-errors" style="display:none;"></div>
{% for field in form.visible_fields %}
<div class="field-wrapper {{ field|input_class }} {{ field.css_classes }}">
{% if field.help_text %}
<div id="help-text-{{ field.auto_id }}" class="help-text">{{ field.help_text|safe }}</div>
{% endif %}
<div class="field-errors" style="display:none;"></div>
{% if field|is_checkbox %}
{{ field }}
{% endif %}
<label for="{{ field.id_for_label }}">
{{ field.label }}
</label>
{% if not field|is_checkbox %}
{{ field }}
{% endif %}
</div>
{% endfor %}
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="button-wrapper submit">
<button class="form-button btn btn-primary" type="submit" value="{{ instance.submit_btn_txt }}">{{ instance.submit_btn_txt }}</button>
</div>
</form>
</div>
<div class="form-success" style="display: none;">
{% if instance.post_submit_msg %}
<p>{{ instance.post_submit_msg|safe }}</p>
{% else %}
{% blocktrans %}
<h3>Submission successful</h3>
<p>Thank You! Your form has been successfully submitted!</p>
{% endblocktrans %}
{% endif %}
</div>
</div>
</div>
</form>
</div>
</script>
<button class="btn btn-consultation" ng-click="open('{{ instance.id }}')" value="">{{ instance.title }}</button>
</div>
{% addtoblock "js" %}
<script src="{% static 'js/djangocms_forms/libs/jquery.form.min.js' %}"></script>
<script src="{% static 'js/djangocms_forms/djangocms_forms.js' %}"></script>
{% endaddtoblock %}

@ -1,16 +1,7 @@
{% load i18n menu_tags cache %} {% load i18n menu_tags cache %}
{% for child in children %} {% for child in children %}
<li {% if child.selected %}class="active"{% endif %}> <li {% if child.selected %}class="active"{% endif %}>
{% if child.children %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ child.get_menu_title }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% else %}
<a href="{{ child.get_absolute_url }}"><span>{{ child.get_menu_title }}</span></a> <a href="{{ child.get_absolute_url }}"><span>{{ child.get_menu_title }}</span></a>
{% endif %}
</li> </li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %} {% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %} {% endfor %}

@ -0,0 +1,14 @@
{% load i18n menu_tags cache %}
{{ children.count }}
{% if children|length > 1 %}
<h4 class="header-menu-font">{% trans 'Our Services' %}</h4>
<div class="background-line-pattern"></div>
<ul class="list-unstyled list-inline header-menu header-menu-font">
{% for child in children %}
<li {% if child.selected %}class="active"{% endif %}>
<a href="{{ child.get_absolute_url }}"><span>{{ child.get_menu_title }}</span></a>
</li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %}
</ul>
{% endif %}

@ -1,5 +1,5 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load cms_tags i18n menu_tags %} {% load cms_tags i18n menu_tags %}
{% block title %}{% page_attribute "page_title" %}{% endblock title %} {% block title %}{% page_attribute "page_title" %}{% endblock title %}
@ -14,7 +14,8 @@
<div class="menu"> <div class="menu">
<h5>{% show_breadcrumb 0 "menu/sub_menu_title.html" 0 %}</h5> <h5>{% show_breadcrumb 0 "menu/sub_menu_title.html" 0 %}</h5>
<ul class="list-unstyled"> <ul class="list-unstyled">
{% show_menu 1 0 100 100 'menu.html' %} {{ node.level }}
{% show_menu 1 100 0 1 'menu.html' %}
</ul> </ul>
</div> </div>
<div class="content"> <div class="content">

Loading…
Cancel
Save