Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decidim-elections module #313

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
89 changes: 89 additions & 0 deletions decidim-elections/.byebug_history
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
continue
record
continue
record
record.model_name
continue
record.model_name
record.class
continue
record.class
record.model_name
continue
record.model_name
record.model
record.models
record.class
options
record
q
object
options
record
record[0]
record.class
q
continue
record.class
record[1]
record[0]
record
record.record
record.model
record.public_methods - Object.public_methods
Object.public_methods
record.public_methods
record.public_method
record.keys
record
options
q
continue
options
continue
record
q
record
q
current_user.roles
current_user.role
current_user
q
puts subject
continue
puts subject
continue
organization
voting
continue
puts subject
continue
puts subject
continue
puts subject
continue
expect(subject).to eq("")
subject.html
continue
pp voting
voting
voting.image
continue
voting.image
voting
n
voting.attachments
continue
voting.attachments.count
continue
page
continue
puts page.driver.to_s
page.driver
page.driver.browser.manage.logs.get(:browser)
continue
sleep 10
take_screenshot
upload_keys
continue
puts Capybara.default_max_wait_time
17 changes: 17 additions & 0 deletions decidim-elections/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

# rspec failure tracking
.rspec-failures

# default test application
spec/decidim_dummy_app

# default development application
development_app
103 changes: 103 additions & 0 deletions decidim-elections/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Decidim::Elections

:warning: This module is under development and is not ready to be used in production.

The Elections module adds elections to any participatory space.

## Usage

Elections will be available as a Component for a Participatory Space.

