Giter Club home page Giter Club logo

spoke's Introduction

Build Status

Sauce Test Status

Spoke

Spoke is an open source text-distribution tool for organizations to mobilize supporters and members into action. Spoke allows you to upload phone numbers, customize scripts and assign volunteers to communicate with supporters while allowing organizations to manage the process.

Spoke was created by Saikat Chakrabarti and Sheena Pakanati, and is now maintained by MoveOn.org.

The latest version is 1.4.1 (see release notes) which we recommend for production use, while our main branch is where features still in development and testing will be available.

Note

This is generated from react-apollo-starter-kit. Look at that project's README for info on some of the libraries used.

Deploy to Heroku

Deploy

Follow up instructions located here

Please let us know if you deployed by filling out this form here

Getting started

  1. Install either sqlite (or another knex-supported database)
  2. Install the Node version listed under engines in package.json. NVM is one way to do this.
  3. npm install
  4. npm install -g foreman
  5. cp .env.example .env
  6. If you want to use Postgres:
    • In .env set DB_TYPE=pg. (Otherwise, you will use sqlite.)
    • Set DB_PORT=5432, which is the default port for Postgres.
    • Create the spokedev database: psql -c "create database spokedev;"
  7. Create an Auth0 account. In your Auth0 account, go to Applications, click on Default App and then grab your Client ID, Client Secret, and your Auth0 domain (should look like xxx.auth0.com). Add those inside your .env file (AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET, AUTH0_DOMAIN respectively).
  8. Run npm run dev to create and populate the tables.
  9. In your Auth0 app settings, add http://localhost:3000/login-callback , http://localhost:3000 and http://localhost:3000/logout-callback to "Allowed Callback URLs", "Allowed Web Origins" and "Allowed Logout URLs" respectively. (If you get an error when logging in later about "OIDC", go to Advanced Settings section, and then OAuth, and turn off 'OIDC Conformant')
  10. Add a new rule in Auth0:
function (user, context, callback) {
context.idToken["https://spoke/user_metadata"] = user.user_metadata;
callback(null, user, context);
}
  1. Update the Auth0 Universal Landing page, click on the Customize Login Page toggle, and copy and paste following code in the drop down into the Default Templates space:

    Code to paste into Auth0
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <title>Sign In with Auth0</title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    </head>
    <body>
      <!--[if IE 8]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/ie8/0.2.5/ie8.js"></script>
      <![endif]-->
    
      <!--[if lte IE 9]>
      <script src="https://cdn.auth0.com/js/base64.js"></script>
      <script src="https://cdn.auth0.com/js/es5-shim.min.js"></script>
      <![endif]-->
      <script src="https://cdn.auth0.com/js/lock/11.11/lock.min.js"></script>
      <script>
        // Decode utf8 characters properly
        var config = JSON.parse(decodeURIComponent(escape(window.atob('@@config@@'))));
        config.extraParams = config.extraParams || {};
        var connection = config.connection;
        var prompt = config.prompt;
        var languageDictionary;
        var language;
    
        if (config.dict && config.dict.signin && config.dict.signin.title) {
          languageDictionary = { title: config.dict.signin.title };
        } else if (typeof config.dict === 'string') {
          language = config.dict;
        }
        var loginHint = config.extraParams.login_hint;
    
        // Available Lock configuration options: https://auth0.com/docs/libraries/lock/v11/configuration
        var lock = new Auth0Lock(config.clientID, config.auth0Domain, {
          auth: {
            redirectUrl: config.callbackURL,
            responseType: (config.internalOptions || {}).response_type ||
              (config.callbackOnLocationHash ? 'token' : 'code'),
            params: config.internalOptions
          },
          // Additional configuration needed for custom domains: https://auth0.com/docs/custom-domains/additional-configuration
          // configurationBaseUrl: config.clientConfigurationBaseUrl,
          // overrides: {
          //   __tenant: config.auth0Tenant,
          //   __token_issuer: 'YOUR_CUSTOM_DOMAIN'
          // },
          assetsUrl:  config.assetsUrl,
          allowedConnections: ['Username-Password-Authentication'],
          rememberLastLogin: !prompt,
          language: language,
          languageDictionary: {
            title: 'Spoke',
            signUpTerms: 'I agree to the <a href="YOUR_LINK HERE" target="_new">terms of service and privacy policy</a>.'
          },
          mustAcceptTerms: true,
          theme: {
            logo:            '',
            primaryColor:    'rgb(83, 180, 119)'
          },
          additionalSignUpFields: [{
            name: 'given_name',
            icon: 'https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png',
            placeholder: 'First Name'
          }, {
            name: 'family_name',
            placeholder: 'Last Name',
            icon: 'https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png'
          }, {
            name: 'cell',
            placeholder: 'Cell Phone',
            icon: 'https://upload.wikimedia.org/wikipedia/commons/c/ca/1x1.png',
            validator: (cell) => ({
              valid: cell.length >= 10,
              hint: 'Must be a valid phone number'
            })
          }],
          prefill: loginHint ? { email: loginHint, username: loginHint } : null,
          closable: false,
          defaultADUsernameFromEmailPrefix: false,
          // Uncomment if you want small buttons for social providers
          // socialButtonStyle: 'small'
        });
        lock.show();
      </script>
    </body>
    </html>
  2. If the application is still running from step 8, kill the process and re-run npm run dev to restart the app. Wait until you see both "Node app is running ..." and "webpack: Compiled successfully." before attempting to connect. (make sure environment variable JOBS_SAME_PROCESS=1)

  3. Go to http://localhost:3000 to load the app.

  4. As long as you leave SUPPRESS_SELF_INVITE= blank and unset in your .env you should be able to invite yourself from the homepage.

    • If you DO set that variable, then spoke will be invite-only and you'll need to generate an invite. Run:
      echo "INSERT INTO invite (hash,is_valid) VALUES ('abc', 1);" |sqlite3 mydb.sqlite
      # Note: When doing this with PostgreSQL, you would replace the `1` with `true`
      
    • Then use the generated key to visit an invite link, e.g.: http://localhost:3000/invite/abc. This should redirect you to the login screen. Use the "Sign Up" option to create your account.
  5. You should then be prompted to create an organization. Create it.

