diff --git a/CHANGELOG.md b/CHANGELOG.md
index 768ef8bf..24d0fb01 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,9 @@ Following Semantic Versioning 2.
## next version:
+## Version 0.0.12 (MINOR)
+- Add card images to Challenges.
+
## Version 0.0.11 (MINOR)
- Fix order filter in Challenges, Solutions and Problems.
diff --git a/Gemfile.lock b/Gemfile.lock
index 13e39fe9..99937f62 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -209,7 +209,7 @@ GIT
PATH
remote: .
specs:
- decidim-challenges (0.0.10)
+ decidim-challenges (0.0.12)
decidim-core (~> 0.24.2)
GEM
@@ -852,4 +852,4 @@ RUBY VERSION
ruby 2.7.5p203
BUNDLED WITH
- 2.2.16
+ 2.3.4
diff --git a/app/cells/decidim/challenges/challenge_m/show.erb b/app/cells/decidim/challenges/challenge_m/show.erb
index 1cf6ee7c..ab1f3d48 100644
--- a/app/cells/decidim/challenges/challenge_m/show.erb
+++ b/app/cells/decidim/challenges/challenge_m/show.erb
@@ -1,4 +1,9 @@
+ <% if resource_image_path.present? %>
+ <%= link_to resource_path do %>
+ <%= image_tag resource_image_path, class: "card__image", alt: title %>
+ <% end %>
+ <% end %>
-
\ No newline at end of file
+
diff --git a/app/cells/decidim/challenges/challenge_m_cell.rb b/app/cells/decidim/challenges/challenge_m_cell.rb
index c324f6ca..324bc653 100644
--- a/app/cells/decidim/challenges/challenge_m_cell.rb
+++ b/app/cells/decidim/challenges/challenge_m_cell.rb
@@ -51,6 +51,14 @@ def resource_state
def current_organization
current_organization
end
+
+ def has_image?
+ @has_image ||= model.component.settings.allow_card_image && model.card_image.present?
+ end
+
+ def resource_image_path
+ @resource_image_path ||= has_image? ? model.card_image.url : nil
+ end
end
end
end
diff --git a/app/commands/decidim/challenges/admin/create_challenge.rb b/app/commands/decidim/challenges/admin/create_challenge.rb
index dd38b301..e7c052f1 100644
--- a/app/commands/decidim/challenges/admin/create_challenge.rb
+++ b/app/commands/decidim/challenges/admin/create_challenge.rb
@@ -51,6 +51,7 @@ def create_challenge!
coordinating_entities: form.coordinating_entities,
collaborating_entities: form.collaborating_entities,
questionnaire: Decidim::Forms::Questionnaire.new,
+ card_image: form.card_image,
}
@challenge = Decidim.traceability.create!(
diff --git a/app/commands/decidim/challenges/admin/update_challenge.rb b/app/commands/decidim/challenges/admin/update_challenge.rb
index ae258b24..38b77d48 100644
--- a/app/commands/decidim/challenges/admin/update_challenge.rb
+++ b/app/commands/decidim/challenges/admin/update_challenge.rb
@@ -60,6 +60,7 @@ def attributes
end_date: form.end_date,
coordinating_entities: form.coordinating_entities,
collaborating_entities: form.collaborating_entities,
+ card_image: form.card_image,
}
end
end
diff --git a/app/forms/decidim/challenges/admin/challenges_form.rb b/app/forms/decidim/challenges/admin/challenges_form.rb
index d1d8d783..cb51ba56 100644
--- a/app/forms/decidim/challenges/admin/challenges_form.rb
+++ b/app/forms/decidim/challenges/admin/challenges_form.rb
@@ -8,6 +8,7 @@ module Admin
class ChallengesForm < Decidim::Form
include TranslatableAttributes
include Decidim::Sdgs::SdgsHelper
+ include Decidim::HasUploadValidations
mimic :challenge
@@ -27,6 +28,9 @@ class ChallengesForm < Decidim::Form
attribute :coordinating_entities, String
attribute :collaborating_entities, String
+ attribute :card_image
+ attribute :remove_card_image
+
validates :title, :local_description, :global_description, translatable_presence: true
validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
validate :valid_state
@@ -34,6 +38,8 @@ class ChallengesForm < Decidim::Form
validates :start_date, presence: true, date: { before_or_equal_to: :end_date }
validates :end_date, presence: true, date: { after_or_equal_to: :start_date }
+ validates :card_image, passthru: { to: Decidim::Challenges::Challenge }
+
alias organization current_organization
def select_states_collection
diff --git a/app/models/decidim/challenges/challenge.rb b/app/models/decidim/challenges/challenge.rb
index 2dc662bb..86474625 100644
--- a/app/models/decidim/challenges/challenge.rb
+++ b/app/models/decidim/challenges/challenge.rb
@@ -13,6 +13,7 @@ class Challenge < Decidim::ApplicationRecord
include Decidim::TranslatableAttributes
include Decidim::Forms::HasQuestionnaire
include Decidim::Randomable
+ include Decidim::HasUploadValidations
belongs_to :scope,
foreign_key: "decidim_scope_id",
@@ -33,6 +34,9 @@ class Challenge < Decidim::ApplicationRecord
component_manifest_name "challenges"
+ validates_upload :card_image
+ mount_uploader :card_image, Decidim::ImageUploader
+
scope :published, -> { where.not(published_at: nil) }
scope :in_proposal, -> { where(state: VALID_STATES.index(:proposal)) }
scope :in_execution, -> { where(state: VALID_STATES.index(:execution)) }
diff --git a/app/presenters/decidim/challenges/challenge_presenter.rb b/app/presenters/decidim/challenges/challenge_presenter.rb
index 8696cd27..6136d9ff 100644
--- a/app/presenters/decidim/challenges/challenge_presenter.rb
+++ b/app/presenters/decidim/challenges/challenge_presenter.rb
@@ -11,6 +11,8 @@ class ChallengePresenter < SimpleDelegator
include Decidim::SanitizeHelper
include Decidim::TranslatableAttributes
+ delegate :url, to: :card_image, prefix: true
+
def challenge
__getobj__
end
@@ -77,6 +79,12 @@ def global_description(links: false, extras: true, strip_tags: false)
text
end
+ def card_image_url
+ return if challenge.card_image.blank?
+
+ URI.join(decidim.root_url(host: challenge.organization.host), challenge.card_image_url).to_s
+ end
+
delegate :count, to: :versions, prefix: true
def resource_manifest
diff --git a/app/views/decidim/challenges/admin/challenges/_form.html.erb b/app/views/decidim/challenges/admin/challenges/_form.html.erb
index 610cc100..5a37230a 100644
--- a/app/views/decidim/challenges/admin/challenges/_form.html.erb
+++ b/app/views/decidim/challenges/admin/challenges/_form.html.erb
@@ -51,6 +51,20 @@
+ <% if component_settings.allow_card_image? %>
+
+
<%= t(".images") %>
+
+
+
+
+
+ <%= form.upload :card_image %>
+
+
+
+ <% end %>
+
<%= t(".duration") %>
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index 6a0525c6..8a4ad436 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -78,6 +78,7 @@ ca:
update: Actualitza
form:
duration: Durada
+ images: Imatges
select_states: Selecciona l'estat
new:
create: Crea
@@ -171,6 +172,7 @@ ca:
name: Reptes
settings:
global:
+ allow_card_image: Permetre targeta amb imatge
announcement: Anunci
hide_filters: Amagar filtres
step:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 5df7efd6..389ac3f0 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -77,6 +77,7 @@ en:
update: Update
form:
duration: Duration
+ images: Images
select_states: Select state
new:
create: New
@@ -175,6 +176,7 @@ en:
name: Challenges
settings:
global:
+ allow_card_image: Allow card image
announcement: Announcement
hide_filters: Hide filters
problems:
diff --git a/config/locales/es.yml b/config/locales/es.yml
index ea55e5b5..a0807b48 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -77,6 +77,7 @@ es:
update: Actualiza
form:
duration: Durada
+ images: Imágenes
select_states: Selecciona estado
new:
create: Crea
@@ -168,6 +169,7 @@ es:
name: Retos
settings:
global:
+ allow_card_image: Habilitar imagen en tarjetas
announcement: Anuncio
hide_filters: Ocultar filtros
problems:
diff --git a/db/migrate/20220407110503_add_card_image_to_challenges.rb b/db/migrate/20220407110503_add_card_image_to_challenges.rb
new file mode 100644
index 00000000..fed728c9
--- /dev/null
+++ b/db/migrate/20220407110503_add_card_image_to_challenges.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddCardImageToChallenges < ActiveRecord::Migration[5.2]
+ def change
+ add_column :decidim_challenges_challenges, :card_image, :string
+ end
+end
diff --git a/lib/decidim/challenges/component.rb b/lib/decidim/challenges/component.rb
index c80ef262..66864ad3 100644
--- a/lib/decidim/challenges/component.rb
+++ b/lib/decidim/challenges/component.rb
@@ -29,6 +29,7 @@
# Available types: :integer, :boolean
settings.attribute :announcement, type: :text, translated: true, editor: true
settings.attribute :hide_filters, type: :boolean, default: false
+ settings.attribute :allow_card_image, type: :boolean, default: false
end
component.settings(:step) do |settings|
diff --git a/lib/decidim/challenges/test/factories.rb b/lib/decidim/challenges/test/factories.rb
index 5f80f62f..578d7417 100644
--- a/lib/decidim/challenges/test/factories.rb
+++ b/lib/decidim/challenges/test/factories.rb
@@ -7,6 +7,14 @@
name { Decidim::Components::Namer.new(participatory_space.organization.available_locales, :challenges).i18n_name }
manifest_name { :challenges }
participatory_space { create(:participatory_process, :with_steps) }
+
+ trait :with_card_image_allowed do
+ settings do
+ {
+ allow_card_image: true,
+ }
+ end
+ end
end
factory :challenge, traits: [:proposal, :execution, :finished], class: "Decidim::Challenges::Challenge" do
@@ -38,6 +46,10 @@
trait :with_survey_enabled do
survey_enabled { true }
end
+
+ trait :with_card_image do
+ card_image { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
+ end
end
factory :survey, class: "Decidim::Challenges::Survey" do
diff --git a/lib/decidim/challenges/version.rb b/lib/decidim/challenges/version.rb
index 78730711..e0ad8954 100644
--- a/lib/decidim/challenges/version.rb
+++ b/lib/decidim/challenges/version.rb
@@ -4,7 +4,7 @@ module Decidim
# This holds the decidim-meetings version.
module Challenges
def self.version
- "0.0.11"
+ "0.0.12"
end
def self.decidim_version
diff --git a/spec/cells/decidim/challenges/challenge_m_cell_spec.rb b/spec/cells/decidim/challenges/challenge_m_cell_spec.rb
index 45fe23bb..6dd18fb8 100644
--- a/spec/cells/decidim/challenges/challenge_m_cell_spec.rb
+++ b/spec/cells/decidim/challenges/challenge_m_cell_spec.rb
@@ -10,7 +10,8 @@ module Decidim::Challenges
Decidim::Faker::Localized.sentence(3)
end
- let!(:challenge) { create :challenge, global_description: description }
+ let(:component) { create(:challenges_component, :with_card_image_allowed) }
+ let!(:challenge) { create :challenge, :with_card_image, global_description: description, component: component }
let(:model) { challenge }
let(:cell_html) { cell("decidim/challenges/challenge_m", challenge, context: { show_space: show_space }).call }
let!(:challenge_description) { translated(challenge.global_description) }
@@ -18,6 +19,7 @@ module Decidim::Challenges
context "when rendering" do
let(:show_space) { false }
+ let!(:card_image) { create(:attachment, :with_image, attached_to: challenge) }
it "renders the card" do
expect(cell_html).to have_css(".card--challenge")
@@ -30,6 +32,10 @@ module Decidim::Challenges
it "renders the challenge title" do
expect(cell_html).to have_content(challenge_title)
end
+
+ it "renders the challenge image card" do
+ expect(cell_html).to have_css(".card__image")
+ end
end
end
end
diff --git a/spec/commands/decidim/challenges/admin/create_challenge_spec.rb b/spec/commands/decidim/challenges/admin/create_challenge_spec.rb
index 4859ac49..197946e4 100644
--- a/spec/commands/decidim/challenges/admin/create_challenge_spec.rb
+++ b/spec/commands/decidim/challenges/admin/create_challenge_spec.rb
@@ -20,6 +20,7 @@ module Admin
let(:end_date) { 2.days.from_now + 4.hours }
let(:collaborating_entities) { "collaborating_entities" }
let(:coordinating_entities) { "coordinating_entities" }
+ let(:card_image) { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
let(:form) do
instance_double(
Decidim::Challenges::Admin::ChallengesForm,
@@ -37,7 +38,8 @@ module Admin
collaborating_entities: collaborating_entities,
current_user: current_user,
current_organization: organization,
- current_component: current_component
+ current_component: current_component,
+ card_image: card_image
)
end
let(:invalid) { false }
diff --git a/spec/commands/decidim/challenges/admin/update_challenge_spec.rb b/spec/commands/decidim/challenges/admin/update_challenge_spec.rb
index 123362e9..2fc6d1ee 100644
--- a/spec/commands/decidim/challenges/admin/update_challenge_spec.rb
+++ b/spec/commands/decidim/challenges/admin/update_challenge_spec.rb
@@ -21,6 +21,7 @@ module Admin
let(:end_date) { 2.days.from_now + 4.hours }
let(:collaborating_entities) { "collaborating_entities" }
let(:coordinating_entities) { "coordinating_entities" }
+ let(:card_image) { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
let(:form) do
instance_double(
Decidim::Challenges::Admin::ChallengesForm,
@@ -38,7 +39,8 @@ module Admin
collaborating_entities: collaborating_entities,
current_user: current_user,
current_organization: organization,
- current_component: current_component
+ current_component: current_component,
+ card_image: card_image
)
end
let(:invalid) { false }
diff --git a/spec/controllers/decidim/challenges/admin/challenges_controller_spec.rb b/spec/controllers/decidim/challenges/admin/challenges_controller_spec.rb
index 6d03e859..788747ac 100644
--- a/spec/controllers/decidim/challenges/admin/challenges_controller_spec.rb
+++ b/spec/controllers/decidim/challenges/admin/challenges_controller_spec.rb
@@ -34,6 +34,7 @@
let(:collaborating_entities) { "collaborating_entities" }
let(:coordinating_entities) { "coordinating_entities" }
let(:state) { 2 }
+ let(:card_image) { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
let(:params) do
{
challenge: {
@@ -47,6 +48,7 @@
end_date: end_date,
collaborating_entities: collaborating_entities,
coordinating_entities: coordinating_entities,
+ card_image: card_image,
},
component_id: component,
scope: scope,
diff --git a/spec/forms/decidim/challenges/admin/challenges_form_spec.rb b/spec/forms/decidim/challenges/admin/challenges_form_spec.rb
index becdd5de..bdc9e71c 100644
--- a/spec/forms/decidim/challenges/admin/challenges_form_spec.rb
+++ b/spec/forms/decidim/challenges/admin/challenges_form_spec.rb
@@ -38,6 +38,7 @@ module Admin
let(:end_date) { 2.days.from_now + 4.hours }
let(:collaborating_entities) { "collaborating_entities" }
let(:coordinating_entities) { "coordinating_entities" }
+ let(:card_image) { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
let(:attributes) do
{
"title" => title,
@@ -51,6 +52,7 @@ module Admin
"collaborating_entities" => collaborating_entities,
"coordinating_entities" => coordinating_entities,
"scope" => scope,
+ "card_image" => card_image,
}
end
diff --git a/spec/system/decidim/challenges/challenges_spec.rb b/spec/system/decidim/challenges/challenges_spec.rb
index 05c0562b..1412cf8f 100644
--- a/spec/system/decidim/challenges/challenges_spec.rb
+++ b/spec/system/decidim/challenges/challenges_spec.rb
@@ -77,5 +77,25 @@
expect(page).to have_selector("#challenges .card-grid .column:last-child", text: older_challenge.title[:en])
end
end
+
+ context "when card images are allow" do
+ let!(:challenge_with_card_image) { create(:challenge, :with_card_image, component: component) }
+ let!(:challenge) { create(:challenge, component: component) }
+
+ context "when list all challenges" do
+ before do
+ component.update(settings: { allow_card_image: true })
+ visit_component
+ end
+
+ it "show cards with images" do
+ expect(page).to have_selector(".card--challenge", count: 2)
+ expect(page).to have_selector(".card__image", count: 1)
+
+ expect(page).to have_content(translated(challenge_with_card_image.title))
+ expect(page).to have_content(translated(challenge.title))
+ end
+ end
+ end
end
end