parent
d6fabb78ca
commit
d03d77a66a
38 changed files with 1222 additions and 33 deletions
@ -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,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')]), |
||||||
|
), |
||||||
|
] |
||||||
@ -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) |
||||||
@ -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 |
||||||
|
|
||||||
|
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'); |
||||||
|
}; |
||||||
|
}); |
||||||
@ -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) {} |
||||||
|
} |
||||||
@ -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 %} |
||||||
Loading…
Reference in new issue