Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:decidim-ice/decidim-module-decid…
Browse files Browse the repository at this point in the history
…im_awesome into develop
  • Loading branch information
microstudi committed Jul 28, 2024
2 parents d17bdf1 + 57125e4 commit 4045f80
Show file tree
Hide file tree
Showing 126 changed files with 2,765 additions and 794 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
CHANGELOG
=========

v0.11.1
------

Compatibility:
- Decidim v0.28.x

Features:
- Added Private Custom Fields feature
- Added GraphQL types for weighted voting in the API
- Added GraphQL types for custom fields in the API
- Adds parsed information about custom fields in the Proposals export
- Adds parsed information bout private custom fields when admins exports private data

v0.11
------

Expand Down
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ source "https://rubygems.org"

ruby RUBY_VERSION

DECIDIM_VERSION = "0.28.1"
DECIDIM_VERSION = "0.28.2"

gem "decidim", DECIDIM_VERSION
# this causes failures if not enabled (check if still necessary in the future)
gem "decidim-decidim_awesome", path: "."
gem "decidim-templates", DECIDIM_VERSION

gem "bootsnap", "~> 1.4"

Expand Down
85 changes: 79 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,63 @@ Decidim::DecidimAwesome.configure do |config|
end
```

##### 11.1. GraphQL types for custom fields

#### 11.1. GraphQL types for custom fields

Custom fields are displayed in the GaphQL API according to their definition in a formatted array of objects in the attribute `bodyFields`.

A query to extract this information could look like this (see that the original `body` is also available):

```graphql
{
component(id: 999) {
... on Proposals {
proposals {
edges {
node {
id
bodyFields {
locales
translation(locale: "en")
translations {
locale
fields
machineTranslated
}
}
body {
locales
translations {
locale
text
machineTranslated
}
}
}
}
}
}
}
}
```

You can then use this custom type in your GraphQL queries and mutations to handle the custom fields in proposals.


##### 11.2. Private Custom fields

Similar to the custom fields feature, but only admins can see the content of the fields. This is useful for adding metadata to proposals that should not be visible to the public (such as contact data).
Data is stored encrypted in the database.

![Private Custom fields screenshot](examples/private_custom_fields.png)

#### 12. Custom Redirections (or URL shortener feature)

Admins can create custom paths that redirect to other places. Destinations can be internal absolute paths or external sites.
There's also possible to choose to sanitize (ie: remove) any query string or to maintain it (so you can decide to use).

For instance you can create a redirection like
For instance you can create a redirection like

* `/take-me-somewhere` => `/processes/canary-islands`

Expand Down Expand Up @@ -284,6 +335,28 @@ This is the Decidim cell used to provide the metadata that is rendered at the bo

What this cell must do is to provide an array of items to render as part of the cell footer. Check the example used at the [voting cards implementation](app/cells/decidim/decidim_awesome/voting/proposal_metadata_cell.rb) for reference.

##### 16.1 GraphQL Types for weighted voting

When a weighed voting mechanism is selected, the GraphQL API will show those weights separated in each proposal.
The attribute that holds this information is `vote_weights`, a query example could look like this:

```graphql
{
component(id: 999) {
... on Proposals {
proposals {
edges {
node {
id
voteWeights
}
}
}
}
}
}
```

#### 17. Limiting amendments in proposals

By default, when proposals can be amended, any number of amendments can be created.
Expand Down Expand Up @@ -322,7 +395,7 @@ Go to `yourdomain/admin/decidim_awesome` and start tweaking things!
> **EXPERTS ONLY**
>
> Under the hood, when running `bundle exec rails decidim:upgrade` the `decidim-decidim_awesome` gem will run the following two tasks (that can also be run manually if you consider):
>
>
> ```bash
> bin/rails decidim_decidim_awesome:install:migrations
> bin/rails decidim_decidim_awesome:webpacker:install
Expand Down Expand Up @@ -360,11 +433,11 @@ Depending on your Decidim version, choose the corresponding Awesome version to e
| 0.6.x | 0.22.x, 0.23.x |
| 0.5.x | 0.21.x, 0.22.x |

