Affinity.works is supporting the surge of resistance against Trump. It's coming at it in two ways. First, working with the new activist groups that have sprung up, building MVP's to solve the problems they've encountered in their organizing. Second, Affinity is enabling rapid collaboration between the grassroots and the big national networks like Indivisible & Daily Kos, to defend the institutions of democracy.
Concretely, the tool is a SaaS and has components for managing a network of groups, a crm, task management for volunteers, outreach, and a reputation marketplace between campaigns, activists, and groups.
Clone the project:
$ git clone https://github.com/affinityworks/main $ cd main
Or (via ssh):
$ git clone firstname.lastname@example.org:affinityworks/main.git $ cd main
The project requires the following system-level dependencies:
postgresqlv 9.6: our database!
redisv 4.0.6: a cache to store frequently-retrieved things in memory instead of on disk
rubyv 2.3.3: the programming language in which the bulk of the app is written
nodejsv 6.9.0: enables us to transpile "es6"-flavored js into js that will run in all browsers
bundlerv 1.x: the package manager for ruby
yarnv 1.x: yet another javacript package manager
Below are some scripts for installing and running those dependencies using either Docker or plain old bash scripts. Feel free to take a look at
dockercompose-yml file, or the
install scripts in the
bin directory to get a sense of what's going on under the hood!
All commands assume you are located in
Run in background:
$ ./bin/docker-up -d
$ ./bin/docker-cmd "bundle exec rails test"
Run arbitrary bash commands:
$ ./bin/docker-cmd "bundle exec rake routes"
Rebuild docker container:
$ ./bin/docker-build "latest" $ docker push affinityworks/web:latest
Note: our bash scripts only work for Mac OSX and Debian-flavored GNU/Linux. They also enforce use of both NVM and RVM. If those constraints don't work for you, please feel free to either:
- Use the Dockerized dev env described above.
- Adapt the comands in our bash scripts to your liking.
- Open an issue or pull request to help us improve the scripts! :)
$ ./bin/run-services # first run only: start redis & postgres $ ./bin/copy_configs # first run only: see `Secrets` section below $ ./bin/seed-db # first run only: seed db $ ./bin/run
Shut down cleanly:
$ kill -9 `cat tmp/pids/server/pid`
$ bundle exec rails test
Switching btw/ docker and bash
If you are switching between docker and bash setups, you might run into odd Devise authentication errors on login. If this happens:
Delete all caches:
$ cd path/to/this/repo $ rm -rf tmp/caches/
If that doesn't fix it, try removing the local dbs and re-seeding:
$ psql # drop database affinity_development; # drop database affinity_test; # \q $ ./bin/seed-db
Secrets For Community Contributors
We provide sample versions of encrypted config files. They are in the
config folder with names like
some_config.yml.exampl. For the app to run, you need to copy them all to files with names like
some_config.yml, which you can do by running the following script:
If you would like to gain access to the encrypted credentials:
- shoot us an email at email@example.com
- drop us a note on Slack: https://advocacycommons.slack.com
- open an issue on this repo
Secrets For Team Members
We use blackbox for secrets management.
It allows us to keep credentials under secure version control by:
- maintaining a list of sensitive files
- gitingoring the files
- encrypting the files to a whitelist of PGP keys
- allowing key-owners to decrypt and re-encrypt files with easy-to-remember commands
To use it, you will first need:
- a PGP key (If you don't have one, we recommend GPGSuite for Mac users, and this guide from Riseup for Linux or Windows users)
- an admin to add your PGP public key to the whitelist at
Now you can use the following commands:
Decrypt all files:
Encrypt a newly created file:
$ ./bin/blackbox_register_new_file some_file_name.yml
Edit an encrypted file:
$ ./bin/blackbox_edit_start some_file.yml.gpg <do your editing> $ ./bin/blackbox_edit_end some_file.yml
Edit an already-decrypted file:
<do your editing> $ ./bin/blackbox_edit_end some_file.yml
Delete all cleartext files:
Add new public key to whitelist:
$ ./bin/blackbox_addadmin $ ./bin/blackbox_shred_all_files $ ./bin/blackbox_update_all_files # re-encrypts to new whitelist
Blackbox is all just shell commands! You can read them in
./bin. If you'd like to install them on your machine so you can type
blackbox_some_command instead of `./bin/blackbox_some_command**, you can:
Install blackbox on your $PATH:
$ git clone firstname.lastname@example.org:StackExchange/blackbox.git $ cd blackbox $ make copy-install $ cd ../ && rm -rf blackbox
Importing Partner Credentials
To import Gsuite credentials for a partner group, first:
- make sure the group is part of a network listed in
- place a copy of the network's
- rename the file to
some_networkis the snakecased version of the network's name given in
$ rake import_keys:gsuite
- place an encrypted version of the credentials in a nested folder of
- delete and gitignore all unencrypted versions
- automatically create a new commit to place the above changes under version control
You will likely want to amend that commit to change the commit message.
To update the list of networks:
- decrypt it with
./bin/blackbox_edit_start config/networks.ymlif necessary
- add networks, groups, and organizers following the format in the file
- re-encrypt the config file with
- create a migration with
rake config:update_networksas the body of the
rake db:migrate RAILS_ENV=test
- commit your changes and push them
client/webpack.config.js. So it is not necessary to rebuild manually. That said, if you want to spit out a static build of the frontend that matches the production build, you can run:
$ bundle exec rake react_on_rails:assets:webpack
Configuration Note: Mailgun + Heroku
Configuring the Heroku Mailgun addon is not that fun. Hopefully you never have to do it!
Just in case you do, here is a near-exhaustive list of the steps involved in doing so:
- Provision the Mailgun add-on (in the "Resources" tab of the
- Click on it (to go to the mailgun dashboard)
- Verify the mailgun account via email or help ticket (help ticket will be necesary if they send email to weird address)
- Creating new domain
- Verify the domain by:
a. clicking "Domains" -> "Domain Verification & DNS"
b. observing the two
TXTrecords that appear c. logging into gandi.net and finding the DNS records d. creating two
TXTrecords with the values observed in step b above
The current pipeline has 3 stages: Review -> Staging -> Production
Build: Built automatically by any new Pull Requests.
Env: Pulls all environment variables from the Staging app environment in Heroku.
Arity: There will be one Review app for each PR until the PR is merged, upon which the Review app is destroyed.
Build: Built automatically upon any new merges of Pull Requests into master.
Env: Gets environment variables from the file .env.heroku/staging-affinityworks.
Arity: Only one Staging app.
Build: Production is built manually built upon promoting Staging.
Env: Gets environment variables from the file .env.heroku/affinityworks
Arity: Currently there is one general Production app, as well as one client specific Production app.
Description: The Heroku CI is currently set up to run automatically upon any of the following conditions: a push to an open Pull Request, a merge of a PR into master, a promotion from one app in the pipeline up to the next (such as from staging to production).
Build: The Heroku CI build pays attention to the
environments: test section of
app.json in this repo. This section contains both the
test-setup script to run before running the tests as well as the
test script for actually executing the tests.
Env: Gets environment variables from settings panel in the Settings panel of the Pipeline, under the section Heroku CI.
To add a new environment variable to all of the Heroku apps, follow these steps:
- Add the variable and its value to all of the files listed in config/heroku.yml
- Run the command
rake heroku:export_varsfrom the command line
- Ensure that the variable has been added to each environment by running the command
heroku config:get $VAR -a $ENVwhere $VAR is the name of the variable and $ENV is one of the envs listed in heroku.yml