Giter Club home page Giter Club logo

swapmyvote's Introduction

Swap My Vote

Swap My Vote is a platform which allows voters to find a partner to swap their vote with. Rather than voting for their preferred minority party in a constituency where a tactical vote is necessary or worthwhile, a voter can find someone who will vote for their preferred party somewhere where that vote makes sense, even under the First Past The Post voting system. In return, they will vote for their partners preferred party as a tactical vote in their own constituency.

Swap My Vote ran a successful project in both the 2015, 2017 and 2019 UK general elections at www.swapmyvote.uk, and is preparing to do the same for the 2024 general election too.

In the interests of transparency, all of the code that we have written and used is available in this repository. We are in the process of working out how to make this project sustainable, but providing an open and welcoming community for continued developed will be important. So please have a look at the Contributing and Contact sections below if you'd like to help.

Setting up Swap My Vote locally

You will need Ruby and Yarn installed.

  • Clone this repository:

    git clone https://github.com/swapmyvote/swapmyvote.git
    
  • Install the necessary gems:

    bundle install
    

    If this fails with error messages that mention pg or PostgreSQL, then try instead:

    bundle install --without=production
    

    since the PostgreSQL database is not normally needed for local development (sqlite is used instead).

  • Install npm packages with Yarn:

    yarn install
    

    If you get an error similar to "The engine "node" is incompatible with this module" then you may need to update to a more recent version of node.js.

  • Set up some credentials and other config variables in a .env.development.local file. You can ask @aspiers for a copy of this file, or if you are using your own Facebook and Twitter apps for login then you can make it yourself by starting from a template:

    $ cp .env.example .env.development.local
    $ cp .env.test.example .env.test.local
    

    Now edit .env.development.local to contain the appropriate credentials. These will get automatically loaded via the dotenv-rails gem.

  • Set up the database schema and populate it with constituency and poll data, as well as some test users accounts for local development.

    bundle exec rake db:setup
    
  • environment variables

    You will need to be aware of two environment variables.

    • ELECTION_DATE needs to be set permanently to the date of the election in format YYYY-MM-DD. This has an impact on your local site
    • ELECTION_TYPE should preferably be set permanently to 'general' or 'g'. It's possible to omit this step, but the database will be queried more often if it is not set. It may also need to be set for rake db:seed to run correctly for a by-election.
  • Seed the database

    Put some default content into your database

    ELECTION_TYPE=(g or b) bundle exec rake db:seed
    
  • Run the application:

    # Ensure binding to localhost even if $HOST is set, so that
    # the URL is accepted by the facebook development app
    ELECTION_DATE=YY-MM-DD bundle exec rails server -b localhost
    
  • Open your browser to http://localhost:3000.

  • Run Guard during development to automatically run tests and do style linting:

    bundle exec guard
    
  • [rspec-snapshot](https://github.com/levinmr/rspec-snapshot) is used for some of the tests. To update the snapshots, do:

    UPDATE_SNAPSHOTS=true bundle exec rspec
    

    or just for a subset of the tests:

    UPDATE_SNAPSHOTS=true bundle exec rspec spec/foo/bar
    
  • Database migrations

    When you pull from swapmyvotemaster and database migrations (files in db/migrations) are included you'll need to run

    bundle exec rake db:migrate
    

    And for tests to keep running successful you'll also need to run

    bundle exec RAILS_ENV=test rake db:migrate
    

    The test database should be empty, do not run the seeds task against it, some tests will fail.

Note that in the development environment, emails are not sent but instead written as files in the tmp/mails/ subdirectory.

Contributing to Swap my Vote

Any help would be well appreciated!

Onboarding

Before we can accept contributions from you, please make sure you read the License section below and follow the required step.

Deciding what to work on

Please take a look at the GitHub project. Issues are sorted into milestones, and the items are roughly sorted by priority descending, so a good place to start would be near the top. If you can, please avoid tackling stuff in future milestones until the current milestone is complete.

In addition, look out for issues labelled help wanted or easy.

Coordinating with the team

If an issue is already assigned, then probably someone is already working on it or at least intending to. If it's unassigned then probably it's up for grabs. However it's safer to ask in the issue and/or in the Zulip #general chat channel before starting on anything, to avoid accidentally duplicating effort. Please email us at the below address to request an invite to our Zulip chat server.

Our roadmap can be seen in our list of milestones.

Submitting issues and pull requests

When submitting new issues or PRs, please remember to apply any relevant labels. Thanks!

Documentation

Our docs are currently very thin on the ground, but you will find a few things in the doc/ directory, in particular the admin guide which contains a cheatsheet for administering a live site.

Contact

You can contact us at [email protected].

License

In order to help ensure that potential voter partners aren't split across different otherwise identical vote swapping platforms in the same country, we have decided to license the code for the time being as follows:

All Rights Reserved © Forward Democracy Limited.

Issue #33 includes previous discussion which may clarify the motivation for this decision.

Contributions to the code will be very gratefully received! Please first use this link to submit a pull request which adds your GitHub username to the .clabot file. It will auto-populate the commit message with a statement that you agree to assign rights for your contributions to Forward Democracy.

Once we merge this pull request, your GitHub username will be added to our list of approved contributors, and any other pull requests from you can then be accepted. This puts us in a future-proof position regarding copyright, e.g. it keeps the possibility to making some or all of the codebase Open Source in the future.

swapmyvote's People

Contributors

aspiers avatar baob avatar coliff avatar dependabot[bot] avatar douglaslutz avatar egglestn avatar emersonmanabuaraki avatar fkorning avatar georgecrawford avatar jfernando122 avatar joshr avatar jpallen avatar stevebaxter avatar tdg avatar threedaymonk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

swapmyvote's Issues

Allow 'pre-confirmed' swaps

Allow 'pre-confirmed' swaps. I.e. a user could say 'if someone from Isle of Wight wants to vote Green, I'll do that', before there are actually any matching users.

Maybe eliminate duplication of modal login dialogs

There are two identical-looking modal login dialogs:

  • .js-submit-modal in home/index
  • .js-login-modal in layouts/application

Both are susceptible to CVE-2015-9284 as mentioned in #19. @jpallen Is there a good reason for needing this duplication? Can't we scrap the one in home/index and just use .js-login-modal everywhere?

Email deliverability of staging environment via Mailgun

Currently it seems that mails from Mailgun on behalf of swapmyvotedev are getting rejected, at least mails to my domain:

{
	"severity": "permanent",
	"tags": [],
	"storage": {
		"url": "https://se.api.mailgun.net/v3/domains/staging.swapmyvote.uk/messages/AgEFbpQ7aZCb-h01IshIaLcn0pTZs5BMZA==",
		"key": "AgEFbpQ7aZCb-h01IshIbLcn0pTZo5BMZA=="
	},
	"delivery-status": {
		"tls": true,
		"mx-host": "mail.adamspiers.org",
		"code": 450,
		"description": "",
		"session-seconds": 2.2834091186523438,
		"attempt-no": 1,
		"message": "4.1.8 <[email protected]>: Sender address rejected: Domain not found"
	},
	"recipient-domain": "adamspiers.org",
	"id": "Q6_G97ggTs2XMQSj8gG0gA",
	"campaigns": [],
	"reason": "generic",
	"user-variables": {},
	"flags": {
		"is-routed": false,
		"is-authenticated": true,
		"is-system-test": false,
		"is-test-mode": false
	},
	"log-level": "error",
	"timestamp": 1572799481.162327,
	"envelope": {
		"transport": "smtp",
		"sender": "[email protected]",
		"sending-ip": "209.61.151.224",
		"targets": "[email protected]"
	},
	"message": {
		"headers": {
			"to": "[email protected]",
			"message-id": "5dbf03f686103_42ac7ed3a2ef8264fe@ed07d9f5-45dc-4001-b5fe-19b6b93736bb.mail",
			"from": "Swap My Vote <[email protected]>",
			"subject": "Welcome to Swap My Vote"
		},
		"attachments": [],
		"size": 4969
	},
	"recipient": "[email protected]",
	"event": "failed"
}

My mail server logs show the same thing:

Nov  3 16:44:40 coral postfix/smtpd[30015]: NOQUEUE: reject: RCPT from rs224.mailgun.us[209.61.151.224]: 450 4.1.8 <[email protected]>: Sender address rejected: Domain not found; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<rs224.mailgun.us>

I notice that swapmyvote.uk has MX but no TXT records (UPDATE: incorrect, they're for mail.swapmyvote.uk and smtp._domainkey.{mail.staging}), whereas staging.swapmyvote.uk has a TXT record but no MX.

Looking closer at the domain settings in Mailgun, it seems that the staging domain has SPF and DKIM at least partially set up, whereas the production has neither (UPDATE: see above). @jpallen Is this expected? A quick report on the status quo would be really helpful. Thanks!

Detailed searches

Allow users to perform detailed searches when looking for a voting partner.
I.e. filter by constituency, with preset defaults for marginals, local constituencies, target seats, etc.

Add constituency to API

To allow third party sites to populate constituency as well as preferred and willing parties

Allow login based on email

This would open up the site to people who can't or won't use Twitter or Facebook. Dependent on #7 otherwise it would be too easy for spammers to attack the site with lots of fake profiles.

Include all constituency parties in preferred voting options

When asking who the voter would like to vote for (their preferred choice), now include all of the parties from constituency parties lookup #2, but probably with the main (largest) parties at the top.

UPDATE: This issue may not make sense - please see comments.

Mailchimp resource blocked in Firefox

From a user email:

Hello,
I’m trying to sign-up to receive email notifications on your website but isn’t working in Firefox. Nothing happens when I click “Subscribe for updates”. I’m a web developer so I’ve instinctively reached for the inspector and when I do I can see this getting logged to the console:
The resource at “https://swapmyvote.us15.list-manage.com/subscribe/post-json?…86ca43a22f=&subscribe=Subscribe+for+updates&=1572957926500" was blocked because content blocking is enabled.
This is a privacy feature of Firefox, more info here: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Privacy/Tracking_Protection
I’d recommend getting this fixed asap as you’re probably missing out on quite a few potential subscribers!

Flag unconfirmed/cancelled swaps

Don't delete unconfirmed/cancelled swaps, just flag them as cancelled so that we still have a record of what swaps were proposed.

Embeddable widget

A widget would allow other third party (democracy and election tech) platforms and websites to embed on their site a front end to the vote swapping process.

At present this could be the three questions and dropdowns, but if and as the SmV platform gets more sophisticated, it could remain with basic questions like these, directing user/voters to the next part of the process.

(Inspiration includes @DemocracyClub https://github.com/DemocracyClub/WhereDoIVote-Widget etc)

Add identity verification icons for potential swap partners

When presenting the list of swap candidates, we should put little icons beside each candidate showing how they've verified their identity so far, and by implication (maybe later even explicitly) how much trust can be placed in that candidate being a real person.

Confirm email address for users

Get users to confirm their email address.

This has a few aspects:

  • When they sign up by providing an email address (as of GE2024, the only way to sign up), we need to get them to prove that address is valid.
  • Only when login via Facebook/Twitter is supported (which it isn't as of GE2024):
    • Confirmation is needed when users update their email address from the one obtained from their Facebook/Twitter account; see comments below.
    • Confirmation is needed with first login via Twitter, since Twitter (we think) doesn't provide the address via omniauth.
    • Confirmation is needed with first login via Facebook if the user tells Facebook not to share their Facebook account's email address with swapmyvote.
  • email generated by code from swapmyvote.uk may have deliverability issues (maybe switch to Amazon SES or similar) Not true, we use Mailgun.
  • CTR / responsiveness of users - make sure email entices people to respond. - filed as #32.

Allow user to be linked with multiple social accounts

Currently login is either facebook or twitter, but it should be possible to link an account to both (and maybe others later?) For this we'll probably need a couple of new tables mapping a many-to-many relationship between users and social networks. Or we could just add facebook and twitter fields to the user table - quick and easy although also kind of ugly.

establish data controller

I think this should be as simple as updating the privacy policy to explicitly state the data controller. @tdg can you do this?

Links from privacy policy to deletion from app and mailchimp

This is required by GDPR. We don't necessarily need to automate this - might be enough to explicitly state in the policy that people should email a certain address requesting removal from our database. Then later if we find a lot of people requesting this, we could automate it.

rake db:migrate installation issue

tim@ASUS MINGW64 /c/swapmyvote (master)
$ rake db:migrate

C:/Ruby26-x64/lib/ruby/2.6.0/fileutils/version.rb:4: warning: already initialized constant FileUtils::VERSION
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/fileutils-1.3.0/lib/fileutils/version.rb:4: warning: previous definition of VERSION was here
C:/Ruby26-x64/lib/ruby/2.6.0/fileutils.rb:1267: warning: already initialized constant FileUtils::Entry_::S_IF_DOOR
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/fileutils-1.3.0/lib/fileutils.rb:1285: warning: previous definition of S_IF_DOOR was here
C:/Ruby26-x64/lib/ruby/2.6.0/fileutils.rb:1538: warning: already initialized constant FileUtils::Entry_::DIRECTORY_TERM
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/fileutils-1.3.0/lib/fileutils.rb:1566: warning: previous definition of DIRECTORY_TERM was here
C:/Ruby26-x64/lib/ruby/2.6.0/fileutils.rb:1595: warning: already initialized constant FileUtils::OPT_TABLE
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/fileutils-1.3.0/lib/fileutils.rb:1626: warning: previous definition of OPT_TABLE was here
C:/Ruby26-x64/lib/ruby/2.6.0/fileutils.rb:1649: warning: already initialized constant FileUtils::LOW_METHODS
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/fileutils-1.3.0/lib/fileutils.rb:1685: warning: previous definition of LOW_METHODS was here
C:/Ruby26-x64/lib/ruby/2.6.0/fileutils.rb:1656: warning: already initialized constant FileUtils::METHODS
C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/fileutils-1.3.0/lib/fileutils.rb:1692: warning: previous definition of METHODS was here
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:

class CreateUsers < ActiveRecord::Migration[4.2]
C:/swapmyvote/db/migrate/20141223112651_create_users.rb:1:in `<top (required)>'

Caused by:
StandardError: Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:

class CreateUsers < ActiveRecord::Migration[4.2]
C:/swapmyvote/db/migrate/20141223112651_create_users.rb:1:in `<top (required)>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

Support willingness to vote for multiple parties

Currently the UI asks which single party you would be willing to vote for instead of your preferred party. Instead it should allow you to express a willingness to vote for multiple parties. This could even be a willingness to vote for any party! although that may run into gaming/trust issues.

See also #2 for providing a more precise list of willing parties which are the ones running in the user's constituency.

Multiple swap requests

Allow multiple swap requests at the same time to maximise the chances of a voter finding a suitable swap.

GDPR compliance

GDPR came in since GE2017 so we need to make sure we're compliant. Let's use this issue to track all sub-tasks needed for compliance.

  • ask consent for cookies (#65)
  • establish way for users to be forgotten (#67)
  • establish data controller (#68)
  • Clarify in privacy policy what info is shared from Facebook & Twitter to SMV (email, name) (#73)
  • establish informed consent at point of data entry (login, confirm email address, confirm mobile phone (#74)
  • anonymise IPs (#101)
  • beef up privacy policy (#73)

Update existing swap preferences from home page form on login

If a user set swap preferences on a previous log-in, and then populates the form on the initial landing page before logging in, it will ignore the values on that form and revert to the values previously set for that user. This is counter-intuitive and should be fixed.

Ask for preferences if logging in directly for first time

If a user clicks Already been here? Log in despite not having logged in before, their user profile will be created with the preferred / willing parties left blank, and without them being immediately asked their preferences. Instead it will only ask them for their constituency via /user/constituency/edit, but it should actually redirect to /user/edit.

See also #42.

Messages and push notifications

Move away from email as main point of contact for some users - Facebook messages, SMS texts, WhatsApp?

Emails have a tendency to be ignored/sent to junk.
Can we do native mobile push notifications from a web based app somehow?

Better mobile support

Better mobile support. At the moment the site is responsive, but very much feels like a web app, not a native app on mobile devices. Whether we can have one web app that works well on both, or need a more significant split of front-ends is an open question.

Change willing choices to exact parties running in the user's constituency

Rather than a single list of all parties we support, first find out the user's constituency, then show them the parties that are running in their constituency that they could be willing to vote for (on behalf of someone else).

N.B. this is about modelling which parties are standing in each constituency, not which candidates are standing. The latter is tracked in #619.

See also #27 for allowing the user multiple willing choices, although that could still be done without implementing this.

Motivation

  • Avoids allowing user to choose a party which they can't vote for.
  • Solves the problem of not being able to allow party X in a by-election because they're not in both constituencies.
  • Allows us to include minor parties WEP, NHA, etc.
  • Avoids cluttering the willing list with parties like SNP, or Plaid Cymru who only stand in certain areas (although it would still clutter the preferred list).
  • Open support for Northern Irish parties.

Implementation

For by-elections, we work with a YAML file that tells us the parties anyway.

For general elections, we could work with democracy club data, with some sensible fallbacks. E.g. if missing democracy club data, assume:

  • any party with more than 10 members in parliament will be standing a candidate in that constituency.
  • any Scottish constituency will have a nationalist candidate (SNP)
  • any Welsh constituency will have a nationalist candidate (Plaid)
  • any NI constituency will have a nationalist candidate ?

Decide license for code

Currently the README says the license is TBD. This really should be sorted before we go live for GE2019.

Goals

  • Transparency and trustability: Allow anyone to audit the code
  • Allow people to contribute easily
  • Limit abuse / misuse of the code-base
  • Avoid boxing ourselves into a corner (e.g. we may want to open source some or all of the code later)

Update user-facing text for GE2019

Some of the web/email text still needs to be updated for GE2017. Most of this is in the email templates, but there might be one or two bits of the web UI which need updating too. @tdg This is something you could definitely help with.

Automatically sync user data to CRM system

Automatically sync user data to email management system/ CRM/ VRM (currently Mailchimp) for easily sending out batches of emails in the lead up to the election to remind people to swap/confirm/etc depending on their status.

Better on-boarding

Better on-boarding, where we walk the user through an explanation of the app, and gather the data and permissions necessary for the system to run.

Support usage in other countries

As a long term goal, we would like to allow this to be used in other countries; UK doesn't have a monopoly on broken democracy. We haven't yet figured out exactly what's needed to support that.

fix Rubocop errors

Since #55 was merged we now have Rubocop infrastructure for linting style inconsistencies and other syntax issues. This can be done via:

bundle exec rubocop

Currently there are a number of different issues. This can potentially be tackled via divide and conquer - my main suggestion would be to stick to PR per type of style issue (i.e. per category of Rubocop error or warning). That will make the PRs easier to review, and should help minimise the need to block merging a PR, since it will avoid mixing more controversial changes with less controversial ones.

If anyone is planning to help with aspects of this, please coordinate on Slack to avoid stepping on other people's toes. Thanks!

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.