Skip to content

Commit

Permalink
Create tokens for groups (#15)
Browse files Browse the repository at this point in the history
* add controller

* add back button

* Update config/locales/en.yml

* Update app/views/decidim/anonymous_codes/admin/codes/index.html.erb

* add new method to codes_controller

* add command createtokens and destroy method

* fix merge

* table headers

* fix index page

* add warning when inactive gorup

* fix index empty status

* add system token_codes_spec

* relocate exporters

* resolve review comments

* use custom find_exporter

* add create_tokens_spec

* add tokens_form_spec

* add codes_controller_spec

* add checks to controller spec

* fix codes_controller_spec get index check

* allow to create tokens from the group creation

* fix controller spec

* add test case for GET #new controller method

* add destroy method spec check

* add create controller method spec

* add create_tokens_job spec

* resolve PR specs review comments

---------

Co-authored-by: elviabth <[email protected]>
  • Loading branch information
microstudi and ElviaBth authored Apr 22, 2024
1 parent 9bc4469 commit f8119d9
Show file tree
Hide file tree
Showing 32 changed files with 668 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def call

transaction do
create_code_group!
CreateTokensJob.perform_later(code_group, form.num_tokens) if form.num_tokens.present?
end

broadcast(:ok)
Expand Down
26 changes: 26 additions & 0 deletions app/commands/decidim/anonymous_codes/admin/create_tokens.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module Decidim
module AnonymousCodes
module Admin
class CreateTokens < Decidim::Command
def initialize(form, code_group)
@form = form
@code_group = code_group
end

def call
return broadcast(:invalid) if form.invalid?

CreateTokensJob.perform_later(code_group, form.num_tokens)

broadcast(:ok)
end

private

attr_reader :form, :code_group
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module SurveysControllerOverride
next unless current_settings.allow_answers? && survey.open?
next if visitor_already_answered?

if token_groups.any?
if token_groups.active.any?
next if current_token&.available?

if current_token.blank?
Expand All @@ -22,6 +22,10 @@ module SurveysControllerOverride
end
render "decidim/anonymous_codes/surveys/code_required"
end

if token_groups.inactive.any? && current_user&.admin?
flash.now[:alert] = I18n.t("decidim.anonymous_codes.inactive_group", path: decidim_admin_anonymous_codes.edit_code_group_path(token_groups.inactive.first)).html_safe
end
end

after_action only: :answer do
Expand All @@ -35,11 +39,11 @@ module SurveysControllerOverride
private

def token_groups
@token_groups ||= Decidim::AnonymousCodes::Group.where(resource: survey, active: true)
@token_groups ||= Decidim::AnonymousCodes::Group.where(resource: survey)
end

def current_token
@current_token ||= Decidim::AnonymousCodes::Token.where(group: token_groups).find_by(token: token_param)
@current_token ||= Decidim::AnonymousCodes::Token.where(group: token_groups.active).find_by(token: token_param)
end

def token_param
Expand Down
22 changes: 19 additions & 3 deletions app/controllers/decidim/anonymous_codes/admin/codes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,34 @@ def index
def new
enforce_permission_to :create, :anonymous_code_token

# todo
@form = form(TokensForm).instance
end

def create
enforce_permission_to :create, :anonymous_code_token

# todo
@form = form(TokensForm).from_params(params)

CreateTokens.call(@form, code_group) do
on(:ok) do
flash[:notice] = I18n.t("codes.create.success", scope: "decidim.anonymous_codes.admin")
redirect_to code_group_codes_path
end

on(:invalid) do
flash.now[:alert] = I18n.t("codes.create.invalid", scope: "decidim.anonymous_codes.admin")
render action: "new"
end
end
end

def destroy
enforce_permission_to :destroy, :anonymous_code_token, token: token
# todo
token.destroy!

flash[:notice] = I18n.t("codes.destroy.success", scope: "decidim.anonymous_codes.admin")

redirect_to code_group_codes_path
end

def export
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

require "wicked_pdf"

module Decidim
module AnonymousCodes
module Exporters
# Inherits from abstract PDF exporter. This class is used to set
# the parameters used to create a PDF when exporting Survey Answers.
#
class AnonymousTokensPdf < Decidim::Exporters::PDF
def controller
@controller ||= AnonymousTokensPdfControllerHelper.new
end

def template
"decidim/anonymous_codes/admin/export/tokens_pdf"
end

def layout
"decidim/anonymous_codes/admin/export/pdf"
end

def locals
{
code_group: collection&.first&.group,
collection: collection.map { |token| Decidim::AnonymousCodes::TokenSerializer.new(token).serialize }
}
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

module Decidim
module AnonymousCodes
module Exporters
# rubocop: disable Rails/ApplicationController
# A dummy controller to render views while exporting questionnaires
class AnonymousTokensPdfControllerHelper < ActionController::Base
# rubocop: enable Rails/ApplicationController
helper Decidim::TranslationsHelper
end
end
end
end
2 changes: 2 additions & 0 deletions app/forms/decidim/anonymous_codes/admin/code_group_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ class CodeGroupForm < Decidim::Form
attribute :active, Boolean, default: true
attribute :max_reuses, Integer, default: 1
attribute :resource_id, Integer
attribute :num_tokens, Integer

validates :title, translatable_presence: true
validates :expires_at, date: { after: Time.current }, if: ->(form) { form.expires_at.present? && form.active }
validates :max_reuses, presence: true, numericality: { only_integer: true, greater_than: 0 }
validates :num_tokens, numericality: { only_integer: true, greater_than: 0 }, if: ->(form) { form.num_tokens.present? }

def resource
@resource ||= Decidim::Surveys::Survey.find_by(id: resource_id)
Expand Down
13 changes: 13 additions & 0 deletions app/forms/decidim/anonymous_codes/admin/tokens_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module Decidim
module AnonymousCodes
module Admin
class TokensForm < Decidim::Form
attribute :num_tokens, Integer, default: 1

validates :num_tokens, presence: true, numericality: { only_integer: true, greater_than: 0 }
end
end
end
end
31 changes: 31 additions & 0 deletions app/jobs/decidim/anonymous_codes/create_tokens_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Decidim
module AnonymousCodes
class CreateTokensJob < ApplicationJob
def perform(code_group, num_tokens)
@code_group = code_group
num_tokens.times do
create_token!
end
end

private

attr_reader :code_group

def create_token!
token = new_token while token.blank?
token.save!
end

def new_token
token = Decidim::AnonymousCodes::Token.new(
token: Decidim::AnonymousCodes.token_generator,
group: code_group
)
token if token.valid?
end
end
end
end
10 changes: 9 additions & 1 deletion app/jobs/decidim/anonymous_codes/export_group_tokens_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ class ExportGroupTokensJob < ApplicationJob
queue_as :exports

def perform(user, group, format)
export_data = Decidim::Exporters.find_exporter(format).new(group.tokens, TokenSerializer).export
exporter = format == "AnonymousTokensPdf" ? Decidim::AnonymousCodes::Exporters::AnonymousTokensPdf : Decidim::Exporters.find_exporter(format)

if exporter
Rails.logger.info "Exporting tokens for group #{group.id} in #{format} format"
else
Rails.logger.error "Cannot export tokens for group #{group.id}: Unknown format: #{format}"
end

export_data = exporter.new(group.tokens, TokenSerializer).export

ExportMailer.export(user, "tokens_for_group_#{group.id}", export_data).deliver_now
end
Expand Down
3 changes: 3 additions & 0 deletions app/models/decidim/anonymous_codes/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class Group < ApplicationRecord
has_many :tokens, class_name: "Decidim::AnonymousCodes::Token", dependent: :destroy
belongs_to :resource, polymorphic: true, optional: true

scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }

