Copyright 2017 NPR. All rights reserved. No part of these materials may be reproduced, modified, stored in a retrieval system, or retransmitted, in any form or by any means, electronic, mechanical or otherwise, without prior written permission from NPR.
(Want to use this code? Send an email to [email protected]!)
- What is this?
- Assumptions
- What's in here?
- Bootstrap the project
- Hide project secrets
- Run the project
- Deploy to EC2
- Install cron jobs
- Install web services
- Run a remote fab command
Cardbuilder is a Django-based application for authoring cards and creating embeddable stacks related to the Russia investigation for use on npr.org.
The following things are assumed to be true in this documentation.
- You are running OSX.
- You are using Python 3.
- You have virtualenv and virtualenvwrapper installed and working.
- You have PostgreSQL installed and working.
- You have NPR's AWS credentials stored as environment variables locally.
For more details on the technology stack used with the app-template, see our development environment blog post.
The project contains the following folders and important files:
assets
: Front-end assets for the Django views. These are compiled through Webpack.config
: Django project configurationconfs
: Server configuration files (nginx, uwsgi, etc)core
: Django applicationdata
: Stub folder for output of JSON for cards locallyfabfile
: Fabric commands for server managementwebpack
: Webpack configuration.babelrc
: Configuration for Babel transpilation, used by Webpackapp_config.py
: General application configurationcrontab
: Default crontab, not in use for this appmanage.py
: Default Django management filepackage.json
: Node requirementsREADME.md
: General documentationrequirements.txt
: Python requirementsrun_on_server.sh
: Bash file used to run Fabric commands on the server, invoked byfab servers.fabcast
.
cd cardbuilder
mkvirtualenv -p `which python3` cardbuilder
pip install -r requirements.txt
npm install
fab django.setup_django
You will need the project's secret key. If you're at NPR, hopefully the person who setup this project put it in our shared env!
Project secrets should never be stored in app_config.py
or anywhere else in the repository. They will be leaked to the client if you do. Instead, always store passwords, keys, etc. in environment variables and document that they are needed here in the README.
Any environment variable that starts with $PROJECT_SLUG_
will be automatically loaded when app_config.get_secrets()
is called.
A flask app is used to run the project locally. It will automatically recompile templates and assets on demand.
workon $PROJECT_SLUG
fab app
Visit localhost:8000 in your browser.
To deploy this project to EC2, first, make sure the IP addresses or hostnames are configured in app_config.py
under the variables PRODUCTION_SERVERS
and STAGING_SERVERS
. Also ensure that, on the servers you are deploying to, you have installed Python 3, upstart, nginx, uWSGI, and PostgreSQL.
Then, run fab staging master servers.setup
to deploy to staging. This will setup the clone the repo, setup the virtual environment, and do other miscellaneous housekeeping.
Once the server is correctly setup, you can run fab staging master deploy_server
to checkout the latest from the repo and restart uWSGI.
Because there are Django views dependent on Webpack builds, if you need to deploy a change to the JavaScript or CSS of a view, run fab staging master deploy_server:True
. This will both deploy the latest changes to the server and run webpack on the server, sending the latest JS and CSS to S3.
Web services are configured in the confs/
folder.
To check that these files are being properly rendered, you can render them locally and see the results in the confs/rendered/
directory.
fab servers.render_confs
Deploy the configuration files by running:
fab servers.deploy_confs
Sometimes it makes sense to run a fabric command on the server, for instance, when you need to render using a production database. You can do this with the fabcast
fabric command. For example:
fab staging master servers.fabcast:deploy
If any of the commands you run themselves require executing on the server, the server will SSH into itself to run them.
The core app only has two models:
- Category: A grouping for cards, i.e. People, Documents, etc.
- Card: A card, contains all the information necessary to build a card on the front end.
I based the whole Django-Webpack integration on this. It works pretty well, but it's pretty weird. Basically, webpack produces a webpack-stats.json
file in the root, and the Django config reads that file to figure out where to find the file. Locally, that's a separate webpack dev server; on the server, that's a file on S3.
The main view in this app is the Card Stack Composer. It presents all published cards in the database and allows users to select and orders the cards they would like to embed in the stack. This is built as a React app, and can be developed in assets/js/app.js
.
Whenever a card is saved and republished, a screenshot is created through a Lambda service. The request to this service is handled in core/signals.py
. You can view current screenshots at /cardbuilder/screenshots/
.