In order to celebrate [End-to-end auditable votings](https://en.wikipedia.org/wiki/End-to-end_auditable_voting_systems) using the Elections module, you will need to connect your Decidim instance with an instance of the [Decidim Bulletin Board application](https://github.com/decidim/decidim-bulletin-board/). To create this connection, please check the [instructions](https://docs.decidim.org/en/services/elections_bulletin_board/).

## Development

In the case that you only want to use this module for local development or testing purposes, you have an example docker-compose configuration in `docs/`. Mind that this setup is not recommended for production environments. It works with default seeds and configurations for a Decidim installation, so you should not do anything.

```bash
cd docs/docker/bulletin_board
docker-compose up
```

One important caveat is that as the Trustees' key generation functionality uses the IndexedDB API, and at least in Firefox there is unsupported in the Private Browsing mode (see ticket [#1639542 in Mozilla's Bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1639542)). As a workaround there is the [Firefox Multi-Account Containers addon](https://addons.mozilla.org/es/firefox/addon/multi-account-containers/).

## Testing

Besides the [set-up typical for Decidim](https://docs.decidim.org/en/develop/develop/testing), for some of the specs a Bulletin Board installation is needed, running in port 5017 by default with the `DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL` environment variable set up with the "true" string. There is a working configuration on `docs`.

```bash
cd docs/docker/bulletin_board_test
docker-compose up
```

As the Bulletin Board service is a necessary dependency for this module to work, if it is not running while executing the specs, the following exception will be shown.

> Failure/Error: Decidim::Elections.bulletin_board.reset_test_database
>
> StandardError:
> Sorry, something went wrong
>
> ./spec/shared/test_bulletin_board_shared_context.rb:6:in 'block (2 levels) in <top (required)>'
> (...)
> -- Caused by:
> Errno::ECONNREFUSED:
> Connection refused - connect(2) for 127.0.0.1:5017
> ./spec/shared/test_bulletin_board_shared_context.rb:6:in 'block (2 levels) in <top (required)>'

## Installation

Add this line to your application's Gemfile:

```ruby
gem "decidim-elections"
```

And then execute:

```bash
bundle
```

## Configuration

### Identification numbers

For the verification of the participants' data in the Voting's census, you can configure which type of documents a participant can have. By default these documents are `identification_number` and `passport`, but in some countries you may need to adapt these to your specifics needs. For instance, in Spain there are `dni`, `nie` and `passport`.

For configuring these you can do so with the Environment Variable `ELECTIONS_DOCUMENT_TYPES`.

```env
ELECTIONS_DOCUMENT_TYPES="dni,nie,passport"
```

You need to also add the following keys in your i18n files (i.e. `config/locales/en.yml`).

```yaml
en:
decidim:
votings:
census:
document_types:
dni: DNI
nie: NIE
passport: Passport
```

### Scheduled tasks

For the Elections module to function as expected, there are some background tasks that should be scheduled to be executed regularly. Alternatively you could use `whenever` gem or the scheduled jobs of your hosting provider.

You can configure it with `crontab -e`, for instance if you have created your Decidim application on /home/user/decidim_application:

```bash
# Remove census export files
0 0 * * * cd /home/user/decidim_application && RAILS_ENV=production bundle exec rake decidim_votings_census:delete_census_access_codes_export
```

## Contributing

See [Decidim](https://github.com/decidim/decidim).

## License

See [Decidim](https://github.com/decidim/decidim).
3 changes: 3 additions & 0 deletions decidim-elections/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

require "decidim/dev/common_rake"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module Decidim
module Elections
module ContentBlocks
class RelatedElectionsCell < Decidim::ContentBlocks::HighlightedElementsWithCellForListCell
private

def list_cell_path = "decidim/elections/highlighted_elections_for_component"
end
end
end
end
27 changes: 27 additions & 0 deletions decidim-elections/app/cells/decidim/elections/election_cell.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Decidim
module Elections
# This cell renders the election card for an instance of an election
# the default size is the Search Card (:s)
class ElectionCell < Decidim::ViewModel
include ElectionCellsHelper
include Cell::ViewModel::Partial

def show
cell card_size, model, options
end

private

def card_size
case @options[:size]
when :s
"decidim/elections/election_s"
else
"decidim/elections/election_g"
end
end
end
end
end
23 changes: 23 additions & 0 deletions decidim-elections/app/cells/decidim/elections/election_g_cell.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module Decidim
module Elections
# This cell renders the Grid (:g) election card
# for a given instance of an Election
class ElectionGCell < Decidim::CardGCell
include ElectionCellsHelper

def metadata_cell
"decidim/elections/election_metadata"
end

def has_image?
model.photos.present?
end

def resource_image_path
model.photos.first.url if has_image?
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module Decidim
module Elections
# This cell renders metadata for an instance of an Election
class ElectionMetadataCell < Decidim::CardMetadataCell
def initialize(*)
super

@items.prepend(*election_items)
end

private

def election_items
[dates_metadata_item, state_item]
end

def state_item
return if model.voting_period_status.blank?

{ text: content_tag(:span, I18n.t(model.voting_period_status, scope: "decidim.elections.election_m.badge_name"), class: "label #{state_class}") }
end

def state_class
case model.voting_period_status
when :ongoing
"success"
when :upcoming
"warning"
end
end

def start_date
return unless model.start_time

model.start_time.to_date
end

def end_date
return unless model.end_time

model.end_time.to_date
end

def dates_metadata_item
{
icon: "calendar-todo-line",
text: [
start_date.present? ? l(start_date, format: :decidim_short_with_month_name_short) : "?",
end_date.present? ? l(end_date, format: :decidim_short_with_month_name_short) : "?"
].join(" → ")
}
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div class="election__section-title">
<%= icon "question-mark" %>
<h2 class="h4"><%= t("decidim.elections.elections.preview.title") %></h2>
</div>

<p class="election__section-desc"><%= t("decidim.elections.elections.preview.description") %></p>

<ul id="accordion-preview" class="space-y-8" data-component="accordion">
<% model.questions.each_with_index do |question, ix| %>
<li class="election__accordion">
<button id="accordion-trigger-<%= ix %>" data-controls="accordion-panel-<%= ix %>" class="election__accordion-trigger" <%= " data-open='true'" if model.questions.one? %>>
<%= translated_attribute(question.title) %>
<%= icon "arrow-down-s-line" %>
<%= icon "arrow-up-s-line" %>
</button>

<div id="accordion-panel-<%= ix %>" class="election__accordion-panel" aria-hidden="true">
<strong><%= t("decidim.elections.elections.preview.available_answers") %></strong>

<ul>
<% question.answers.each do |answer| %>
<li><%= translated_attribute(answer.title) %></li>
<% end %>
</ul>
</div>
</li>
<% end %>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module Decidim
module Elections
# This cell renders the questions preview
# for a given instance of an Election
class ElectionPreviewCell < Decidim::ViewModel
def show
render unless model.finished?
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div>
<div class="flex items-center justify-between gap-2">
<div class="flex justify-between grow bg-gray" role="progressbar" tabindex="0" aria-labelledby="total-answers-<%= id %>" aria-valuenow="<%= results_percentage %>" aria-valuemin="0" aria-valuetext="<%= results_percentage %> %" aria-valuemax="100">
<div class="h-2 bg-success" style="width: <%= results_percentage %>%"></div>
</div>

<div class="w-1/6 md:w-1/12 font-bold text-right">
<%= t("decidim.elections.elections.results.percentage", count: results_percentage) %>
</div>
</div>

<div id="total-answers-<%= id %>" class="text-sm font-semibold">
<%= t("decidim.elections.elections.results.votes", count: results_total) %>
</div>
</div>
Loading
Loading