Merge pull request #7 from euclidian/develop

Move Haiti Data to Kartoza's standard project structure
This commit is contained in:
sbsimo authored and GitHub committed 2017-08-31 11:27:41 +02:00
commit e5fd5ddcdf
596 files changed
+26170 -8843

No files matched your search

+45 -12
View File
@@ -1,13 +1,10 @@
.idea/
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
@@ -25,17 +22,14 @@ var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
@@ -45,23 +39,62 @@ htmlcov/
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Downstream Project
downloaded/
geoserver/
uploaded/
development.db
development.db-journal
# PyCharm
.idea
venv
*.pyc
*.*~
vagrant-fabric-lxc
django_project/media/images
visual_changelog.db
.vagrant
node_modules
id_dsa.pub
id_rsa.pub
docs/build
fabgis_resources
private.py
# Vim leftovers
# project specifc
django_project/core/settings/secret.py
xmlrunner
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos
# into it.
#PyCharm
# Virtual env
# Node
django_project/static
# Working data not intended to be versioned
data_for_import
scrap.html
.pycharm_helpers
.sudo_as_admin_successful
# Pg cluster for docker
deployment/pg
# Template for apt-cacher
# static and media dirs
deployment/static
deployment/media
deployment/docker/71-apt-cacher-ng
django_project/geonode
django_project/celerybeat-schedule
# local media
django_project/media
# OSX Crap
deployment/backups
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+30
View File
@@ -0,0 +1,30 @@
# Haitidata
You should write some docs, it's good for the soul.
# Docker installation
## Install docker
This will install an Haitidata container
Makes sure to have docker-compose installed
```
sudo apt-get install python-pip
sudo pip install docker-compose
```
## Get project code
Clone the repo:
```
git clone https://github.com/HaitiData/haitidata.git
```
## Run project
Run the docker container:
```
cd deployment
make deploy
make update-migrations-localization:
```
then you can visit http://0.0.0.0:33300```
-84
View File
@@ -1,84 +0,0 @@
Haitidata
========================
You should write some docs, it's good for the soul.
Installation
------------
Install geonode with::
$ sudo add-apt-repository ppa:geonode/stable
$ sudo apt-get update
$ sudo apt-get install geonode
Create a new template based on the geonode example project.::
$ django-admin startproject my_geonode --template=https://github.com/GeoNode/geonode-project/archive/2.6.zip -epy,rst
$ sudo pip install -e my_geonode
.. note:: You should NOT use the name geonode for your project as it will conflict with the default geonode package name.
Usage
-----
Rename the local_settings.py.sample to local_settings.py and edit it's content by setting the SITEURL and SITENAME.
Edit the file /etc/apache2/sites-available/geonode and change the following directive from:
WSGIScriptAlias / /var/www/geonode/wsgi/geonode.wsgi
to:
WSGIScriptAlias / /path/to/my_geonode/my_geonode/wsgi.py
To avoid having to grant apache permissions (i.e. www-data user and group) to your home dir where you likely setup the geonode-project; you may want to instead copy the wsgi.py file next to geonode.wsgi and replace the file name instead of the entire path.
$ cp /path/to/my_geonode/my_geonode/wsgi.py /var/www/geonode/wsgi/wsgi.py
Add the "Directory" directive for your folder like the following example:
<Directory "/home/vagrant/my_geonode/my_geonode/">
Order allow,deny
Options Indexes FollowSymLinks
Allow from all
Require all granted
IndexOptions FancyIndexing
</Directory>
Restart apache::
$ sudo service apache2 restart
Edit the templates in my_geonode/templates, the css and images to match your needs.
In the my_geonode folder run::
$ python manage.py collectstatic
Github Considerations
------------------------
While it is helpful to recommit your django project wrapper back to a distributed version control repository.
* It is also important to remember that production instances will store security information in the local_settings.py
* Admin/Devs should always remember to exclude this file in the .gitignore file in the same folder as the .git::
$ nano .gitignore
/{project}/local_settings.py
save, make sure the file is also removed from git cache::
$ git rm -f --cache //local_settings.py
$ git status
confirm the file is no longer staged for the next commit or that if it is as "removed"
+386
View File
@@ -0,0 +1,386 @@
PROJECT_ID := haitidata
PRODUCTION_HOST := haitidata.com
SHELL := /bin/bash
# ----------------------------------------------------------------------------
# P R O D U C T I O N C O M M A N D S
# ----------------------------------------------------------------------------
fresh-web: build permissions web
# Use this for fresh build (it will restore with empty stable database)
fresh-deploy: fresh-web
@docker exec -t -i $(PROJECT_ID)-db su - postgres -c "dropdb gis"
@docker exec -t -i $(PROJECT_ID)-db su - postgres -c "createdb -O docker -T template_postgis gis"
@docker exec -t -i $(PROJECT_ID)-db pg_restore /fresh-backups/fresh-database.dmp | docker exec -i $(PROJECT_ID)-db su - postgres -c "psql gis"
default: web
run: build permissions web migrate collectstatic
deploy: run
@echo
@echo "------------------------------------------------------------------"
@echo "Bringing up fresh instance "
@echo "You can access it on http://localhost:63300"
@echo "------------------------------------------------------------------"
build:
@echo
@echo "------------------------------------------------------------------"
@echo "Building in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) build uwsgi
@docker-compose -p $(PROJECT_ID) build uwsgi-ephemeral
web:
@echo
@echo "------------------------------------------------------------------"
@echo "Running in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) up -d web
@docker-compose -p $(PROJECT_ID) up -d uwsgi-ephemeral
@# Dont confuse this with the dbbackup make command below
@# This one runs the postgis-backup cron container
@# We add --no-recreate so that it does not destroy & recreate the db container
@docker-compose -p $(PROJECT_ID) up --no-recreate --no-deps -d dbbackups
permissions:
# Probably we want something more granular here....
# Your sudo password will be needed to set the file permissions
# on logs, media, static and pg dirs
@if [ ! -d "logs" ]; then mkdir logs; fi
@if [ ! -d "media" ]; then mkdir media; fi
@if [ ! -d "static" ]; then mkdir static; fi
@if [ ! -d "backups" ]; then mkdir backups; fi
@if [ -d "logs" ]; then sudo chmod -R a+rwx logs; fi
@if [ -d "media" ]; then sudo chmod -R a+rwx media; fi
@if [ -d "static" ]; then sudo chmod -R a+rwx static; fi
@if [ -d "backups" ]; then sudo chmod -R a+rwx backups; fi
db:
@echo
@echo "------------------------------------------------------------------"
@echo "Running db in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) up -d db
nginx:
@echo
@echo "------------------------------------------------------------------"
@echo "Running nginx in production mode"
@echo "Normally you should use this only for testing"
@echo "In a production environment you will typically use nginx running"
@echo "on the host rather if you have a multi-site host."
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) up -d nginx
@echo "Site should now be available at http://localhost"
migrate:
@echo
@echo "------------------------------------------------------------------"
@echo "Running migrate static in production mode"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)_uwsgi-ephemeral_1 /bin/bash -c "\
python manage.py migrate"
update-migrations:
@echo
@echo "------------------------------------------------------------------"
@echo "Running update migrations in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) run uwsgi-ephemeral python manage.py makemigrations
update-migrations-localization:
@echo
@echo "------------------------------------------------------------------"
@echo "Running update migrations in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) run uwsgi bash -c "python manage.py makemigrations && python manage.py migrate"
collectstatic:
@echo
@echo "------------------------------------------------------------------"
@echo "Collecting static in production mode"
@echo "------------------------------------------------------------------"
#We need to run collect static in the same context as the running
# uwsgi-ephemeral container it seems so I use docker exec here
# no -it flag so we can run over remote shell
@docker-compose -p $(PROJECT_ID) run uwsgi-ephemeral python manage.py collectstatic --noinput
reload:
@echo
@echo "------------------------------------------------------------------"
@echo "Reload django project in production mode"
@echo "------------------------------------------------------------------"
# no -it flag so we can run over remote shell
@docker exec $(PROJECT_ID)-uwsgi uwsgi --reload /tmp/django.pid
kill:
@echo
@echo "------------------------------------------------------------------"
@echo "Killing in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) kill
kill-uwsgi:
@echo
@echo "------------------------------------------------------------------"
@echo "Killing in uwsgi production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) kill uwsgi
kill-uwsgi-ephemeral:
@echo
@echo "------------------------------------------------------------------"
@echo "Killing in uwsgi production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) kill uwsgi-ephemeral
rm: dbbackup rm-only
rm-only: kill
@echo
@echo "------------------------------------------------------------------"
@echo "Removing production instance!!! "
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) rm
logs:
@echo
@echo "------------------------------------------------------------------"
@echo "Showing uwsgi logs in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) logs uwsgi
dblogs:
@echo
@echo "------------------------------------------------------------------"
@echo "Showing db logs in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) logs db
nginxlogs:
@echo
@echo "------------------------------------------------------------------"
@echo "Showing nginx logs in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) logs web
shell:
@echo
@echo "------------------------------------------------------------------"
@echo "Shelling in in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) run uwsgi-ephemeral /bin/bash
superuser:
@echo
@echo "------------------------------------------------------------------"
@echo "Creating a superuser in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) run uwsgi-ephemeral python manage.py createsuperuser
reviewaccess:
@echo
@echo "------------------------------------------------------------------"
@echo "Creating review permissions in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) run uwsgi-ephemeral python manage.py create_review_permissions
dbbash:
@echo
@echo "------------------------------------------------------------------"
@echo "Bashing in to production database"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)-db /bin/bash
dbsnapshot:
@echo
@echo "------------------------------------------------------------------"
@echo "Grab a quick snapshot of the database and place in the host filesystem"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)-db /bin/bash -c "PGPASSWORD=docker pg_dump -Fc -h localhost -U docker -f /tmp/$(PROJECT_ID)-snapshot.dmp gis"
@docker cp $(PROJECT_ID)-db:/tmp/$(PROJECT_ID)-snapshot.dmp .
@docker exec -t -i $(PROJECT_ID)-db /bin/bash -c "rm /tmp/$(PROJECT_ID)-snapshot.dmp"
@ls -lahtr *.dmp
dbschema:
@echo
@echo "------------------------------------------------------------------"
@echo "Print the database schema to stdio"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)-db /bin/bash -c "PGPASSWORD=docker pg_dump -s -h localhost -U docker gis"
dbshell:
@echo
@echo "------------------------------------------------------------------"
@echo "Shelling in in production database"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)-db psql -U docker -h localhost gis
dbrestore:
@echo
@echo "------------------------------------------------------------------"
@echo "Restore dump from backups/latest.dmp in production mode"
@echo "------------------------------------------------------------------"
@# - prefix causes command to continue even if it fails
-@docker exec -t -i $(PROJECT_ID)-db su - postgres -c "dropdb gis"
@docker exec -t -i $(PROJECT_ID)-db su - postgres -c "createdb -O docker -T template_postgis gis"
@docker exec -t -i $(PROJECT_ID)-db pg_restore /backups/latest.dmp | docker exec -i $(PROJECT_ID)-db su - postgres -c "psql gis"
dbbackup:
@echo
@echo "------------------------------------------------------------------"
@echo "Create `date +%d-%B-%Y`.dmp in production mode"
@echo "Warning: backups/latest.dmp will be replaced with a symlink to "
@echo "the new backup."
@echo "------------------------------------------------------------------"
@# - prefix causes command to continue even if it fails
@# Explicitly don't use -it so we can call this make target over a remote ssh session
@docker exec $(PROJECT_ID)-db-backups /backups.sh
@docker exec $(PROJECT_ID)-db-backups cat /var/log/cron.log | tail -2 | head -1 | awk '{print $4}'
-@if [ -f "backups/latest.dmp" ]; then rm backups/latest.dmp; fi
# backups is intentionally missing from front of first clause below otherwise symlink comes
# out with wrong path...
@ln -s `date +%Y`/`date +%B`/PG_$(PROJECT_ID)_gis.`date +%d-%B-%Y`.dmp backups/latest.dmp
@echo "Backup should be at: backups/`date +%Y`/`date +%B`/PG_$(PROJECT_ID)_gis.`date +%d-%B-%Y`.dmp"
sentry:
@echo
@echo "--------------------------"
@echo "Running sentry production mode"
@echo "--------------------------"
@docker-compose -p $(PROJECT_ID) up -d sentry
maillogs:
@echo
@echo "------------------------------------------------------------------"
@echo "Showing smtp logs in production mode"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)-smtp tail -f /var/log/mail.log
mailerrorlogs:
@echo
@echo "------------------------------------------------------------------"
@echo "Showing smtp error logs in production mode"
@echo "------------------------------------------------------------------"
@docker exec -t -i $(PROJECT_ID)-smtp tail -f /var/log/mail.err
mediasync:
@echo
@echo "------------------------------------------------------------------"
@echo "Syncing media files and secret.py from live server"
@echo "------------------------------------------------------------------"
@rsync -av --progress $(PRODUCTION_HOST):/home/web/haitidata/deployment/media/ media
@rsync -av --progress $(PRODUCTION_HOST):/home/web/haitidata/django_project/core/settings/secret.py ../django_project/core/settings/
dbsync:
@echo
@echo "------------------------------------------------------------------"
@echo "Syncing database files from live server"
@echo "------------------------------------------------------------------"
-@ssh $(PRODUCTION_HOST) "cd /home/web/haitidata/deployment; make dbbackup"
@rsync -av --progress $(PRODUCTION_HOST):/home/web/haitidata/deployment/backups/ backups
create-machine:
@echo
@echo "------------------------------------------------------------------"
@echo "Creating a docker machine."
@echo "------------------------------------------------------------------"
@docker-machine create -d virtualbox $(PROJECT_ID)
enable-machine:
@echo
@echo "------------------------------------------------------------------"
@echo "Enabling docker machine."
@echo "------------------------------------------------------------------"
@echo "eval \"$(docker-machine env mezzanine)\""
create-workspace:
@echo
@echo "------------------------------------------------------------------"
@echo "Create geoserver workspace."
@echo "------------------------------------------------------------------"
@curl -v -u admin:geoserver -XPOST -H "Content-type: text/xml" -d "<workspace><name>geonode</name><default>true</default></workspace>" http://localhost:33308/geoserver/rest/workspaces
# ----------------------------------------------------------------------------
# DEVELOPMENT C O M M A N D S
# --no-deps will attach to prod deps if running
# after running you will have ssh and web ports open (see dockerfile for no's)
# and you can set your pycharm to use the python in the container
# Note that pycharm will copy in resources to the /root/ user folder
# for pydevd etc. If they dont get copied, restart pycharm...
# ----------------------------------------------------------------------------
devweb: db
@echo
@echo "------------------------------------------------------------------"
@echo "Running in DEVELOPMENT mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) up --no-deps -d devweb
build-devweb: db
@echo
@echo "------------------------------------------------------------------"
@echo "Building devweb"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) build devweb
# --------------- help --------------------------------
help:
@echo "* **build** - builds all required containers."
@echo "* **build-devweb** - build the development container. See [development notes](README-dev.md)."
@echo "* **collectstatic** - run the django collectstatic command."
@echo "* **create-machine** ."
@echo "* **db** - build and run the db container."
@echo "* **dbbackup** - make a snapshot of the database, saving it to deployments/backups/YYYY/MM/project-DDMMYYYY.dmp. It also creates a symlink to backups/latest.dmp for the latest backup."
@echo "* **dbbash** - open a bash shell inside the database container."
@echo "* **dblogs** - view the database logs."
@echo "* **dbrestore** - restore deployment/backups/latest.dmp over the active database. Will delete any existing data in your database and replace with the restore, so **use with caution**."
@echo "* **dbschema** - dump the current db schema (without data) to stdio. Useful if you want to compare changes between instances."
@echo "* **dbshell** - get a psql prompt into the db container. "
@echo "* **dbsnapshot** - as above but makes the backup as deployment/snapshot.smp - replacing any pre-existing snapshot."
@echo "* **dbsync** - use this from a development or offsite machine. It will rsync all database backups from deployment/backups to your offsite machine."
@echo "* **default** ."
@echo "* **deploy** ."
@echo "* **devweb** - create an ssh container derived from uwsgi that can be used as a remote interpreter for PyCharm. See [development notes](README-dev.md)."
@echo "* **enable-machine** - "
@echo "* **kill** - kills all running containers. Does not remove them."
@echo "* **logs** - view the logs of all running containers. Note that you can also view individual logs in the deployment/logs directory."
@echo "* **mailerrorlogs** - View the error logs from the mail server."
@echo "* **maillogs** - view the transaction logs from the mail server."
@echo "* **mediasync** - use this from a development or offsite machine. It will rsync all media backups from deployment/media to your offsite machine."
@echo "* **migrate** - run any pending migrations. "
@echo "* **nginx** - builds and runs the nginx container."
@echo "* **nginxlogs** - view just the nginx activity logs."
@echo "* **permissions** - Update the permissions of shared volumes. Note this will destroy any existing permissions you have in place."
@echo "* **reload** - reload the uwsgi process. Useful when you need django to pick up any changes you may have deployed."
@echo "* **rm** - remove all containers."
@echo "* **rm-only** - remove any containers without trying to kill them first. "
@echo "* **run** - builds and runs the complete orchestrated set of containers."
@echo "* **sentry** - **currently not working I think.** The idea is to spin up a sentry instance together with your app for fault reporting."
@echo "* **shell** - open a bash shell in the uwsgi (where django runs) container."
@echo "* **superuser** - create a django superuser account."
@echo "* **update-migrations** - freshen all migration definitions to match the current code base."
@echo "* **web** - same as **run** - runs the production site."
worker:
@echo
@echo "------------------------------------------------------------------"
@echo "Running worker production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) up -d worker
workerlogs:
@echo
@echo "------------------------------------------------------------------"
@echo "Showing celery worker logs in production mode"
@echo "------------------------------------------------------------------"
@docker-compose -p $(PROJECT_ID) logs worker
+99
View File
@@ -0,0 +1,99 @@
# Deploying with docker
**Note:** This documentation is intentionally generic so that it can
be copy-pasted between projects - do not put project specific details here.
This document explains how to do various sysadmin related tasks when your
site has been deployed under docker. These deployment modes are supported:
* **production**: no debug etc is enabled, has its own discrete database. Configure
your production environment in core.settings.prod_docker - this
DJANGO_SETTINGS_MODULE is used when running in production mode.
* **staging**: Configure your staging environment in core.settings.staging_docker -
this DJANGO_SETTINGS_MODULE is used when running in production mode.
# Build your docker images and run them
## Production
You can simply run the provided script and it will build and deploy the docker
images for you in **production mode**.
```
cd deployment
# allow pg volume to be written to
sudo chmod -R a+rwX pg/postgres_data/
make deploy
sudo chmod -R a+rwX static
```
Now point your browser at the ip of the web container on port 8080 or to the
host port mapping as defined in the fig.yml file.
To make a superuser account do:
```
make shell
python manage.py createsuperuser
exit
```
## Staging
The procedure is exactly the same as production, but you should preceed
each command with 'staging' e.g. ``make staging-deploy``.
**Note:** VERY IMPORTANT - for staging deployment you should use a **separate
git checkout** from the production checkout as the code from the git checkout
is shared into the source tree.
## Using make
The following key make commands are provided for production:
* **build** - build production containers
* **run** - builds then runs db and uwsgi services
* **collectstatic** - collect static in production instance
* **migrate** - run django migrations in production instance
Additional make commands are provided in the Makefile - please see there
for details.
#### Arbitrary commands
Running arbitrary management commands is easy
## Setup nginx reverse proxy
You should create a new nginx virtual host - please see
``*-nginx.conf`` in the deployment directory for examples. There is
one provided for production and one for staging.
Simply add the example file (renaming them as needed) to your
``/etc/nginx/sites-enabled/`` directory and then modify the contents to
match your local filesystem paths. Then use
```
sudo nginx -t
```
To verify that your configuration is correct and then reload / restart nginx
e.g.
```
sudo /etc/init.d/nginx restart
```
### Managing containers
Please refer to the general [fig documentation](http://www.fig.sh/cli.hyml)
for further notes on how to manage the infrastructure using fig.
# Configuration options
You can configure the base port used and various other options like the
image organisation namespace and postgis user/pass by editing the ``fig*.yml``
files.
+197
View File
@@ -0,0 +1,197 @@
#
# Production server with UWSGI configured to run on port 8080
#
# docker-compose build
# docker-compose up -d web
#
# See accompanying Make commands for easy collectstatic etc.
rabbitmq:
image: library/rabbitmq
hostname: rabbitmq
environment:
- RABBIT_PASSWORD=rabbit_test_password
- USER=rabbit_user
- RABBITMQ_NODENAME=rabbit
smtp:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-smtp
image: catatnight/postfix
hostname: postfix
environment:
# You could change this to something more suitable
- maildomain=kartoza.com
- smtp_user=noreply:docker
restart: always
db:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-db
image: kartoza/postgis:9.4-2.1
volumes:
- ./pg/postgres_data:/var/lib/postgresql
- ./backups:/backups
- ./fresh-backups:/fresh-backups
environment:
- USERNAME=docker
- PASS=docker
restart: always
ports:
- "33305:5432"
uwsgi-base:
# Note you cannot scale if you use conteiner_name
build: docker
hostname: uwsgi
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- GEOSERVER_PUBLIC_LOCATION=http://0.0.0.0:33300/api/geoserver/
# Set your locale - you need to ensure this is created in Dockerfile too...
- LC_ALL=en_ZA.UTF-8
volumes:
- ../django_project:/home/web/django_project
- ./static:/home/web/static:rw
- ./media:/home/web/media:rw
- ./reports:/home/web/reports
- ./logs:/var/log/
user: root
uwsgi-ephemeral:
extends: uwsgi-base
links:
- smtp:smtp
- db:db
user: root
restart: on-failure:5
uwsgi:
# Note you cannot scale if you use conteiner_name
extends: uwsgi-base
container_name: haitidata-uwsgi
links:
- smtp:smtp
- db:db
- geoserver:geoserver
restart: always
dbbackups:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-db-backups
image: kartoza/pg-backup:9.4
hostname: pg-backups
volumes:
- ./backups:/backups
links:
- db:db
environment:
# take care to let the project name below match that
# declared in the top of the makefile
- DUMPPREFIX=PG_haiti
# These are all defaults anyway, but setting explicitly in
# case we ever want to ever use different credentials
- PGUSER=docker
- PGPASSWORD=docker
- PGPORT=5432
- PGHOST=db
- PGDATABASE=gis
restart: always
# This is normally the main entry point for a production server
web:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-web
image: nginx
hostname: nginx
volumes:
- ./sites-enabled:/etc/nginx/conf.d:ro
# I dont use volumes_from as I want to use the ro modifier
- ./static:/home/web/static:ro
- ./media:/home/web/media:ro
- ./logs:/var/log/nginx
# - /etc/letsencrypt:/etc/letsencrypt
- ./webroot-path:/home/web/webroot-path
links:
- uwsgi:uwsgi
- geoserver:geoserver
ports:
- "33300:8080"
restart: always
# This is the entry point for a development server.
# Run with --no-deps to run attached to the services
# from produ environment if wanted
devweb:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-dev-web
build: docker
dockerfile: Dockerfile-dev
hostname: haitidata-dev-web
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- PYTHONPATH=/home/web/django_project
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- GEOSERVER_PUBLIC_LOCATION=http://0.0.0.0:33303/api/geoserver/
volumes:
- ../django_project:/home/web/django_project
- ./static:/home/web/static
- ./media:/home/web/media
- ./reports:/home/web/reports
- ./logs:/var/log/
links:
- smtp:smtp
- db:db
- rabbitmq:rabbitmq
- geoserver:geoserver
ports:
# for django test server
- "33303:8080"
# for ssh
- "33302:22"
worker:
build: docker
hostname: worker
command: celery worker -A config.celery -l info --beat
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- DATABASE_QGIS_HOST=db_gis
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- C_FORCE_ROOT=true
volumes:
- ../django_project:/home/web/django_project
- ./static:/home/web/static
- ./media:/home/web/media
- ./reports:/home/web/reports
- ./logs:/var/log/
links:
- smtp:smtp
- db:db
- rabbitmq:rabbitmq
restart: on-failure:5
geoserver:
image: kartoza/geoserver
container_name: haitidata-geoserver
ports:
- "33308:8080"
@@ -0,0 +1,4 @@
#Acquire::http { Proxy "http://192.168.0.106:3142"; };
#Acquire::http { Proxy "http://192.168.2.9:3142"; };
#Acquire::http { Proxy "http://192.168.0.131:3142"; };
#Acquire::http { Proxy "http://192.168.1.13:3142"; };
+60
View File
@@ -0,0 +1,60 @@
#--------- Generic stuff all our Dockerfiles should start with so we get caching ------------
# Note this base image is based on debian
FROM kartoza/django-base
MAINTAINER Muhammad Anis<anis@kartoza.com>
#RUN ln -s /bin/true /sbin/initctl
# Use local cached debs from host (saves your bandwidth!)
# Change ip below to that of your apt-cacher-ng host
# Or comment this line out if you do not with to use caching
ADD 71-apt-cacher-ng /etc/apt/apt.conf.d/71-apt-cacher-ng
# Pandoc needed to generate rst dumps, uic compressor needed for django-pipeline
RUN apt-get update -y
# Set the locale - change to your preferred locale ... We use South African english
# We do this as cartridge (ecommerce platform for mezzanine) relies on
# the locale to set the correct number of decimal places for the MoneyField
RUN echo "deb http://ftp.debian.org/debian jessie main" >> /etc/apt/sources.list.d/gdal.list
RUN apt-get update
RUN apt-get install locales && \
echo "en_ZA.UTF-8 UTF-8" >> /etc/locale.gen && \
locale-gen en_ZA.UTF-8
RUN apt-get install libgdal-dev -y
ENV LANG en_ZA.UTF-8
ENV LANGUAGE en_ZA:en
ENV LC_ALL en_ZA.UTF-8
ENV CPLUS_INCLUDE_PATH /usr/include/gdal
ENV C_INCLUDE_PATH /usr/include/gdal
ENV TEST a
ADD REQUIREMENTS.txt /REQUIREMENTS.txt
RUN pip install -r /REQUIREMENTS.txt
RUN pip uninstall -y South
RUN pip install uwsgi
RUN pip uninstall geonode-dialogos -y
RUN pip install git+https://github.com/meomancer/geonode-dialogos.git
RUN pip uninstall geonode-agon-ratings -y
RUN pip install git+https://github.com/euclidian/custom-agon-ratings
RUN pip uninstall Django -y
RUN pip install Django==1.8.18
RUN pip uninstall django-oauth-toolkit -y
RUN pip install django-oauth-toolkit==0.12.0
RUN pip uninstall django-user-accounts -y
RUN pip install git+https://github.com/GeoNode/geonode-user-accounts@invite-user
RUN apt-get install gdal-bin
# Open port 8080 as we will be running our uwsgi socket on that
EXPOSE 8080
#USER www-data
WORKDIR /home/web/django_project
CMD ["uwsgi", "--env", "LC_ALL=en_ZA.UTF-8", "--ini", "/uwsgi.conf"]
+68
View File
@@ -0,0 +1,68 @@
#--------- Generic stuff all our Dockerfiles should start with so we get caching ------------
# Note this base image is based on debian
FROM kartoza/django-base
MAINTAINER Muhammad Anis<anis@kartoza.com>
#RUN ln -s /bin/true /sbin/initctl
# Use local cached debs from host (saves your bandwidth!)
# Change ip below to that of your apt-cacher-ng host
# Or comment this line out if you do not with to use caching
# ADD 71-apt-cacher-ng /etc/apt/apt.conf.d/71-apt-cacher-ng
# Pandoc needed to generate rst dumps, uic compressor needed for django-pipeline
RUN apt-get update -y
# Set the locale - change to your preferred locale ... We use South African english
# We do this as cartridge (ecommerce platform for mezzanine) relies on
# the locale to set the correct number of decimal places for the MoneyField
RUN echo "deb http://ftp.debian.org/debian jessie main" >> /etc/apt/sources.list.d/gdal.list
RUN apt-get update
RUN apt-get install locales && \
echo "en_ZA.UTF-8 UTF-8" >> /etc/locale.gen && \
locale-gen en_ZA.UTF-8
RUN apt-get install libgdal-dev -y
ENV LANG en_ZA.UTF-8
ENV LANGUAGE en_ZA:en
ENV LC_ALL en_ZA.UTF-8
ENV CPLUS_INCLUDE_PATH /usr/include/gdal
ENV C_INCLUDE_PATH /usr/include/gdal
ADD REQUIREMENTS.txt /REQUIREMENTS.txt
RUN pip install -r /REQUIREMENTS.txt
RUN pip uninstall -y South
RUN pip install uwsgi
RUN pip uninstall geonode-dialogos -y
RUN pip install git+https://github.com/meomancer/geonode-dialogos.git
RUN pip uninstall geonode-agon-ratings -y
RUN pip install git+https://github.com/euclidian/custom-agon-ratings
RUN pip uninstall Django -y
RUN pip install Django==1.8.18
RUN pip uninstall django-oauth-toolkit -y
RUN pip install django-oauth-toolkit==0.12.0
RUN pip uninstall django-user-accounts -y
RUN pip install git+https://github.com/GeoNode/geonode-user-accounts@invite-user
RUN apt-get install gdal-bin
# Open port 8080 as we will be running our uwsgi socket on that
EXPOSE 8080
#USER www-data
WORKDIR /home/web
# Download repository
RUN git clone https://github.com/euclidian/haitidata
RUN make migrate
RUN make collectstatic
WORKDIR /home/web/django_project
CMD ["uwsgi", "--env", "LC_ALL=en_ZA.UTF-8", "--ini", "/uwsgi.conf"]
+41
View File
@@ -0,0 +1,41 @@
#--------- Generic stuff all our Dockerfiles should start with so we get caching ------------
# Note this base image is based on debian
FROM haitidata_uwsgi
MAINTAINER Muhammad Anis<anis@kartoza.com>
# Use local cached debs from host (saves your bandwidth!)
# Change ip below to that of your apt-cacher-ng host
# Or comment this line out if you do not with to use caching
ADD 71-apt-cacher-ng /etc/apt/apt.conf.d/71-apt-cacher-ng
# This section taken on 2 July 2015 from
# https://docs.docker.com/examples/running_ssh_service/
# Sudo is needed by pycharm when it tries to pip install packages
RUN apt-get update && apt-get install -y openssh-server sudo
RUN mkdir /var/run/sshd
RUN echo 'root:docker' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
# End of cut & paste section
ADD REQUIREMENTS-dev.txt /REQUIREMENTS-dev.txt
RUN pip install -r /REQUIREMENTS-dev.txt
ADD bashrc /root/.bashrc
# --------------------------------------------------------
# Open ports as needed
# --------------------------------------------------------
# Open port 8080 as we will be running our django dev server on
EXPOSE 8080
# Open port 22 as we will be using a remote interpreter from pycharm
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
+15
View File
@@ -0,0 +1,15 @@
django-nose
coverage
pep8>=1.5.7,<1.6
pylint
flake8==2.5.4
factory_boy
django-devserver
# documentation
Sphinx
# pdb plus plus
pdbpp
+42
View File
@@ -0,0 +1,42 @@
celery==3.1
Django==1.10
psycopg2
django-compressor
icalendar==3.0.1b2
geopy==0.95.1
filebrowser-safe==0.4.5
# https://github.com/getsentry/raven-python/issues/337
raven==5.8.1
django-sentry==1.13.5
requests==2.13.0
#cartridge requirement
cartridge==0.12.0
django-appconf==1.0.1
django-model-utils==2.3.1
django-reversion==1.9.3
django-sitetree==1.5.1
django-taggit==0.21.5
django-timezone-field==1.3
django-user-accounts==1.2.0
easy-thumbnails==2.2
html5lib==0.999999999
markdown==2.6.2
pytz==2015.6
pyyaml==3.11
ruamel.yaml==0.13.14
bleach==2.0.0
#geonode
django-geonode-client
git+https://github.com/GeoNode/django-osgeo-importer.git
django-jsonfield
python-dateutil
gdal==1.10.0
git+https://github.com/meomancer/GeoNode-1.git
django-tastypie
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
# This is intended to be placed in the docker dev environment so
# that the django project is in the path when you log in
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
export PYTHONPATH=/home/web/django_project:$PYTHONPATH
export DJANGO_SETTINGS_MODULE=core.settings.dev_docker
cd /home/web/django_project
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
docker build -t kartoza/mezzanine .
+19
View File
@@ -0,0 +1,19 @@
[uwsgi]
# Touch this file to reload uwsgi
touch-reload = /tmp/touch-me-to-reload
chdir = /home/web/django_project
module = core.wsgi
master = true
pidfile=/tmp/django.pid
socket = 0.0.0.0:49360
workers = 4
cheaper = 2
env = DJANGO_SETTINGS_MODULE=core.settings.prod_docker
# disabled so we run in the foreground for docker
#daemonize = /tmp/django.log
reload-os-env
#uid = 1000
#gid = 1000
memory-report = true
harakiri = 20
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
from locust import HttpLocust, TaskSet, task
class HaitiData(TaskSet):
def on_start(self):
response = self.client.get("/account/login")
csrftoken = response.cookies['csrftoken']
self.client.post("/account/login/",
{"username": "admin",
"password": "admin"},
headers={"X-CSRFToken": csrftoken})
@task
def index(self):
self.client.get("/layers/geonode:madagascar_earthquake_cqmtpiu_tif_2017_08_23_08_59_10")
class HaitiUser(HttpLocust):
task_set = HaitiData
min_wait = 5000
max_wait = 15000
View File
File renamed without changes.
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
MYDATE=`date +%d-%B-%Y`
MONTH=$(date +%B)
YEAR=$(date +%Y)
cd /home/web/mezzanine.kartoza.com/deployment
MYBASEDIR=`pwd`/backups
MYBACKUPDIR=${MYBASEDIR}/${YEAR}/${MONTH}
mkdir -p ${MYBACKUPDIR}
cd ${MYBACKUPDIR}
docker exec -ti mezzanine-db /bin/bash -c "PGPASSWORD=docker pg_dump -Fc -f /tmp/latest.dmp -h localhost -U docker gis"
docker cp mezzanine-db:/tmp/latest.dmp PG_mezzanine-${MYDATE}.dmp
cd -
rm backups/latest.dmp
cd backups
ln -s ${MYBACKUPDIR}/PG_mezzanine-${MYDATE}.dmp latest.dmp
cd ..
File renamed without changes.
+18
View File
@@ -0,0 +1,18 @@
---
- hosts: haitidata_swarm
vars:
http_port: 80
max_clients: 200
tasks:
- name: pull haiti source code from github
git:
repo: https://github.com/euclidian/haitidata.git
dest: /tmp/web_haiti
- name: run migrate
make:
chdir: /tmp/web_haiti/deployment
target: migrate
- name: run collect static
make:
chdir: /tmp/web_haiti/deployment
target: collectstatic
+2
View File
@@ -0,0 +1,2 @@
[haitidata_swarm]
haitidata
+53
View File
@@ -0,0 +1,53 @@
upstream qgisug {
server 127.0.0.1:63300;
}
server {
# OTF gzip compression
gzip on;
gzip_min_length 860;
gzip_comp_level 5;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml application/x-javascript text/xml text/css application/json;
gzip_disable “MSIE [1-6].(?!.*SV1)”;
# the port your site will be served on
listen 443 ssl;
# the domain name it will serve for
server_name qgis.org.za;
ssl on;
ssl_certificate /etc/letsencrypt/live/qgis.org.za/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/qgis.org.za/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
location /.well-known/acme-challenge {
default_type "text/plain";
# set to webroot path
root /home/web/qgis.org.za/deployment/webroot-path;
}
charset utf-8;
# max upload size, adjust to taste
client_max_body_size 15M;
location / {
proxy_pass http://qgisug;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
server {
listen 80;
server_name qgis.org.za, foss4g-africa.org, www.foss4g-africa.org;
if ($host = 'www.foss4g-africa.org') {
return 301 https://foss4g-africa.org$request_uri;
}
return 301 https://$host$request_uri;
}
+7
View File
@@ -0,0 +1,7 @@
[
{rabbit, [
{default_user, <<“rabbit_admin”>>},
{default_pass, <<“rabbit_password”>>},
{tcp_listeners,[{“0.0.0.0″,5672}]}
]}
]
+2
View File
@@ -0,0 +1,2 @@
uwsgi:
scale: 3
+197
View File
@@ -0,0 +1,197 @@
#
# Production server with UWSGI configured to run on port 8080
#
# docker-compose build
# docker-compose up -d web
#
# See accompanying Make commands for easy collectstatic etc.
rabbitmq:
image: library/rabbitmq
hostname: rabbitmq
environment:
- RABBIT_PASSWORD=rabbit_test_password
- USER=rabbit_user
- RABBITMQ_NODENAME=rabbit
smtp:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-smtp
image: catatnight/postfix
hostname: postfix
environment:
# You could change this to something more suitable
- maildomain=kartoza.com
- smtp_user=noreply:docker
restart: always
db:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-db
image: kartoza/postgis:9.4-2.1
volumes:
- ./pg/postgres_data:/var/lib/postgresql
- ./backups:/backups
- ./fresh-backups:/fresh-backups
environment:
- USERNAME=docker
- PASS=docker
restart: always
ports:
- "33305:5432"
uwsgi-ephemeral:
image: muhammadanis/haitidata_uwsgi
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- GEOSERVER_PUBLIC_LOCATION=http://0.0.0.0:33300/api/geoserver/
# Set your locale - you need to ensure this is created in Dockerfile too...
- LC_ALL=en_ZA.UTF-8
links:
- smtp:smtp
- db:db
user: root
restart: on-failure:5
uwsgi:
# Note you cannot scale if you use conteiner_name
image: muhammadanis/haitidata_uwsgi
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- GEOSERVER_PUBLIC_LOCATION=http://0.0.0.0:33300/api/geoserver/
# Set your locale - you need to ensure this is created in Dockerfile too...
- LC_ALL=en_ZA.UTF-8
user: root
links:
- smtp:smtp
- db:db
- geoserver:geoserver
restart: always
dbbackups:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-db-backups
image: kartoza/pg-backup:9.4
hostname: pg-backups
volumes:
- ./backups:/backups
links:
- db:db
environment:
# take care to let the project name below match that
# declared in the top of the makefile
- DUMPPREFIX=PG_haiti
# These are all defaults anyway, but setting explicitly in
# case we ever want to ever use different credentials
- PGUSER=docker
- PGPASSWORD=docker
- PGPORT=5432
- PGHOST=db
- PGDATABASE=gis
restart: always
# This is normally the main entry point for a production server
web:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-web
image: nginx
hostname: nginx
volumes:
- ./sites-enabled:/etc/nginx/conf.d:ro
# I dont use volumes_from as I want to use the ro modifier
- ./static:/home/web/static:ro
- ./media:/home/web/media:ro
- ./logs:/var/log/nginx
# - /etc/letsencrypt:/etc/letsencrypt
- ./webroot-path:/home/web/webroot-path
links:
- uwsgi:uwsgi
- geoserver:geoserver
ports:
- "33300:8080"
restart: always
# This is the entry point for a development server.
# Run with --no-deps to run attached to the services
# from produ environment if wanted
devweb:
# Note you cannot scale if you use conteiner_name
container_name: haitidata-dev-web
build: docker
dockerfile: Dockerfile-dev
hostname: haitidata-dev-web
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- PYTHONPATH=/home/web/django_project
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- GEOSERVER_PUBLIC_LOCATION=http://0.0.0.0:33303/api/geoserver/
volumes:
- ../django_project:/home/web/django_project
- ./static:/home/web/static
- ./media:/home/web/media
- ./reports:/home/web/reports
- ./logs:/var/log/
links:
- smtp:smtp
- db:db
- rabbitmq:rabbitmq
- geoserver:geoserver
ports:
# for django test server
- "33303:8080"
# for ssh
- "33302:22"
worker:
build: docker
hostname: worker
command: celery worker -A config.celery -l info --beat
environment:
- DATABASE_NAME=gis
- DATABASE_USERNAME=docker
- DATABASE_PASSWORD=docker
- DATABASE_HOST=db
- DATABASE_QGIS_HOST=db_gis
- RABBITMQ_HOST=rabbitmq
- DJANGO_SETTINGS_MODULE=core.settings.prod_docker
- VIRTUAL_HOST=haitidata.com
- VIRTUAL_PORT=8080
- C_FORCE_ROOT=true
volumes:
- ../django_project:/home/web/django_project
- ./static:/home/web/static
- ./media:/home/web/media
- ./reports:/home/web/reports
- ./logs:/var/log/
links:
- smtp:smtp
- db:db
- rabbitmq:rabbitmq
restart: on-failure:5
geoserver:
image: kartoza/geoserver
container_name: haitidata-geoserver
ports:
- "33308:8080"
+4
View File
@@ -0,0 +1,4 @@
This directory is used to contain nginx configuration
when using a non dockergen nginx configuration.
See docker-compose.yml to see how it is used.
+69
View File
@@ -0,0 +1,69 @@
# Define connection details for connecting to django running in
# a docker container.
upstream uwsgi {
server uwsgi:8080;
}
upstream geoserver {
server geoserver:8080;
}
server {
# OTF gzip compression
gzip on;
gzip_min_length 860;
gzip_comp_level 5;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml application/x-javascript text/xml text/css application/json;
gzip_disable “MSIE [1-6].(?!.*SV1)”;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# the port your site will be served on
listen 8080;
# the domain name it will serve for
# server_name staging.foss4g-africa.org;
charset utf-8;
# max upload size, adjust to taste
client_max_body_size 15M;
# Django media
location /media {
# your Django project's media files - amend as required
alias /home/web/media;
expires 21d; # cache for 71 days
}
location /static {
# your Django project's static files - amend as required
alias /home/web/static;
expires 21d; # cache for 21 days
}
location /api/geoserver/ {
proxy_pass http://geoserver/geoserver/;
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass uwsgi;
# the uwsgi_params file you installed needs to be passed with each
# request.
# the uwsgi_params need to be passed with each uwsgi request
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;
}
}
+29
View File
@@ -0,0 +1,29 @@
upstream qgisug {
server 127.0.0.1:63300;
}
server {
# OTF gzip compression
gzip on;
gzip_min_length 860;
gzip_comp_level 5;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml application/x-javascript text/xml text/css application/json;
gzip_disable “MSIE [1-6].(?!.*SV1)”;
# the port your site will be served on
listen 80
# the domain name it will serve for
# server_name staging.foss4g-africa.org;
charset utf-8;
# max upload size, adjust to taste
client_max_body_size 15M;
location / {
proxy_pass http://qgisug;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
echo "Use this to tag a version on your local"
echo "machine, push the tag upstream and then"
echo "deploy it to the remote"
echo "e.g."
echo "$0 version-1.2.3"
VERSION=$1
make dbbackup
make mediasync
git tag $VERSION
git push --tags upstream
ssh kartoza4 "cd /home/web/kartoza.com/deployment && git fetch --tags && git checkout $VERSION && make build && make kill && make web && make migrate && make collectstatic && make reload"
+30
View File
@@ -0,0 +1,30 @@
# Haitidata
You should write some docs, it's good for the soul.
# Docker installation
## Install docker
This will install an Haitidata container
Makes sure to have docker-compose installed
```
sudo apt-get install python-pip
sudo pip install docker-compose
```
## Get project code
Clone the repo:
```
git clone https://github.com/HaitiData/haitidata.git
```
## Run project
Run the docker container:
```
cd deployment
make deploy
make update-migrations-localization:
```
then you can visit http://0.0.0.0:33300```
File renamed without changes.
+58
View File
@@ -0,0 +1,58 @@
"""
Django settings for charts project.
Generated by 'django-admin startproject' using Django 1.8.7.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from geonode.settings import *
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SITENAME = 'charts-prj'
LOCAL_ROOT = os.path.abspath(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '*u(5zzp_wjj!^!w4$h@e#jv!*y02z17lb8gu-l)j+*79p^r8%('
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# Application definition
INSTALLED_APPS = INSTALLED_APPS + (
'charts_app',
'wfs_harvest'
)
WSGI_APPLICATION = 'charts-prj.wsgi.application'
# Additional directories which hold static files
STATICFILES_DIRS.append(
os.path.join(LOCAL_ROOT, "static"),
)
# Location of url mappings
ROOT_URLCONF = 'charts-prj.urls'
# Location of locale files
LOCALE_PATHS = (
os.path.join(LOCAL_ROOT, 'locale'),
) + LOCALE_PATHS
TEMPLATES[0]['DIRS'].insert(0, os.path.join(LOCAL_ROOT, "templates"))
MAX_CSV_RECORDS = 20000
ALLOWED_HOSTS = ['*']
PROXY_ALLOWED_HOSTS = ['*']
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,24 @@
{% load i18n %}
<ul class="nav nav-tabs">
<li class="active"><a href="#info" data-toggle="tab"><i class="fa fa-info-circle"></i>{% trans "Info" %}</a></li>
{% if resource.polymorphic_ctype.name == 'layer' %}
<li><a href="#attributes" data-toggle="tab"><i class="fa fa-bars"></i>{% trans "Attributes" %}</a></li>
{% endif %}
{% if resource.is_mosaic %}
<li><a href="#granules" data-toggle="tab"><i class="fa fa-bars"></i>{% trans "Granules" %}</a></li>
{% endif %}
{% if resource.service_type == 'WFS' %}
<li><a href="#charts" data-toggle="tab"><i class="fa fa-charts"></i>{% trans "Charts" %}</a></li>
{% endif %}
{% if SOCIAL_BUTTONS %}
<li><a href="#share" data-toggle="tab"><i class="fa fa-share"></i>{% trans "Share" %}</a></li>
{% endif %}
<li><a href="#rate" data-toggle="tab"><i class="fa fa-star"></i>{% trans "Ratings" %}</a></li>
<li><a href="#comments" data-toggle="tab"><i class="fa fa-comment-o"></i> {% trans "Comments" %}</a></li>
{% if GEOGIG_ENABLED and resource.link_set.geogig %}
<li><a href="#geogig" data-toggle="tab"><i class="fa fa-code-fork"></i> {% trans "GeoGig" %}</a></li>
{% endif %}
{% if EXIF_ENABLED and resource.polymorphic_ctype.name == 'document' and exif_data %}
<li><a href="#exif" data-toggle="tab"><i class="fa fa-photo"></i> {% trans "Exif" %}</a></li>
{% endif %}
</ul>
@@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block extra_head %}
<link href="{{ STATIC_URL }}css/site_base.css" rel="stylesheet"/>
{% endblock %}
{% block extra_tab %}
{% comment %}
Add Tab for Third Party Apps
<li>
<a href="{{ PROJECT_ROOT }}app">App</a>
</li>
{% endcomment %}
{% endblock %}
@@ -0,0 +1,15 @@
{% extends 'index.html' %}
{% load i18n %}
{% comment %}
This is where you can override the hero area block. You can simply modify the content below or replace it wholesale to meet your own needs.
{% endcomment %}
{% block hero %}
<div class="jumbotron">
<div class="container">
<h1>{% trans "Welcome to the charts GeoNode" %}</h1>
<p>{% blocktrans %}GeoNode is an open source platform for sharing geospatial data and maps.{% endblocktrans %}</p>
<p>{% blocktrans %}If you have any questions about the software or service, join our <a href="https://groups.google.com/d/forum/geonode-users">mailing list</a>.{% endblocktrans %}</p>
<span>{% trans 'Need help?' %} <a href="http://docs.geonode.org/en/latest/tutorials/users/quickstart/index.html">{% trans 'Getting Started' %}</a></span>
</div>
</div>
{% endblock %}
@@ -0,0 +1,109 @@
"""
Django settings for pippo project.
Generated by 'django-admin startproject' using Django 1.8.7.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '5i81&t!#h$4ie!-kg$&@5b-1j*)d9@(6)8g8o4kg*xw3i2e=@t'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)
ROOT_URLCONF = 'charts-prj.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'charts-prj.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
ANONYMOUS_USER_ID = 1
LOCAL_MEDIA_URL = ''
API_INCLUDE_REGIONS_COUNT = ''
HAYSTACK_SEARCH = ''
RESOURCE_PUBLISHING = ''
+31
View File
@@ -0,0 +1,31 @@
"""
WSGI config for charts project.
This module contains the WSGI application used by Django's development server
and any production WSGI deployments. It should expose a module-level variable
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
this application via the ``WSGI_APPLICATION`` setting.
Usually you will have the standard Django WSGI application here, but it also
might make sense to replace the whole Django WSGI application with a custom one
that later delegates to the Django one. For example, you could introduce WSGI
middleware here, or combine a Django application with an application of another
framework.
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "charts-prj.settings")
# This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
# Apply WSGI middleware here.
# from helloworld.wsgi import HelloWorldApplication
# application = HelloWorldApplication(application)
+10
View File
@@ -0,0 +1,10 @@
from django.contrib import admin
from .models import Chart
class ChartAdmin(admin.ModelAdmin):
list_display = ['id', 'title']
admin.site.register(Chart, ChartAdmin)
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('layers', '24_to_26'),
]
operations = [
migrations.CreateModel(
name='Chart',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=128, blank=True)),
('category', models.CharField(max_length=200)),
('quantity', models.CharField(max_length=200)),
('type', models.SmallIntegerField(default=0, choices=[(0, b'Bar chart'), (1, b'Pie chart'), (2, b'Donut chart')])),
('aggr_type', models.SmallIntegerField(default=3, choices=[(0, b'Sum'), (1, b'Mean'), (2, b'Category count'), (3, b'Max'), (4, b'Min')])),
('abstract', models.TextField(blank=True)),
('layer', models.ForeignKey(to='layers.Layer')),
],
),
]
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import charts_app.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('charts_app', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='chart',
name='created_by',
field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AlterField(
model_name='chart',
name='layer',
field=models.ForeignKey(to='layers.Layer', validators=[charts_app.models.validate_wfs]),
),
migrations.AlterField(
model_name='chart',
name='type',
field=models.SmallIntegerField(default=0, choices=[(0, b'Bar chart'), (1, b'Pie chart'), (2, b'Donut chart'), (3, b'Line chart')]),
),
]
+80
View File
@@ -0,0 +1,80 @@
from django.db import models
from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from django.forms import ModelForm, ValidationError as VE
from geonode.layers.models import Layer
from wfs_harvest.utils import get_featno, get_fields
def validate_wfs(value):
lyr = Layer.objects.get(pk=value)
if lyr.service_type != 'WFS':
raise ValidationError(_('%(lyr_title)s is not a WFS layer'),
code='not_a_wfs',
params={'lyr_title': lyr.title})
feat_no = get_featno(value)
if feat_no > settings.MAX_CSV_RECORDS:
raise ValidationError(_('%(lyr_title)s has too many features; '
'chart functionality is not available '
'for very large datasets'),
code='too_many_records',
params={'lyr_title': lyr.title})
class Chart(models.Model):
CHART_TYPES = (
(0, 'Bar chart'),
(1, 'Pie chart'),
(2, 'Donut chart'),
(3, 'Line chart')
)
AGGREGATION_TYPES = (
(0, 'Sum'),
(1, 'Mean'),
(2, 'Category count'),
(3, 'Max'),
(4, 'Min'),
)
layer = models.ForeignKey(Layer, validators=[validate_wfs])
title = models.CharField(max_length=128, blank=True)
category = models.CharField(max_length=200)
quantity = models.CharField(max_length=200)
type = models.SmallIntegerField(choices=CHART_TYPES, default=0)
aggr_type = models.SmallIntegerField(choices=AGGREGATION_TYPES, default=3)
abstract = models.TextField(blank=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null = True)
def get_absolute_url(self):
return reverse('chart_detail', kwargs={'pk': self.pk})
class ChartForm(ModelForm):
def clean(self):
cleaned_data = super(ChartForm, self).clean()
layer = cleaned_data.get('layer')
category = cleaned_data.get('category')
quantity = cleaned_data.get('quantity')
categories, quantities = get_fields(layer)
if category not in categories:
lyr = Layer.objects.get(pk=layer)
raise VE(_('%(lyr_title)s does not contain the field %(category)s'),
code='non_extant_category_field',
params={'lyr_title': lyr.title, 'category': category})
if quantity not in quantities:
lyr = Layer.objects.get(pk=layer)
raise VE(_('%(lyr_title)s does not contain the field %(quantity)s'),
code='non_extant_quantity_field',
params={'lyr_title': lyr.title, 'quantity': quantity})
class Meta:
model = Chart
fields = '__all__'
@@ -0,0 +1,68 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Donut Chart v1</title>
<h1>Simple Donut Chart v1</h1>
<h2>Zero values excluded</h2>
<p>D3js version 4, use canvas</p>
<canvas width="960" height="500"></canvas>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d");
var width = canvas.width,
height = canvas.height,
radius = Math.min(width, height) / 2;
var colors = ["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00", "#800000", "#8E388E",
"#7171C6", "#7D9EC0", "#388E8E", "#71C671", "#8E8E38", "#C5C1AA", "#C67171"];
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 70)
.context(context);
var labelArc = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40)
.context(context);
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.area; });
context.translate(width / 2, height / 2);
d3.csv("{% url "get_csv" %}", function(d) {
d.area = +d.area;
if (d.area !== 0) {
return d;}
}, function(error, data) {
if (error) throw error;
var arcs = pie(data);
arcs.forEach(function(d, i) {
context.beginPath();
arc(d);
context.fillStyle = colors[i];
context.fill();
});
context.beginPath();
arcs.forEach(arc);
context.strokeStyle = "#fff";
context.stroke();
context.textAlign = "center";
context.textBaseline = "middle";
context.fillStyle = "#000";
arcs.forEach(function(d) {
var c = labelArc.centroid(d);
context.fillText(d.data.name, c[0], c[1]);
});
});
</script>
<body></body>
@@ -0,0 +1,169 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Donut Chart v2</title>
<h1>Simple Donut Chart v2</h1>
<h2>Zero values excluded, label with ticks</h2>
<p>D3js version 3, use svg</p>
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
svg {
width: 100%;
height: 100%;
}
path.slice{
stroke-width:2px;
}
polyline{
opacity: .3;
stroke: black;
stroke-width: 2px;
fill: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var svg = d3.select("body")
.append("svg")
.append("g")
svg.append("g")
.attr("class", "slices");
svg.append("g")
.attr("class", "labels");
svg.append("g")
.attr("class", "lines");
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.area;
});
var arc = d3.svg.arc()
.outerRadius(radius * 0.8)
.innerRadius(radius * 0.4);
var outerArc = d3.svg.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9);
d3.csv("{% url "get_csv" %}", function(d) {
d.area = +d.area;
if (d.area !== 0) {
return d;}
}, function(error, data) {
if (error) throw error;
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var key = function(d){ return d.data.name};
var color = d3.scale.ordinal()
.domain([key])
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var slice = svg.select(".slices").selectAll("path.slice")
.data(pie(data), key);
slice.enter()
.insert("path")
.style("fill", function(d) { return color(d.data.area); })
.attr("class", "slice");
slice
.transition().duration(1000)
.attrTween("d", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
})
/* ------- TEXT LABELS -------*/
var text = svg.select(".labels").selectAll("text")
.data(pie(data), key);
text.enter()
.append("text")
.attr("dy", ".35em")
.text(function(d) {
return d.data.name + ' - ' +d.data.area; ;
});
function midAngle(d){
return d.startAngle + (d.endAngle - d.startAngle)/2;
}
text.transition().duration(1000)
.attrTween("transform", function(d) {
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
var pos = outerArc.centroid(d2);
pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
return "translate("+ pos +")";
};
})
.styleTween("text-anchor", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
return midAngle(d2) < Math.PI ? "start":"end";
};
});
/* ------- SLICE TO TEXT POLYLINES -------*/
var polyline = svg.select(".lines").selectAll("polyline")
.data(pie(data), key);
polyline.enter()
.append("polyline");
polyline.transition().duration(1000)
.attrTween("points", function(d){
this._current = this._current || d;
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
var d2 = interpolate(t);
var pos = outerArc.centroid(d2);
pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
return [arc.centroid(d2), outerArc.centroid(d2), pos];
};
});
});
</script>
</body>
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Pie Chart v1</title>
<h1>Simple Pie Chart v1</h1>
<h2>All data</h2>
<p>D3js version 4, use svg</p>
<style>
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.area; });
var path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
d3.csv("{% url "get_csv" %}", function(d) {
d.area = +d.area;
return d;
}, function(error, data) {
if (error) throw error;
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arc.append("path")
.attr("d", path)
.attr("fill", function(d) { return color(d.data.name); });
arc.append("text")
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; })
.attr("dy", "0.35em")
.text(function(d) { return d.data.name; });
});
</script>
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Pie Chart v2</title>
<h1>Simple Pie Chart v2</h1>
<h2>Zero values excluded</h2>
<p>D3js version 4, use svg</p>
<style>
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.{{ quantity }}; });
var path = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
d3.csv("/table?lyrname={{ lyrname }}&category={{ category }}&quantity={{ quantity }}", function(d) {
d.area = +d.area;
if (d.area !== 0) {
return d;}
}, function(error, data) {
if (error) throw error;
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
arc.append("path")
.attr("d", path)
.attr("fill", function(d) { return color(d.data.{{ category }}); });
arc.append("text")
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; })
.attr("dy", "0.35em")
.text(function(d) { return d.data.{{ category }}; });
});
</script>
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+11
View File
@@ -0,0 +1,11 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<pk>[0-9]+)/$', views.ChartDetail.as_view(), name='chart_detail'),
url(r'^add/(?P<layer_id>[0-9]+)/$', views.ChartCreate.as_view(), name='chart_add'),
url(r'^update/(?P<pk>[0-9]+)/$', views.ChartUpdate.as_view(), name='chart_update'),
url(r'^delete/(?P<pk>[0-9]+)/$', views.ChartDelete.as_view(), name='chart_delete'),
url(r'^$', views.ChartList.as_view(), name='chart_list')
]
+106
View File
@@ -0,0 +1,106 @@
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.list import ListView
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from geonode.layers.models import Layer
from .models import Chart, ChartForm
from wfs_harvest.utils import get_fields
class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **initkwargs):
view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
return login_required(view)
class ChartDetail(DetailView):
model = Chart
def get_object(self, queryset=None):
obj = super(ChartDetail, self).get_object(queryset=queryset)
lyr_obj = Layer.objects.get(pk=obj.layer)
if not self.request.user.has_perm('download_resourcebase', lyr_obj.get_self_resource()):
raise PermissionDenied
return obj
def get_context_data(self, **kwargs):
context = super(ChartDetail, self).get_context_data(**kwargs)
return context
class ChartCreate(LoginRequiredMixin, CreateView):
form_class = ChartForm
template_name_suffix = 'charts_app/chart_update_form.html'
template_name = 'charts_app/chart_update_form.html'
def get_initial(self):
layer_id = self.kwargs['layer_id']
initial = self.initial.copy()
initial['layer'] = layer_id
return initial
def get_context_data(self, **kwargs):
layer_id = self.kwargs['layer_id']
layer = Layer.objects.get(pk=layer_id)
if not self.request.user.has_perm('download_resourcebase', layer.get_self_resource()):
raise PermissionDenied
fieldnames, num_fieldnames = get_fields(layer_id)
ctx = super(ChartCreate, self).get_context_data(**kwargs)
ctx['fieldnames'] = fieldnames
ctx['num_fieldnames'] = num_fieldnames
ctx['layer'] = layer
return ctx
def form_valid(self, form):
if not self.request.user.has_perm('download_resourcebase', form.instance.layer.get_self_resource()):
raise PermissionDenied
form.instance.created_by = self.request.user
return super(ChartCreate, self).form_valid(form)
class ChartUpdate(LoginRequiredMixin, UpdateView):
model = Chart
fields = '__all__'
template_name = 'charts_app/chart_update_form.html'
def get_object(self, queryset=None):
obj = super(ChartUpdate, self).get_object(queryset=queryset)
is_chart_owner = (self.request.user == obj.created_by)
lyr_obj = Layer.objects.get(pk=obj.layer)
is_lyr_owner = (self.request.user == lyr_obj.owner)
if not (self.request.user.is_superuser or is_chart_owner or is_lyr_owner):
raise PermissionDenied
return obj
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(ChartUpdate, self).form_valid(form)
class ChartDelete(LoginRequiredMixin, DeleteView):
model = Chart
success_url = '/layers/'
def get_object(self, queryset=None):
obj = super(ChartDelete, self).get_object(queryset=queryset)
is_chart_owner = (self.request.user == obj.created_by)
lyr_obj = Layer.objects.get(pk=obj.layer)
is_lyr_owner = (self.request.user == lyr_obj.owner)
if not (self.request.user.is_superuser or is_chart_owner or is_lyr_owner):
raise PermissionDenied
return obj
class ChartList(ListView):
model = Chart
fields = '__all__'
template_name = 'charts_app/chart_list.html'
def get_context_data(self, **kwargs):
context = super(ChartList, self).get_context_data(**kwargs)
return context
+8
View File
@@ -0,0 +1,8 @@
This directory is used to store static assets for your project. User media files
(FileFields/ImageFields) are not stored here.
The convention for this directory is:
* css/ — stores CSS files
* js/ — stores Javascript files
* img/ — stores image files
File renamed without changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Loaded 100 of 596 files, more files were not shown because too many files have changed in this diff. Show more