def self.for(organization)
where(organization: organization)
end
Expand Down
36 changes: 14 additions & 22 deletions app/views/decidim/anonymous_codes/admin/code_groups/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
<div class="card">
<div class="card-divider">
<h2 class="card-title"><%= title %></h2>
</div>

<div class="card-section">
<div class="row column">
<%= form.translated :text_field, :title, label: t(".title") %>
</div>
<div class="row column">
<%= form.translated :text_field, :title, label: t(".title") %>
</div>

<div class="row column">
<%= form.datetime_field :expires_at, label: t(".expires_at") %>
</div>
<div class="row column">
<%= form.datetime_field :expires_at, label: t(".expires_at") %>
</div>

<div class="row column">
<%= form.check_box :active, label: t(".active") %>
</div>
<div class="row column">
<%= form.check_box :active, label: t(".active") %>
</div>

<div class="row column">
<%= form.number_field :max_reuses, label: t(".max_reuses") %>
</div>
<div class="row column">
<%= form.number_field :max_reuses, label: t(".max_reuses") %>
</div>

<div class="row column">
<%= form.select :resource_id, surveys, include_blank: true, label: t(".resource") %>
</div>
</div>
<div class="row column">
<%= form.select :resource_id, surveys, include_blank: true, label: t(".resource") %>
</div>
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
<%= decidim_form_for(@form, html: { class: "form edit_code_group" }) do |f| %>
<%= render partial: "form", object: f, locals: { title: t(".title") } %>
<div class="card">
<div class="card-divider">
<h2 class="card-title"><%= t(".title") %>
<a class="button tiny button--title hollow" href="<%= code_groups_path %>"><%= t("codes.index.back", scope: "decidim.anonymous_codes.admin") %></a>
</h2>
</div>

<div class="card-section">
<%= render partial: "form", object: f %>
</div>
</div>