If you want to create an invite via the home page "Login and get started" link, make sure your SUPPRESS_SELF_INVITE variable is not set.

Getting started with Docker

  1. cp .env.example .env
  2. Follow Steps 7, 9, & 10 above to set up your Auth0 account.
  3. Build a Spoke Docker image with docker-compose build app
  4. Start the PostgreSQL & Redis containers in the background with docker-compose up -d postgres redis.
  5. Start the Spoke application in the foreground with docker-compose up app.
  6. Go to http://localhost:3000 to load the app.
  7. Follow Step 13 above.
  • But if you need to generate an invite, run:
docker-compose exec postgres psql -U spoke -d spokedev -c "INSERT INTO invite (hash,is_valid) VALUES ('<your-hash>', true);"
  • Then use the generated key to visit an invite link, e.g.: http://localhost:3000/invite/<your-hash>. This should redirect you to the login screen. Use the "Sign Up" option to create your account.
  1. You should then be prompted to create an organization. Create it.
  2. Bring down your application with docker-compose down, or docker-compose down -v to bring it down and completely destroy your Postgres database & Redis datastore along with it.

Running Tests

See https://github.com/MoveOnOrg/Spoke/blob/main/docs/HOWTO-run_tests.md

Big Thanks

Cross-browser Testing Platform and Open Source <3 Provided by Sauce Labs.

Helpful Dev Tips

SMS

For development, you can set DEFAULT_SERVICE=fakeservice to skip using an SMS provider (Twilio or Nexmo) and insert the message directly into the database.

To simulate receiving a reply from a contact you can use the Send Replies utility: http://localhost:3000/admin/1/campaigns/1/send-replies, updating the app and campaign IDs as necessary.

Twilio

Twilio provides test credentials that will not charge your account as described in their documentation. You may use either your test credentials or your live keys by following the instructions here.

Deploying

  1. Run OUTPUT_DIR=./build npm run prod-build-server This will generate something you can deploy to production in ./build and run nodejs server/server/index.js
  2. Run npm run prod-build-client
  3. Make a copy of deploy/spoke-pm2.config.js.template, e.g. spoke-pm2.config.js, add missing environment variables, and run it with pm2, e.g. pm2 start spoke-pm2.config.js --env production
  4. Install PostgreSQL
  5. Start PostgreSQL (e.g. sudo /etc/init.d/postgresql start), connect (e.g. sudo -u postgres psql), create a user and database (e.g. create user spoke password 'spoke'; create database spoke owner spoke;), disconnect (e.g. \q) and add credentials to DB_ variables in spoke-pm2.config.js

License

Spoke is licensed under the MIT license.

spoke's People

Contributors

spakanati avatar schuyler1d avatar shakalee14 avatar lperson avatar bchrobot avatar cp4r3z avatar sreynen avatar jamesr2323 avatar mathemagica avatar joemcl avatar benmort avatar jparkrr avatar hiemanshu avatar jmcarp avatar azuzunaga avatar sandramchung avatar codygordon avatar saikat avatar ben-pr-p avatar harpojaeger avatar bdatkins avatar millsoper avatar etothepiipower avatar lady3bean avatar jlegrone avatar zluo16 avatar jeremyparker avatar anasauce avatar dzeez avatar dalperin avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.