> *Heads up!*
> *Heads up!*
> * version 0.11.0 is only compatible with Decidim v0.28 as a major redesign makes backward compatibility impractical.
> * version 0.10.0 requires database migrations! Don't forget the migrations step when updating.
> * version 0.8.0 removes CSS Themes for tenants. If you have been using them you will have to manually migrate them to custom styles.
> * version 0.8.0 uses ActiveStorage, same as Decidim 0.25. 2 new rake task have been introduced to facilitate the migration: `bin/rails decidim_awesome:active_storage_migrations:check_migration_from_carrierwave` and
> * version 0.8.0 uses ActiveStorage, same as Decidim 0.25. 2 new rake task have been introduced to facilitate the migration: `bin/rails decidim_awesome:active_storage_migrations:check_migration_from_carrierwave` and
`bin/rails decidim_awesome:active_storage_migrations:migrate_from_carrierwave`
> * version 0.7.1 requires database migrations! Don't forget the migrations step when updating.
Expand Down Expand Up @@ -486,8 +559,8 @@ However, this project works with different versions of Decidim. In order to test
You can run run tests against the legacy Decidim versions by using:

```bash
export DATABASE_USERNAME=<username>
export DATABASE_PASSWORD=<password>
export DATABASE_USERNAME=<username>
export DATABASE_PASSWORD=<password>
RBENV_VERSION=3.1.1 BUNDLE_GEMFILE=Gemfile.legacy bundle
RBENV_VERSION=3.1.1 BUNDLE_GEMFILE=Gemfile.legacy bundle exec rake test_app
RBENV_VERSION=3.1.1 BUNDLE_GEMFILE=Gemfile.legacy bundle exec rspec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def constraint_can_be_destroyed?(constraint)
return true if constraint.awesome_config.constraints.count > 1

case constraint.awesome_config.var.to_s
when /^proposal_custom_field/
when /^proposal_(private_)?custom_field/
false
else
true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Decidim
module DecidimAwesome
module Proposals
module Admin
##
# Decorates update draft and update proposal
# to avoid private field to be logged in PaperTrail.
module UpdateProposalOverride
extend ActiveSupport::Concern

included do
private

alias_method :decidim_original_update_proposal, :update_proposal

def update_proposal
decidim_original_update_proposal
update_private_field!
end

def update_private_field!
@proposal.update_private_body!(form.private_body) if form.private_body.present?
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Decidim
module DecidimAwesome
module Proposals
##
# Decorate create_collaborative_draft to avoid
# private data to be in PaperTrail
module CreateCollaborativeDraftOverride
extend ActiveSupport::Concern

included do
private

alias_method :decidim_original_create_collaborative_draft, :create_collaborative_draft

def create_collaborative_draft
created_draft = decidim_original_create_collaborative_draft
# Update the proposal with the private body, to
# avoid tracebility on private fields.
created_draft.update_private_body!(form.private_body) if form.private_body.present?
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Decidim
module DecidimAwesome
module Proposals
##
# Decorate create_proposal to avoid
# private data to be in PaperTrail
module CreateProposalOverride
extend ActiveSupport::Concern

included do
private

alias_method :decidim_original_create_proposal, :create_proposal

def create_proposal
created_proposal = decidim_original_create_proposal
# Update the proposal with the private body, to
# avoid tracebility on private fields.
created_proposal.update_private_body!(form.private_body) if form.private_body.present?
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Decidim
module DecidimAwesome
module Proposals
##
# Decorates update draft and update proposal
# to avoid private field to be logged in PaperTrail.
module UpdateCollaborativeDraftOverride
extend ActiveSupport::Concern

included do
private

alias_method :decidim_original_update_collaborative_draft, :update_collaborative_draft

def update_collaborative_draft
decidim_original_update_collaborative_draft
# Update the proposal with the private body, to
# avoid tracebility on private fields.
@collaborative_draft.update_private_body!(form.private_body) if form.private_body.present?
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module Decidim
module DecidimAwesome
module Proposals
##
# Decorates update draft and update proposal
# to avoid private field to be logged in PaperTrail.
module UpdateProposalOverride
extend ActiveSupport::Concern
include Admin::UpdateProposalOverride

included do
private

alias_method :decidim_original_update_draft, :update_draft

def update_proposal
decidim_original_update_proposal
update_private_field!
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ class CreateProposalCustomField < Command

# Public: Initializes the command.
#
def initialize(organization)
def initialize(organization, config_var = :proposal_custom_fields)
@organization = organization
@ident = rand(36**8).to_s(36)
@config_var = config_var
end

# Executes the command. Broadcasts these events:
Expand All @@ -20,13 +21,13 @@ def initialize(organization)
#
# Returns nothing.
def call
fields = AwesomeConfig.find_or_initialize_by(var: :proposal_custom_fields, organization: @organization)
fields = AwesomeConfig.find_or_initialize_by(var: @config_var, organization: @organization)
fields.value = {} unless fields.value.is_a? Hash
# TODO: prevent (unlikely) colisions with exisiting values
fields.value[@ident] = default_definition
fields.save!

create_constraint_never(:proposal_custom_field)
create_constraint_never(@config_var == :proposal_custom_fields ? :proposal_custom_field : :proposal_private_custom_field)

broadcast(:ok, @ident)
rescue StandardError => e
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ class DestroyProposalCustomField < Command
#
# key - the key to destroy inise proposal_custom_fields
# organization
def initialize(key, organization)
def initialize(key, organization, config_var = :proposal_custom_fields)
@key = key
@organization = organization
@config_var = config_var
end

# Executes the command. Broadcasts these events:
Expand All @@ -20,14 +21,16 @@ def initialize(key, organization)
#
# Returns nothing.
def call
fields = AwesomeConfig.find_by(var: :proposal_custom_fields, organization: @organization)
fields = AwesomeConfig.find_by(var: @config_var, organization: @organization)
return broadcast(:invalid, "Not a hash") unless fields&.value.is_a? Hash
return broadcast(:invalid, "#{key} key invalid") unless fields.value.has_key?(@key)

fields.value.except!(@key)
fields.save!

# remove constrains associated (a new config var is generated automatically, by removing it, it will trigger destroy on dependents)
constraint = AwesomeConfig.find_by(var: "proposal_custom_field_#{@key}", organization: @organization)
constraint = @config_var == :proposal_custom_fields ? :proposal_custom_field : :proposal_private_custom_field
constraint = AwesomeConfig.find_by(var: "#{constraint}_#{@key}", organization: @organization)
constraint.destroy! if constraint.present?

broadcast(:ok, @key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def append_awesome_intergram_directives
if intergram.host && intergram.scheme
content_security_policy.append_csp_directive("script-src", "#{intergram.scheme}://#{intergram.host}")
content_security_policy.append_csp_directive("frame-src", "#{intergram.scheme}://#{intergram.host}")
# this is commetes in the intergram github, but does not look necessary
# this script is in the intergram code, but does not look necessary to work
# content_security_policy.append_csp_directive("frame-src", "http://www.loadmill.com")
# content_security_policy.append_csp_directive("frame-src", "http://app.loadmill.com")
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ConstraintsController < DecidimAwesome::Admin::ApplicationController

layout false
before_action do
enforce_permission_to :edit_config, constraint_key
render plain: "no permissions for #{constraint_key}" unless allowed_to? :edit_config, constraint_key
end

def show
Expand Down Expand Up @@ -132,6 +132,8 @@ def constraint_key
:scoped_admins
when /^proposal_custom_field_/
:proposal_custom_fields
when /^proposal_private_custom_field_/
:proposal_private_custom_fields
else
key
end
Expand Down
Loading

0 comments on commit 4045f80

Please sign in to comment.