Nosht is an event ticketing platform originally built for The Hands Up Foundation which is available under an open source license (MIT) for use by anyone.
If you have any questions please create an issue on github.
The platform is built using the following tools:
- the server side is built using aiohttp web framework and python 3
- the main database is postgres with redis as a cache and queuing system
- the front end uses react and "create react app"
- the system is deployed at present using heroku's container runtime although nothing in the system should rely on heroku
- AWS SES is used to send emails
- AWS S3 is used to store user uploaded images
- Cloudflare is used as a reverse-proxy and CDN for all traffic including S3
- sentry/raven collects error reports
- Stripe does card payments
Install the following:
- python3.6
- heroku cli
- docker
Create an app on heroku (make sure to choose the most appropriate region), add the following add-ons
- Heroku Postgres - choose a size appropriate for your needs
- Redis Cloud - the free 30MB option should be sufficient
- Papertail - the smallest (free) option should be sufficient
Export an environment variable identifying your heroku app:
export HEROKU_APP=<name of your app>
Make sure your heroku CLI can connect to heroku:
heroku ps -a $HEROKU_APP
(you won't see much but the command should pass)
You'll need to set the following config (environment) variables in heroku:
APP_AUTH_KEY
can be set by simply runningmake heroku-set-auth-key
, random key, keep is secretAPP_AWS_ACCESS_KEY
key from AWS, see "AWS Setup" belowAPP_AWS_SECRET_KEY
key from AWS, see "AWS Setup" belowAPP_S3_BUCKET
name of the S3 bucket your using eg.events-images.example.org
, see "AWS Setup" belowAPP_S3_DOMAIN
root url for the S3 bucket eg.https://events-images.example.org
, see "AWS Setup" belowAPP_AWS_SES_WEBHOOK_AUTH
basic auth password for SES webhooksAPP_S3_PREFIX
prefix to use for all files in S3, eg.prod
APP_FACEBOOK_SIW_APP_SECRET
key from facebook, see "Facebook Setup" belowAPP_GOOGLE_MAPS_STATIC_KEY
key for google maps, see "Google Setup" belowAPP_GOOGLE_SIW_CLIENT_KEY
google signin with key, see "Google Setup" belowAPP_GRECAPTCHA_SECRET
google recaptcha key, see "Google Setup" belowRAVEN_DSN
DSN from sentry/raven, see "Sentry Setup" belowAPP_DONORFY_API_KEY
API key for donorfy integrationAPP_DONORFY_ACCESS_KEY
API "access key" for donorfy integrationAPP_CSP_IMAGE_SOURCE
to something likehttps://events-images.example.org
to allow images to show
With Heroku's container runtime you build docker images for you app locally, push them to heroku, then deploy those images.
First of all, clone the nosht code
git clone git@github.com:samuelcolvin/nosht.git
cd nosht
Before you can build the image you'll need to create a few static files which are built into the images:
these files are kept in a directory named deploy-settings-<heroku-app-name>
, eg. if your app on heroku is called
example-events
, the directory should be called deploy-settings-example-events
It should look like
deploy-settings-example-events/
├── .env.production
└── favicons
├── android-chrome-192x192.png
├── android-chrome-256x256.png
├── apple-touch-icon.png
├── browserconfig.xml
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── logo.png
├── mstile-150x150.png
├── safari-pinned-tab.svg
└── site.webmanifest
You can generate most of the files for favicons/
using this helpful service.
The only exception is logo.png
which should be a 380x150px logo for your service.
.env.production
provides production settings for the "create react apps" build, it should contain the following
REACT_APP_SITE_NAME='<the name of your service/company>'
REACT_APP_THEME_COLOUR='company hex colour, should match favicons/browserconfig.xml, eg. "016997"'
REACT_APP_COPYRIGHT_STATEMENT='© copyright statement for the footer'
REACT_APP_GOOGLE_MAPS_KEY='<public google maps key, see below>'
REACT_APP_GOOGLE_SIW_CLIENT_KEY='<google signin with client key, see below>'
REACT_APP_FACEBOOK_SIW_APP_ID='<facebook signin with app id, see below>'
REACT_APP_RECAPTCHA_KEY='<google recaptcah public key>'
REACT_APP_SENTRY_DSN='<sentry dsn for js error tracking>'
REACT_APP_GA_TRACKING_ID='<tracking id for google analytics>'
Log in to heroku's container registry
heroku container:login
With deploy-settings-<heroku-app-name>
setup, you can build and deploy your images:
make heroku-push
will build the docker images and push them to heroku,
make heroku-release
will release those images, the following should now show you both the worker and web dyno's running
heroku ps -a $HEROKU_APP
However you'll likely get a 500 error if you try to go to your site.
To create database tables run
heroku run "./run.py reset_database" --type=worker -a $HEROKU_APP
and to create a company:
heroku run "./run.py patch create_new_company --live" --type=worker -a $HEROKU_APP
You can see other commands available by running just ./run.py
or ./run.py patch
.
Create an S3 bucket, you'll need to name it the same as the domain you want to access it from. Eg. name
the bucket event-images.example.org
to a access files at https://event-images.example.org/...
.
Create an IAM role with the following policy
(remember to change the bucket name from bucketname.example.org
to your bucket name).
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::bucketname.example.org"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:GetObjectAcl",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::bucketname.example.org/*"
]
},
{
"Effect": "Allow",
"Action": [
"ses:*"
],
"Resource": "*"
}
]
}
Go to SES and setup a sending domain. You either need to set it up in the eu-west-1
region
or change the region aws_region
setting.
Notifications of email events (delivery, opening, clicks etc.) are recorded in nosht via webhooks from SES.
To setup these webhooks:
- log into AWS > SES > Configuration Sets
- Create a Configuration Set called exactly
nosht
. - Add a destination of type "SNS", call it something like
nosht-cloudwatch
and check all Event types, choose "Create an SNS topic" and call itnosht-emails
or similar. - Move in the AWS console to SNS, go to topics and you should see the topic you just created.
- Hit "create subscription", choose the type as "https" and enter the url as
https://{APP_AWS_SES_WEBHOOK_AUTH}@events.example.org/api/ses-webhook/
, whereAPP_AWS_SES_WEBHOOK_AUTH
is is the basic auth username and password which will also be set in Heroku, it needs a colon in, eg.user:randompassword
. - If the platform is up and running when you create the subscription (and you've done it right) it should get approved immediately, if not you'll need to create another one or retry once the platform is running
- Currently emails and email events aren't displayed anywhere in the system, but they're saved to the database for manual checking or future display.
To set from AWS:
- heroku config
APP_AWS_ACCESS_KEY
- heroku config
APP_AWS_SECRET_KEY
- heroku config
APP_S3_BUCKET
- heroku config
APP_S3_DOMAIN
- heroku config
APP_AWS_SES_WEBHOOK_AUTH
Add a CNAME record for the main system (probably events.
)
CNAME events events.example.org.herokudns.com
(or whatever domain heroku gives you)
Add a CNAME record for the S3 subdomain, eg.
CNAME event-images events-images.example.org.s3.amazonaws.com
Search for "facebook developer dashboard", wade through their horrible interface until you've created an app to "Let people log in with their Facebook account", you can then go to settings > basic to get the "App ID" and "App Secret".
To set from Facebook:
- heroku config
APP_FACEBOOK_SIW_APP_SECRET
.env.production
>REACT_APP_FACEBOOK_SIW_APP_ID
Lots of keys need for different bits of google's integration:
Go to https://console.developers.google.com, make sure your on the right project, or create a new one (you'll need billing to be setup for all the keys to work correctly), go to credentials:
- set up an "API Key" with permission for "Maps JavaScript API" and "Geocoding API",
restrict it to your domain using "HTTP referres", use this for
REACT_APP_GOOGLE_MAPS_KEY
. - set up an "API Key" with permission for "Maps Static API", use this for
APP_GOOGLE_MAPS_STATIC_KEY
. - set up an "OAuth client ID", set the authorised origin, set
REACT_APP_GOOGLE_SIW_CLIENT_KEY
to the Client ID andAPP_GOOGLE_SIW_CLIENT_KEY
to the "Client secret".
Search "google recaptcha" and setup a V2 key for your site, set the allowed domains,
set REACT_APP_RECAPTCHA_KEY
to the "Site key", set APP_GRECAPTCHA_SECRET
to the "Secret key".
Go to google analytics, set up a new property, take the tracking ID and copy it into REACT_APP_GA_TRACKING_ID
.
To set from Google:
- heroku config
APP_GOOGLE_MAPS_STATIC_KEY
- heroku config
APP_GOOGLE_SIW_CLIENT_KEY
- heroku config
APP_GRECAPTCHA_SECRET
.env.production
>REACT_APP_GOOGLE_MAPS_KEY
.env.production
>REACT_APP_GOOGLE_SIW_CLIENT_KEY
.env.production
>REACT_APP_RECAPTCHA_KEY
.env.production
>REACT_APP_GA_TRACKING_ID
Go to https://sentry.io, create a new account, organisation or project and copy the DSN.
To set from Sentry:
- heroku config
RAVEN_DSN
.env.production
>REACT_APP_SENTRY_DSN
Setup the the stripe account, create a webhook with the following settings:
- event types, just
payment_intent.succeeded
- url
https://events.example.org/api/stripe/webhook/
Enter the stripe public key, stripe secret key and stripe webhook secret into the company edit form.
You'll need to run something like the following and use your initiative if things fail, add an issue to github if you get confused
pwd # should be /.../nosht
virtualenv -p `which python3.6` env
source env/bin/active
make install
cd js/
yarn
cd ..
To run tests locally, you should be able to simply run
make
(Requires the same dependencies as above as well as postgresql and redis, and of course for the code to be cloned.)
To run the front end in development mode
cd js/
yarn start
The js dev server will proxy requests through to the backend so you'll also need to run the server at the same time in a different window.
Before running this you'll probaly need to set up some of the environment variables mentioned above for the system to run properly.
cd nosht/
source env/bin/activate
cd py/
./run.py web
(or change the last command to adev runserver web/main.py
to reload the system on file changes.)
If you want the worker running as well you'll also run (from another terminal)
cd nosht/
source env/bin/activate
cd py/
./run.py worker
Instead of running each process/component independently you can also develop using docker to run your application, this will result in a much slower feedback but may be easier in some circumstances:
Simply run
make docker-dev
And then make docker-dev-stop
once you've finished to stop the server.