<div class="button--double form-general-submit">
<%= f.submit "update" %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
<% groups.each do |group| %>
<tr>
<td><%= translated_attribute(group.title) %></td>
<td><%= t("booleans.#{group.active}") %></td>
<td><%= group.expires_at.present? ? ("<span class=\"text-#{ group.expired? ? "warning" : ""}\">#{l(group.expires_at, format: :decidim_short)}</span>".html_safe) : t(".never") %></td>
<td><strong class="<%= group.active? ? "text-success" : "text-alert" %>"><%= t("booleans.#{group.active}") %></strong></td>
<td><%= group.expires_at.present? ? ("<span class=\"text-#{ group.expired? ? "warning" : ""}\">#{l(group.expires_at, format: :decidim_short)}</span>".html_safe) : content_tag(:em, t(".never")) %></td>
<td><%= "#{group.tokens.used.count} / #{group.tokens_count}" %></td>
<td><%= group.max_reuses %></td>
<td class="table-list__actions">
<%= icon_link_to "eye", resource_path(group), t("actions.preview", scope: "decidim.anonymous_codes.admin"), class: "action-icon--preview#{group&.resource ? '':' invisible'}", target: :_blank %>
<%= icon_link_to "list", code_group_codes_path(group), t("actions.list_tokens", scope: "decidim.anonymous_codes.admin"), class: "action-icon--preview#{group&.resource ? '':' invisible'}" %>
<%= icon_link_to "pencil", edit_code_group_path(group.id), t("actions.edit", scope: "decidim.anonymous_codes.admin"), class: "action-icon--edit#{allowed_to?(:update, :anonymous_code_group, code_group: group) ? '' : ' invisible'}" %>
<%= icon_link_to "circle-x", code_group_path(group.id), t("actions.destroy", scope: "decidim.anonymous_codes.admin"), method: :delete, class: "action-icon--remove#{allowed_to?(:destroy, :anonymous_code_group, code_group: group) ? '' : ' invisible'}", data: { confirm: t("actions.confirm_destroy", scope: "decidim.anonymous_codes.admin") } %>
<%= icon_link_to "list", code_group_codes_path(group), t("actions.list_tokens", scope: "decidim.anonymous_codes.admin"), class: "action-icon--preview#{allowed_to?(:view, :anonymous_code_token) ? '':' invisible'}" %>
<%= icon_link_to "pencil", edit_code_group_path(group), t("actions.edit", scope: "decidim.anonymous_codes.admin"), class: "action-icon--edit#{allowed_to?(:update, :anonymous_code_group, code_group: group) ? '' : ' invisible'}" %>
<%= icon_link_to "circle-x", code_group_path(group), t("actions.destroy", scope: "decidim.anonymous_codes.admin"), method: :delete, class: "action-icon--remove#{allowed_to?(:destroy, :anonymous_code_group, code_group: group) ? '' : ' invisible'}", data: { confirm: t("actions.confirm_destroy", scope: "decidim.anonymous_codes.admin") } %>
</td>
</tr>
<% end %>
Expand All @@ -44,7 +44,7 @@
<% else %>
<div>
<%= t("code_groups.index.no_access_code_groups_records", scope: "decidim.anonymous_codes.admin") %>
<p><%= t("code_groups.index.start_by", scope: "decidim.anonymous_codes.admin", button: link_to(t("code_groups.index.new_access_code_group_button", scope: "decidim.anonymous_codes.admin"), new_code_group_path)) %></p>
<p><%= link_to t("code_groups.index.start_by", scope: "decidim.anonymous_codes.admin"), new_code_group_path %></p>
</div>
<% end %>
</div>
Expand Down
16 changes: 15 additions & 1 deletion app/views/decidim/anonymous_codes/admin/code_groups/new.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
<%= decidim_form_for(@form, url: code_groups_path, html: { class: "form new_code_group" }) do |f| %>
<%= render partial: "form", object: f, locals: { title: t(".title") } %>
<div class="card">
<div class="card-divider">
<h2 class="card-title"><%= t(".title") %>
<a class="button tiny button--title hollow" href="<%= code_groups_path %>"><%= t("codes.index.back", scope: "decidim.anonymous_codes.admin") %></a>
</h2>
</div>

<div class="card-section">
<%= render partial: "form", object: f %>

<div class="row column">
<%= f.number_field :num_tokens, label: t(".num_tokens") %>
</div>
</div>
</div>

<div class="button--double form-general-submit">
<%= f.submit "create" %>
Expand Down
14 changes: 14 additions & 0 deletions app/views/decidim/anonymous_codes/admin/codes/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="card">
<div class="card-divider">
<h2 class="card-title"><%= title %>

<a class="button tiny button--title hollow" href="<%= code_group_codes_path(code_group) %>"><%= t("codes.index.back_to_codes", scope: "decidim.anonymous_codes.admin") %></a>
</h2>
</div>

<div class="card-section">
<div class="row column">
<%= form.number_field :num_tokens, label: t(".number_of_tokens_to_generate") %>
</div>
</div>
</div>
Loading

0 comments on commit f8119d9

Please sign in to comment.