Merge branch 'master' into aperez-admin-question-videos

This commit is contained in:
Raimond Garcia
2017-10-06 01:12:22 +02:00
committed by GitHub
42 changed files with 460 additions and 277 deletions

View File

@@ -149,6 +149,7 @@ $sidebar-active: #f4fcd0;
} }
table { table {
.break { .break {
word-break: break-word; word-break: break-word;
} }

View File

@@ -1591,6 +1591,10 @@
.orbit-container { .orbit-container {
height: 100% !important; height: 100% !important;
max-height: none !important; max-height: none !important;
li {
margin-bottom: 0 !important;
}
} }
.orbit-slide { .orbit-slide {

View File

@@ -0,0 +1,32 @@
class Admin::Poll::Questions::Answers::ImagesController < Admin::Poll::BaseController
before_action :load_answer
def index
end
def new
@answer = ::Poll::Question::Answer.find(params[:answer_id])
end
def create
@answer = ::Poll::Question::Answer.find(params[:answer_id])
@answer.attributes = images_params
if @answer.save
redirect_to admin_answer_images_path(@answer),
notice: "Image uploaded successfully"
else
render :new
end
end
private
def images_params
params.permit(images_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
end
def load_answer
@answer = ::Poll::Question::Answer.find(params[:answer_id])
end
end

View File

@@ -1,7 +1,6 @@
class Admin::Poll::ShiftsController < Admin::Poll::BaseController class Admin::Poll::ShiftsController < Admin::Poll::BaseController
before_action :load_booth before_action :load_booth
before_action :load_polls
before_action :load_officer before_action :load_officer
def new def new
@@ -39,10 +38,6 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
@booth = ::Poll::Booth.find(params[:booth_id]) @booth = ::Poll::Booth.find(params[:booth_id])
end end
def load_polls
@polls = ::Poll.current_or_incoming
end
def load_shifts def load_shifts
@shifts = @booth.shifts @shifts = @booth.shifts
end end

View File

@@ -3,7 +3,8 @@ class Officing::VotersController < Officing::BaseController
def new def new
@user = User.find(params[:id]) @user = User.find(params[:id])
@polls = Poll.answerable_by(@user) booths = current_user.poll_officer.shifts.current.vote_collection.pluck(:booth_id).uniq
@polls = Poll.answerable_by(@user).where(id: Poll::BoothAssignment.where(booth: booths).pluck(:poll_id).uniq)
end end
def create def create

View File

@@ -25,7 +25,7 @@ module AdminHelper
end end
def menu_polls? def menu_polls?
%w[polls questions officers booths officer_assignments booth_assignments recounts results shifts].include? controller_name %w[polls questions officers booths officer_assignments booth_assignments recounts results shifts questions answers].include? controller_name
end end
def menu_profiles? def menu_profiles?

View File

@@ -0,0 +1,12 @@
module Galleryable
extend ActiveSupport::Concern
included do
has_many :images, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true, update_only: true
def image_url(style)
image.attachment.url(style) if image && image.attachment.exists?
end
end
end

View File

@@ -19,7 +19,9 @@ class DirectUpload
if @resource_type.present? && @resource_relation.present? && (@attachment.present? || @cached_attachment.present?) if @resource_type.present? && @resource_relation.present? && (@attachment.present? || @cached_attachment.present?)
@resource = @resource_type.constantize.find_or_initialize_by(id: @resource_id) @resource = @resource_type.constantize.find_or_initialize_by(id: @resource_id)
if @resource.class.reflections[@resource_relation].macro == :has_one if @resource.respond_to?(:images)
@relation = @resource.images.send("build", relation_attributtes)
elsif @resource.class.reflections[@resource_relation].macro == :has_one
@relation = @resource.send("build_#{resource_relation}", relation_attributtes) @relation = @resource.send("build_#{resource_relation}", relation_attributtes)
else else
@relation = @resource.send(@resource_relation).build(relation_attributtes) @relation = @resource.send(@resource_relation).build(relation_attributtes)

View File

@@ -2,6 +2,7 @@ class Poll
class Officer < ActiveRecord::Base class Officer < ActiveRecord::Base
belongs_to :user belongs_to :user
has_many :officer_assignments, class_name: "Poll::OfficerAssignment" has_many :officer_assignments, class_name: "Poll::OfficerAssignment"
has_many :shifts, class_name: "Poll::Shift"
has_many :failed_census_calls, foreign_key: :poll_officer_id has_many :failed_census_calls, foreign_key: :poll_officer_id
validates :user_id, presence: true, uniqueness: true validates :user_id, presence: true, uniqueness: true

View File

@@ -1,4 +1,6 @@
class Poll::Question::Answer < ActiveRecord::Base class Poll::Question::Answer < ActiveRecord::Base
include Galleryable
belongs_to :question, class_name: 'Poll::Question', foreign_key: 'question_id' belongs_to :question, class_name: 'Poll::Question', foreign_key: 'question_id'
has_many :videos, class_name: 'Poll::Question::Answer::Video' has_many :videos, class_name: 'Poll::Question::Answer::Video'

View File

@@ -10,6 +10,10 @@ class Poll
enum task: { vote_collection: 0, recount_scrutiny: 1 } enum task: { vote_collection: 0, recount_scrutiny: 1 }
scope :vote_collection, -> { where(task: 'vote_collection') }
scope :recount_scrutiny, -> { where(task: 'recount_scrutiny') }
scope :current, -> { where(date: Date.current) }
before_create :persist_data before_create :persist_data
after_create :create_officer_assignments after_create :create_officer_assignments
before_destroy :destroy_officer_assignments before_destroy :destroy_officer_assignments

View File

@@ -60,12 +60,14 @@
<span class="icon-checkmark-circle"></span> <span class="icon-checkmark-circle"></span>
<strong><%= t("admin.menu.title_polls") %></strong> <strong><%= t("admin.menu.title_polls") %></strong>
</a> </a>
<ul id="polls_menu" <%= "class=is-active" if menu_polls? && controller.class.parent == Admin::Poll %>> <ul id="polls_menu" <%= "class=is-active" if menu_polls? || controller.class.parent == Admin::Poll::Questions::Answers %>>
<li <%= "class=active" if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>> <li <%= "class=active" if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>>
<%= link_to t('admin.menu.polls'), admin_polls_path %> <%= link_to t('admin.menu.polls'), admin_polls_path %>
</li> </li>
<li <%= "class=active" if current_page?(admin_questions_path) %>> <li <%= "class=active" if controller_name == "questions" ||
controller_name == "answers" ||
controller.class.parent == Admin::Poll::Questions::Answers %>>
<%= link_to t("admin.menu.poll_questions"), admin_questions_path %> <%= link_to t("admin.menu.poll_questions"), admin_questions_path %>
</li> </li>
@@ -158,12 +160,14 @@
<span class="icon-settings"></span> <span class="icon-settings"></span>
<strong><%= t("admin.menu.title_site_customization") %></strong> <strong><%= t("admin.menu.title_site_customization") %></strong>
</a> </a>
<ul <%= "class=is-active" if menu_customization? %>> <ul <%= "class=is-active" if menu_customization? &&
controller.class.parent != Admin::Poll::Questions::Answers %>>
<li <%= "class=active" if controller_name == "pages" %>> <li <%= "class=active" if controller_name == "pages" %>>
<%= link_to t("admin.menu.site_customization.pages"), admin_site_customization_pages_path %> <%= link_to t("admin.menu.site_customization.pages"), admin_site_customization_pages_path %>
</li> </li>
<li <%= "class=active" if controller_name == "images" %>> <li <%= "class=active" if controller_name == "images" &&
controller.class.parent != Admin::Poll::Questions::Answers %>>
<%= link_to t("admin.menu.site_customization.images"), admin_site_customization_images_path %> <%= link_to t("admin.menu.site_customization.images"), admin_site_customization_images_path %>
</li> </li>

View File

@@ -4,9 +4,8 @@
<%= f.hidden_field :proposal_id %> <%= f.hidden_field :proposal_id %>
<div class="row">
<div class="small-12 column"> <div class="small-12">
<div class="small-12 medium-6 large-4"> <div class="small-12 medium-6 large-4">
<%= f.select :poll_id, <%= f.select :poll_id,
options_for_select(Poll.pluck(:name, :id)), options_for_select(Poll.pluck(:name, :id)),
@@ -27,12 +26,9 @@
aria: {describedby: "video-url-help-text"} %> aria: {describedby: "video-url-help-text"} %>
</div> </div>
<div class="row"> <div class="small-12 medium-6 large-4 margin-top">
<div class="actions small-12 medium-4 column margin-top">
<%= f.submit(class: "button expanded", value: t("shared.save")) %> <%= f.submit(class: "button expanded", value: t("shared.save")) %>
</div> </div>
</div> </div>
</div>
</div>
<% end %> <% end %>

View File

@@ -4,21 +4,19 @@
<%= f.hidden_field :question_id, value: @question.id %> <%= f.hidden_field :question_id, value: @question.id %>
<div class="row"> <%= f.label :title, t('admin.questions.new.form.title') %>
<div class="small-12 column"> <%= f.text_field :title, label: false %>
<%= f.text_field :title %>
<div class="ckeditor"> <div class="ckeditor">
<%= f.label :description, t('admin.questions.new.form.description') %>
<%= f.cktext_area :description, <%= f.cktext_area :description,
maxlength: Poll::Question.description_max_length, maxlength: Poll::Question.description_max_length,
ckeditor: { language: I18n.locale } %> ckeditor: { language: I18n.locale },
label: false %>
</div> </div>
<div class="row"> <div class="small-12 medium-6 large-4">
<div class="actions small-12 medium-4 column margin-top">
<%= f.submit(class: "button expanded", value: t("shared.save")) %> <%= f.submit(class: "button expanded", value: t("shared.save")) %>
</div> </div>
</div>
</div>
</div>
<% end %> <% end %>

View File

@@ -0,0 +1,16 @@
<%= back_link_to admin_question_path(@answer.question) %>
<%= link_to t("admin.questions.answers.images.add_image"),
new_admin_answer_image_path(@answer),
class: "button hollow float-right" %>
<ul class="breadcrumbs margin-top">
<li><%= @answer.question.title %></li>
<li><%= @answer.title %></li>
</ul>
<% @answer.images.each do |image| %>
<div class="small-12 medium-4 column end">
<%= render_image(image, :large, true) if image.present? %>
</div>
<% end %>

View File

@@ -0,0 +1,13 @@
<div class="poll-question-form">
<%= form_for(Poll::Question::Answer.new,
url: admin_answer_images_path(@answer),
method: :post) do |f| %>
<%= render 'shared/errors', resource: @answer %>
<div class="images">
<%= render 'images/nested_image', imageable: @answer, f: f, image_fields: :images %>
</div>
<%= f.submit t("admin.questions.answers.images.save_image"), class: "button success" %>
<% end %>
</div>

View File

@@ -1,5 +1,10 @@
<%= back_link_to %> <%= back_link_to %>
<ul class="breadcrumbs margin-top">
<li><%= @question.title %></li>
<li><%= t('admin.answers.new.title') %></li>
</ul>
<h2><%= t('admin.answers.new.title') %></h2> <h2><%= t('admin.answers.new.title') %></h2>
<div class="poll-question-answer-form"> <div class="poll-question-answer-form">

View File

@@ -1,6 +1,6 @@
<%= back_link_to %> <%= back_link_to %>
<h2><%= t("admin.questions.edit.title") %></h2> <h2 class="margin-top"><%= t("admin.questions.edit.title") %></h2>
<div class="poll-question-form"> <div class="poll-question-form">
<%= render "form", form_url: admin_question_path(@question) %> <%= render "form", form_url: admin_question_path(@question) %>

View File

@@ -3,11 +3,9 @@
<%= link_to t('admin.questions.index.create'), new_admin_question_path, <%= link_to t('admin.questions.index.create'), new_admin_question_path,
class: "button success float-right" %> class: "button success float-right" %>
<div class="row"> <div class="small-12 medium-6">
<div class="small-12 medium-6 column">
<%= render 'search' %> <%= render 'search' %>
</div> </div>
</div>
<div class="tabs-content" data-tabs-content="questions-tabs"> <div class="tabs-content" data-tabs-content="questions-tabs">
<%= render "filter_subnav" %> <%= render "filter_subnav" %>

View File

@@ -1,6 +1,6 @@
<%= back_link_to %> <%= back_link_to %>
<h2><%= t("admin.questions.new.title") %></h2> <h2 class="margin-top"><%= t("admin.questions.new.title") %></h2>
<div class="poll-question-form"> <div class="poll-question-form">
<%= render "form", form_url: admin_questions_path %> <%= render "form", form_url: admin_questions_path %>

View File

@@ -5,10 +5,19 @@
<div class="clear"></div> <div class="clear"></div>
<div class="row"> <div class="small-12 medium-6">
<div class="small-12 medium-9 column"> <div class="callout highlight">
<p>
<strong><%= t("admin.questions.show.title") %></strong> <strong><%= t("admin.questions.show.title") %></strong>
<h1><%= @question.title %></h1> <br>
<%= @question.title %>
</p>
<p>
<strong><%= t("admin.questions.show.author") %></strong>
<br>
<%= link_to @question.author.name, user_path(@question.author) %>
</p>
<% if @question.proposal.present? %> <% if @question.proposal.present? %>
<p> <p>
@@ -17,20 +26,13 @@
<%= link_to @question.proposal.title, proposal_path(@question.proposal) %> <%= link_to @question.proposal.title, proposal_path(@question.proposal) %>
</p> </p>
<% end %> <% end %>
</div>
</div>
<p> <table class="margin-top">
<strong><%= t("admin.questions.show.author") %></strong>
<br>
<%= link_to @question.author.name, user_path(@question.author) %>
</p>
<table>
<thead>
<tr> <tr>
<th> <th colspan="3" scope="col" class="with-button">
<%= t('admin.questions.show.valid_answers') %> <%= t('admin.questions.show.valid_answers') %>
</th>
<th colspan="2">
<%= link_to t("admin.questions.show.add_answer"), <%= link_to t("admin.questions.show.add_answer"),
new_admin_question_answer_path(@question), new_admin_question_answer_path(@question),
class: "button hollow float-right" %> class: "button hollow float-right" %>
@@ -39,22 +41,24 @@
<tr> <tr>
<th><%= t("admin.questions.show.answers.title") %></th> <th><%= t("admin.questions.show.answers.title") %></th>
<th><%= t("admin.questions.show.answers.description") %></th> <th class="medium-7"><%= t("admin.questions.show.answers.description") %></th>
<th class="text-center"><%= t("admin.questions.show.answers.images") %></th>
<th><%= t("admin.questions.show.answers.videos") %></th> <th><%= t("admin.questions.show.answers.videos") %></th>
</tr> </tr>
</thead>
<tbody>
<% @question.question_answers.each do |answer| %> <% @question.question_answers.each do |answer| %>
<tr id="<%= dom_id(answer) %>" class="poll_question_answer"> <tr id="<%= dom_id(answer) %>" class="poll_question_answer">
<td><%= answer.title %></td> <td><%= answer.title %></td>
<td><%= answer.description %></td> <td><%= answer.description %></td>
<td class="text-center">
(<%= answer.images.count %>)<br>
<%= link_to t("admin.questions.show.answers.images_list"),
admin_answer_images_path(answer) %></td>
<td><%= link_to t("admin.questions.show.answers.video_list", <td><%= link_to t("admin.questions.show.answers.video_list",
count: answer.videos.count), count: answer.videos.count),
admin_answer_videos_path(answer) %></td> admin_answer_videos_path(answer) %></td>
</tr> </tr>
<% end %> <% end %>
</tbody>
</table> </table>
<% if @question.video_url.present? %> <% if @question.video_url.present? %>
@@ -72,5 +76,3 @@
<a href="<%= @question.documents.first.attachment.url %>"><%= @question.documents.first.title %></a> <a href="<%= @question.documents.first.attachment.url %>"><%= @question.documents.first.title %></a>
</p> </p>
<% end %> <% end %>
</div>
</div>

View File

@@ -24,12 +24,12 @@
<div class="small-12 medium-3 column"> <div class="small-12 medium-3 column">
<label><%= t("admin.poll_shifts.new.date") %></label> <label><%= t("admin.poll_shifts.new.date") %></label>
<%= select 'shift[date]', 'vote_collection_date', <%= select 'shift[date]', 'vote_collection_date',
options_for_select(shift_vote_collection_dates(@polls)), options_for_select(shift_vote_collection_dates(@booth.polls)),
{ prompt: t("admin.poll_shifts.new.select_date"), { prompt: t("admin.poll_shifts.new.select_date"),
label: false }, label: false },
class: 'js-shift-vote-collection-dates' %> class: 'js-shift-vote-collection-dates' %>
<%= select 'shift[date]', 'recount_scrutiny_date', <%= select 'shift[date]', 'recount_scrutiny_date',
options_for_select(shift_recount_scrutiny_dates(@polls)), options_for_select(shift_recount_scrutiny_dates(@booth.polls)),
{ prompt: t("admin.poll_shifts.new.select_date"), { prompt: t("admin.poll_shifts.new.select_date"),
label: false }, label: false },
class: 'js-shift-recount-scrutiny-dates', class: 'js-shift-recount-scrutiny-dates',

View File

@@ -2,7 +2,6 @@
<div> <div>
<%= f.label :image, t("images.form.admin_title") %> <%= f.label :image, t("images.form.admin_title") %>
<%= link_to_add_association t('images.form.add_new_image'), f, :image, <%= link_to_add_association t('images.form.add_new_image'), f, :image,
force_non_association_create: true, force_non_association_create: true,
partial: "images/image_fields", partial: "images/image_fields",
@@ -16,6 +15,8 @@
association_insertion_method: "append" association_insertion_method: "append"
} %> } %>
<%= render_image(f.object.image, :thumb, false) if f.object.image %>
<div id="nested-image"> <div id="nested-image">
<%= f.fields_for :image do |image_builder| %> <%= f.fields_for :image do |image_builder| %>
@@ -26,17 +27,11 @@
<%= image_builder.text_field :title, placeholder: t("images.form.title_placeholder"), label: "#{t("images.form.admin_alt_text")}" %> <%= image_builder.text_field :title, placeholder: t("images.form.title_placeholder"), label: "#{t("images.form.admin_alt_text")}" %>
<div class="attachment-actions"> <div class="attachment-actions">
<div class="small-12 column action-add attachment-errors image-attachment"> <div class="small-12 column action-add attachment-errors image-attachment">
<%= render_image_attachment(image_builder, imageable, image_builder.object) %> <%= render_image_attachment(image_builder, imageable, image_builder.object) %>
</div> </div>
</div> </div>
<div class="small-12 column">
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
</div>
</div> </div>
<% end %> <% end %>

View File

@@ -1,17 +1,20 @@
<%= f.label :image, t("images.form.title") %> <% image_fields ||= :image %>
<%= f.label image_fields, t("images.form.title") %>
<p class="help-text"><%= imageables_note(imageable) %></p> <p class="help-text"><%= imageables_note(imageable) %></p>
<div id="nested-image"> <div id="nested-image">
<%= f.fields_for :image do |image_builder| %> <%= f.fields_for image_fields do |image_builder| %>
<%= render 'images/image_fields', f: image_builder, imageable: imageable %> <%= render 'images/image_fields', f: image_builder, imageable: imageable %>
<% end %> <% end %>
</div> </div>
<%= link_to_add_association t('images.form.add_new_image'), f, :image, <%= link_to_add_association t('images.form.add_new_image'), f, image_fields,
force_non_association_create: true, force_non_association_create: true,
partial: "images/image_fields", partial: "images/image_fields",
id: "new_image_link", id: "new_image_link",
class: "button hollow #{"hide" if imageable.image.present?}", class: "button hollow
#{"hide" if image_fields == :image && imageable.image.present?}",
render_options: { render_options: {
locals: { imageable: imageable } locals: { imageable: imageable }
}, },

View File

@@ -1,5 +1,5 @@
<div class="orbit margin-bottom" role="region" aria-label="Answer 1" data-orbit data-auto-play="false"> <div class="orbit margin-bottom" role="region" aria-label="<%= answer.title %>" data-orbit data-auto-play="false">
<a data-toggle="answer_1" class="zoom-link show-for-medium-up"> <a data-toggle="answer_<%= answer.id %>" class="zoom-link show-for-medium-up">
<span class="icon-search-plus"></span> <span class="icon-search-plus"></span>
<span class="show-for-sr"><%= t("polls.show.zoom_plus") %></span> <span class="show-for-sr"><%= t("polls.show.zoom_plus") %></span>
</a> </a>
@@ -15,32 +15,25 @@
<span class="show-for-sr"><%= t("shared.orbit.next_slide") %></span>&#9654;&#xFE0E; <span class="show-for-sr"><%= t("shared.orbit.next_slide") %></span>&#9654;&#xFE0E;
</button> </button>
</li> </li>
<!-- each image do -->
<li class="is-active orbit-slide"> <% answer.images.each_with_index do |image, index| %>
<%= link_to "/assets/example_vertical.jpg", target: "_blank" do %> <li class="orbit-slide <%= active_class(index) %>">
<%= image_tag "example_horizontal.jpg", class: "orbit-image" %> <%= link_to image.attachment.url(:original), target: "_blank" do %>
<%= image_tag image.attachment.url(:medium),
class: "orbit-image",
alt: image.title %>
<% end %> <% end %>
<!-- replace this with image title --> <span class="orbit-caption"><%= image.title %></span>
<span class="orbit-caption">Image title 1</span>
<!-- /. replace this with image title -->
</li> </li>
<!-- end -->
<li class="orbit-slide">
<%= link_to "/assets/example_vertical.jpg", target: "_blank" do %>
<%= image_tag "example_vertical.jpg", class: "orbit-image" %>
<% end %> <% end %>
<span class="orbit-caption">Image title 2</span>
</li>
</ul> </ul>
<nav class="orbit-bullets"> <nav class="orbit-bullets">
<button class="is-active" data-slide="0"> <% answer.images.each_with_index do |image, index| %>
<!-- replace this with image title --> <button class="<%= active_class(index) %>" data-slide="<%= index %>">
<span class="show-for-sr">Image title 1</span> <span class="show-for-sr"><%= image.title %></span>
<!-- /. replace this with image title -->
</button>
<button data-slide="1">
<span class="show-for-sr">Image title 2</span>
</button> </button>
<% end %>
</nav> </nav>
</div> </div>

View File

@@ -1,37 +1,9 @@
<% poll_group.each do |poll| %> <% poll_group.each do |poll| %>
<div class="poll with-image"> <div class="poll with-image">
<% if poll.answerable_by?(current_user) && poll.votable_by?(current_user) %> <% if user_signed_in? && !poll.votable_by?(current_user) %>
<%= link_to poll,
class: "icon-poll-answer can-answer",
title: t("polls.index.can_answer") do %>
<span class="show-for-sr">
<%= t("polls.index.can_answer") %>
</span>
<% end %>
<% elsif current_user.nil? %>
<%= link_to new_user_session_path,
class: "icon-poll-answer not-logged-in",
title: t("polls.index.cant_answer_not_logged_in") do %>
<span class="show-for-sr">
<%= t("polls.index.cant_answer_not_logged_in") %>
</span>
<% end %>
<% elsif current_user.unverified? %>
<%= link_to verification_path,
class: "icon-poll-answer unverified",
title: t("polls.index.cant_answer_verify") do %>
<span class="show-for-sr">
<%= t("polls.index.cant_answer_verify") %>
</span>
<% end %>
<% elsif !poll.votable_by?(current_user) %>
<div class="icon-poll-answer already-answer" title="<%= t("polls.index.already_answer") %>"> <div class="icon-poll-answer already-answer" title="<%= t("polls.index.already_answer") %>">
<span class="show-for-sr"><%= t("polls.index.already_answer") %></span> <span class="show-for-sr"><%= t("polls.index.already_answer") %></span>
</div> </div>
<% else %>
<div class="icon-poll-answer cant-answer" title="<%= t("polls.index.cant_answer") %>">
<span class="show-for-sr"><%= t("polls.index.cant_answer") %></span>
</div>
<% end %> <% end %>
<div class="row" data-equalizer> <div class="row" data-equalizer>
<div class="small-12 medium-3 column"> <div class="small-12 medium-3 column">

View File

@@ -62,27 +62,23 @@
<div class="expanded poll-more-info-answers"> <div class="expanded poll-more-info-answers">
<div class="row padding"> <div class="row padding">
<!-- EACH ANSWER DO --> <% @poll.questions.map(&:question_answers).flatten.each do |answer| %>
<div class="small-12 medium-6 column end" id="answer_1" data-toggler=".medium-6"> <div class="small-12 medium-6 column end" id="answer_<%= answer.id %>"
data-toggler=".medium-6">
<!-- REPLACE THIS WITH answer title --> <h3><%= answer.title %></h3>
<h3>Answer 1</h3>
<!-- /. REPLACE THIS WITH answer title -->
<!-- If Answer have images render this: <% if answer.images.any? %>
Maybe something like <%# render "gallery", gallery: answer.gallery %> --> <%= render "gallery", answer: answer %>
<%= render "gallery" %> <% end %>
<!-- If Answer have images render this -->
<!-- REPLACE THIS WITH answer description -->
<div class="margin-top"> <div class="margin-top">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> <%= safe_html_with_links simple_format(answer.description) %>
</div>
</div>
<% end %>
</div> </div>
<!-- /. REPLACE THIS WITH answer description -->
</div>
</div>
<!-- /. EACH ANSWER DO -->
</div> </div>
</div> </div>

View File

@@ -1,25 +1,28 @@
staging: staging:
deploy_to: "/var/www/consul" deploy_to: "/var/www/consul"
ssh_port: 21 ssh_port: 21
server: staging.consul.es server: "staging.consul.es"
user: xxxxx db_server: "postgre.consul.es"
full_app_name: consul user: "xxxxx"
server_name: staging.consul.es server_name: "staging.consul.es"
db_server: postgre.consul.es full_app_name: "consul"
preproduction: preproduction:
deploy_to: "/var/www/consul" deploy_to: "/var/www/consul"
ssh_port: 2222 ssh_port: 2222
server1: xxx.xxx.xxx.xxx server1: xxx.xxx.xxx.xxx
server2: xxx.xxx.xxx.xxx server2: xxx.xxx.xxx.xxx
user: xxxxx
full_app_name: consul
db_server: xxx.xxx.xxx.xxx db_server: xxx.xxx.xxx.xxx
user: xxxxx
server_name: pre.consul.es
full_app_name: "consul"
production: production:
deploy_to: "/var/www/consul" deploy_to: "/var/www/consul"
ssh_port: 2222 ssh_port: 22
server: xxx.xxx.xxx.xxx server1: xxx.xxx.xxx.xxx
user: xxxxx server2: xxx.xxx.xxx.xxx
full_app_name: consul db_server: xxx.xxx.xxx.xxx
user: "deploy"
server_name: "consul.es"
full_app_name: "consul"

View File

@@ -587,6 +587,13 @@ en:
new: new:
title: "Create Question" title: "Create Question"
poll_label: "Poll" poll_label: "Poll"
form:
title: Title
description: Description
answers:
images:
add_image: "Add image"
save_image: "Save image"
show: show:
proposal: Original proposal proposal: Original proposal
author: Author author: Author
@@ -600,6 +607,8 @@ en:
description: Description description: Description
videos: Videos videos: Videos
video_list: Video list (%{count}) video_list: Video list (%{count})
images: Images
images_list: Images list
answers: answers:
new: new:
title: New answer title: New answer

View File

@@ -180,6 +180,7 @@ en:
spending_proposal: Spending proposal spending_proposal: Spending proposal
budget/investment: Investment budget/investment: Investment
poll/shift: Shift poll/shift: Shift
poll/question/answer: Answer
user: Account user: Account
verification/sms: phone verification/sms: phone
signature_sheet: Signature sheet signature_sheet: Signature sheet
@@ -466,10 +467,6 @@ en:
no_geozone_restricted: "All city" no_geozone_restricted: "All city"
geozone_restricted: "Districts" geozone_restricted: "Districts"
geozone_info: "Can participate people in the Census of: " geozone_info: "Can participate people in the Census of: "
can_answer: "You can participate in this poll!"
cant_answer: "This poll is not available on your geozone"
cant_answer_not_logged_in: "You must sign in or sign up to participate"
cant_answer_verify: "You must verify your account in order to answer"
already_answer: "You already have participated in this poll" already_answer: "You already have participated in this poll"
section_header: section_header:
icon_alt: Voting icon icon_alt: Voting icon

View File

@@ -587,6 +587,13 @@ es:
new: new:
title: "Crear pregunta ciudadana" title: "Crear pregunta ciudadana"
poll_label: "Votación" poll_label: "Votación"
form:
title: Título
description: Descripción
answers:
images:
add_image: "Añadir imagen"
save_image: "Guardar imagen"
show: show:
proposal: Propuesta ciudadana original proposal: Propuesta ciudadana original
author: Autor author: Autor
@@ -601,6 +608,8 @@ es:
description: Descripción description: Descripción
videos: Vídeos videos: Vídeos
video_list: Lista de vídeos (%{count}) video_list: Lista de vídeos (%{count})
images: Imágenes
images_list: Lista de imágenes
answers: answers:
new: new:
title: "Nueva respuesta" title: "Nueva respuesta"

View File

@@ -180,6 +180,7 @@ es:
spending_proposal: la propuesta de gasto spending_proposal: la propuesta de gasto
budget/investment: la propuesta de inversión budget/investment: la propuesta de inversión
poll/shift: el turno poll/shift: el turno
poll/question/answer: la respuesta
user: la cuenta user: la cuenta
verification/sms: el teléfono verification/sms: el teléfono
signature_sheet: la hoja de firmas signature_sheet: la hoja de firmas
@@ -466,10 +467,6 @@ es:
no_geozone_restricted: "Toda la ciudad" no_geozone_restricted: "Toda la ciudad"
geozone_restricted: "Distritos" geozone_restricted: "Distritos"
geozone_info: "Pueden participar las personas empadronadas en: " geozone_info: "Pueden participar las personas empadronadas en: "
can_answer: "¡Puedes participar en esta votación!"
cant_answer: "Esta votación no está disponible en tu zona"
cant_answer_not_logged_in: "Necesitas iniciar sesión o registrarte para participar"
cant_answer_verify: "Por favor verifica tu cuenta para poder responder"
already_answer: "Ya has participado en esta votación" already_answer: "Ya has participado en esta votación"
section_header: section_header:
icon_alt: Icono de Votaciones icon_alt: Icono de Votaciones

View File

@@ -301,7 +301,8 @@ Rails.application.routes.draw do
end end
resources :questions, shallow: true do resources :questions, shallow: true do
resources :answers, only: [:new, :create], controller: 'questions/answers' do resources :answers, only: [:new, :create], controller: 'questions/answers', shallow: true do
resources :images, controller: 'questions/answers/images'
resources :videos, controller: 'questions/answers/videos' resources :videos, controller: 'questions/answers/videos'
end end
end end

View File

@@ -1,46 +1,74 @@
default: &default default: &default
secret_key_base: "56792feef405a59b18ea7db57b4777e855103882b926413d4afdfb8c0ea8aa86ea6649da4e729c5f5ae324c0ab9338f789174cf48c544173bc18fdc3b14262e4" secret_key_base: 56792feef405a59b18ea7db57b4777e855103882b926413d4afdfb8c0ea8aa86ea6649da4e729c5f5ae324c0ab9338f789174cf48c544173bc18fdc3b14262e4
maps: &maps
map_tiles_provider: "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" map_tiles_provider: "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
map_tiles_provider_attribution: "&copy; <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors" map_tiles_provider_attribution: "&copy; <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors"
development: apis: &apis
<<: *default
test:
<<: *default
staging:
server_name: ""
<<: *default
production: &production
secret_key_base: "817232feef405a59b18ea7db57b4777e855103882b926413d4afdfb8c0ea8aa86ea6649da4e729c5f5ae324c0ab9338f789174cf48c544173bc18fdc3b14262e4"
census_api_end_point: "" census_api_end_point: ""
census_api_institution_code: "" census_api_institution_code: ""
census_api_portal_name: "" census_api_portal_name: ""
census_api_user_code: "" census_api_user_code: ""
sms_end_point: "" sms_end_point: ""
sms_username: "" sms_username: ""
sms_password: "" sms_password: ""
http_basic_auth: &http_basic_auth
http_basic_auth: true
development:
http_basic_username: "dev"
http_basic_password: "pass"
<<: *default
test:
<<: *default
<<: *maps
staging:
secret_key_base: ""
server_name: ""
rollbar_server_token: ""
http_basic_username: "" http_basic_username: ""
http_basic_password: "" http_basic_password: ""
managers_url: ""
managers_application_key: ""
<<: *default
<<: *maps
<<: *apis
preproduction:
secret_key_base: ""
server_name: ""
rollbar_server_token: ""
http_basic_username: ""
http_basic_password: ""
managers_url: ""
managers_application_key: ""
twitter_key: "" twitter_key: ""
twitter_secret: "" twitter_secret: ""
facebook_key: "" facebook_key: ""
facebook_secret: "" facebook_secret: ""
google_oauth2_key: "" google_oauth2_key: ""
google_oauth2_secret: "" google_oauth2_secret: ""
<<: *maps
<<: *apis
production:
secret_key_base: ""
server_name: ""
rollbar_server_token: "" rollbar_server_token: ""
server_name: "" http_basic_username: ""
http_basic_password: ""
map_tiles_provider: "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" managers_url: ""
map_tiles_provider_attribution: "&copy; <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors" managers_application_key: ""
twitter_key: ""
preproduction: twitter_secret: ""
server_name: "" facebook_key: ""
<<: *production facebook_secret: ""
google_oauth2_key: ""
google_oauth2_secret: ""
<<: *maps
<<: *apis

View File

@@ -70,14 +70,18 @@ feature 'Admin polls' do
scenario "Edit" do scenario "Edit" do
poll = create(:poll) poll = create(:poll)
create(:image, imageable: poll)
visit admin_poll_path(poll) visit admin_poll_path(poll)
click_link "Edit" click_link "Edit"
end_date = 1.year.from_now end_date = 1.year.from_now
expect(page).to have_css("img[alt='#{poll.image.title}']")
fill_in "poll_name", with: "Next Poll" fill_in "poll_name", with: "Next Poll"
fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y") fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y")
click_button "Update poll" click_button "Update poll"
expect(page).to have_content "Poll updated successfully" expect(page).to have_content "Poll updated successfully"

View File

@@ -0,0 +1,14 @@
require 'rails_helper'
feature 'Images' do
background do
admin = create(:administrator)
login_as(admin.user)
end
pending "Index"
pending "Create"
pending "Destroy"
end

View File

@@ -31,6 +31,8 @@ feature 'Admin shifts' do
end end
scenario "Create Vote Collection Shift and Recount & Scrutiny Shift on same date", :js do scenario "Create Vote Collection Shift and Recount & Scrutiny Shift on same date", :js do
create(:poll)
create(:poll, :incoming)
poll = create(:poll, :current) poll = create(:poll, :current)
booth = create(:poll_booth) booth = create(:poll_booth)
assignment = create(:poll_booth_assignment, poll: poll, booth: booth) assignment = create(:poll_booth_assignment, poll: poll, booth: booth)

View File

@@ -2,16 +2,19 @@ require 'rails_helper'
feature 'Voters' do feature 'Voters' do
let(:poll) { create(:poll, :current) }
let(:booth) { create(:poll_booth) }
let(:officer) { create(:poll_officer) } let(:officer) { create(:poll_officer) }
background do background do
login_as(officer.user) login_as(officer.user)
create(:geozone, :in_census) create(:geozone, :in_census)
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection)
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
end end
scenario "Can vote", :js do scenario "Can vote", :js do
poll = create(:poll_officer_assignment, officer: officer).booth_assignment.poll
visit new_officing_residence_path visit new_officing_residence_path
officing_verify_residence officing_verify_residence
@@ -31,15 +34,16 @@ feature 'Voters' do
end end
scenario "Already voted", :js do scenario "Already voted", :js do
poll1 = create(:poll) poll2 = create(:poll, :current)
poll2 = create(:poll) booth_assignment = create(:poll_booth_assignment, poll: poll2, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
user = create(:user, :level_two) user = create(:user, :level_two)
voter = create(:poll_voter, poll: poll1, user: user) voter = create(:poll_voter, poll: poll, user: user)
visit new_officing_voter_path(id: voter.user.id) visit new_officing_voter_path(id: voter.user.id)
within("#poll_#{poll1.id}") do within("#poll_#{poll.id}") do
expect(page).to have_content "Has already participated in this poll" expect(page).to have_content "Has already participated in this poll"
expect(page).to_not have_button "Confirm vote" expect(page).to_not have_button "Confirm vote"
end end
@@ -52,7 +56,6 @@ feature 'Voters' do
scenario "Had already verified his residence, but is not level 2 yet", :js do scenario "Had already verified his residence, but is not level 2 yet", :js do
user = create(:user, residence_verified_at: Time.current, document_type: "1", document_number: "12345678Z") user = create(:user, residence_verified_at: Time.current, document_type: "1", document_number: "12345678Z")
expect(user).to_not be_level_two_verified expect(user).to_not be_level_two_verified
poll = create(:poll_officer_assignment, officer: officer).booth_assignment.poll
visit new_officing_residence_path visit new_officing_residence_path
officing_verify_residence officing_verify_residence
@@ -61,6 +64,37 @@ feature 'Voters' do
expect(page).to have_content poll.name expect(page).to have_content poll.name
end end
#Fix and use answerable_by(user) scenario "Display only current polls on which officer has a voting shift today, and user can answer", :js do
xscenario "Display only answerable polls" poll_current = create(:poll, :current)
second_booth = create(:poll_booth)
booth_assignment = create(:poll_booth_assignment, poll: poll_current, booth: second_booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
create(:poll_shift, officer: officer, booth: second_booth, date: Date.current, task: :recount_scrutiny)
create(:poll_shift, officer: officer, booth: second_booth, date: Date.tomorrow, task: :vote_collection)
poll_expired = create(:poll, :expired)
create(:poll_officer_assignment, officer: officer, booth_assignment: create(:poll_booth_assignment, poll: poll_expired, booth: booth))
poll_incoming = create(:poll, :incoming)
create(:poll_officer_assignment, officer: officer, booth_assignment: create(:poll_booth_assignment, poll: poll_incoming, booth: booth))
poll_geozone_restricted_in = create(:poll, :current, geozone_restricted: true, geozones: [Geozone.first])
booth_assignment = create(:poll_booth_assignment, poll: poll_geozone_restricted_in, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
poll_geozone_restricted_out = create(:poll, :current, geozone_restricted: true, geozones: [create(:geozone, census_code: "02")])
booth_assignment = create(:poll_booth_assignment, poll: poll_geozone_restricted_out, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
visit new_officing_residence_path
officing_verify_residence
expect(page).to have_content "Polls"
expect(page).to have_content poll.name
expect(page).not_to have_content poll_current.name
expect(page).not_to have_content poll_expired.name
expect(page).not_to have_content poll_incoming.name
expect(page).to have_content poll_geozone_restricted_in.name
expect(page).not_to have_content poll_geozone_restricted_out.name
end
end end

View File

@@ -33,9 +33,25 @@ feature 'Answers' do
click_button "Save" click_button "Save"
expect(page).to have_content "Answer created successfully" expect(page).to have_content "Answer created successfully"
expect(page).to have_css(".poll_question_answer", count: 1)
expect(page).to have_content "¿Would you like to reform Central Park?"
expect(page).to have_content "Adding more trees, creating a play area..."
end end
pending "Update" pending "Update"
pending "Destroy" pending "Destroy"
context "Gallery" do
it_behaves_like "nested imageable",
"poll_question_answer",
"new_admin_answer_image_path",
{ "answer_id": "id" },
nil,
"Save image",
"Image uploaded successfully",
true
end
end end

View File

@@ -6,11 +6,15 @@ feature 'Polls' do
scenario 'Polls can be listed' do scenario 'Polls can be listed' do
polls = create_list(:poll, 3) polls = create_list(:poll, 3)
create(:image, imageable: polls[0])
create(:image, imageable: polls[1])
create(:image, imageable: polls[2])
visit polls_path visit polls_path
polls.each do |poll| polls.each do |poll|
expect(page).to have_content(poll.name) expect(page).to have_content(poll.name)
expect(page).to have_css("img[alt='#{poll.image.title}']")
expect(page).to have_link("Participate in this poll") expect(page).to have_link("Participate in this poll")
end end
end end
@@ -59,7 +63,7 @@ feature 'Polls' do
context 'Show' do context 'Show' do
let(:geozone) { create(:geozone) } let(:geozone) { create(:geozone) }
let(:poll) { create(:poll) } let(:poll) { create(:poll, summary: "Summary", description: "Description") }
scenario 'Lists questions from proposals as well as regular ones' do scenario 'Lists questions from proposals as well as regular ones' do
normal_question = create(:poll_question, poll: poll) normal_question = create(:poll_question, poll: poll)
@@ -67,6 +71,8 @@ feature 'Polls' do
visit poll_path(poll) visit poll_path(poll)
expect(page).to have_content(poll.name) expect(page).to have_content(poll.name)
expect(page).to have_content(poll.summary)
expect(page).to have_content(poll.description)
expect(page).to have_content(normal_question.title) expect(page).to have_content(normal_question.title)
expect(page).to have_content(proposal_question.title) expect(page).to have_content(proposal_question.title)

View File

@@ -4,11 +4,24 @@ feature "Voter" do
context "Origin" do context "Origin" do
scenario "Voting via web", :js do let(:poll) { create(:poll, :current) }
let(:booth) { create(:poll_booth) }
let(:officer) { create(:poll_officer) }
background do
create(:geozone, :in_census)
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection)
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
end
scenario "Voting via web - Standard", :js do
poll = create(:poll) poll = create(:poll)
question = create(:poll_question, poll: poll) question = create(:poll_question, poll: poll)
answer1 = create(:poll_question_answer, question: question, title: 'Yes') answer1 = create(:poll_question_answer, question: question, title: 'Yes')
answer2 = create(:poll_question_answer, question: question, title: 'No') answer2 = create(:poll_question_answer, question: question, title: 'No')
user = create(:user, :level_two) user = create(:user, :level_two)
login_as user login_as user
@@ -25,13 +38,6 @@ feature "Voter" do
scenario "Voting in booth", :js do scenario "Voting in booth", :js do
user = create(:user, :in_census) user = create(:user, :in_census)
create(:geozone, :in_census)
poll = create(:poll)
officer = create(:poll_officer)
ba = create(:poll_booth_assignment, poll: poll)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba)
login_through_form_as_officer(officer.user) login_through_form_as_officer(officer.user)
@@ -50,14 +56,12 @@ feature "Voter" do
context "Trying to vote the same poll in booth and web" do context "Trying to vote the same poll in booth and web" do
let(:poll) { create(:poll) } let(:poll) { create(:poll) }
let(:question) { create(:poll_question, poll: poll) } let(:question) { create(:poll_question, poll: poll) }
let!(:answer1) { create(:poll_question_answer, question: question, title: 'Yes') } let!(:answer1) { create(:poll_question_answer, question: question, title: 'Yes') }
let!(:answer2) { create(:poll_question_answer, question: question, title: 'No') } let!(:answer2) { create(:poll_question_answer, question: question, title: 'No') }
let!(:user) { create(:user, :in_census) }
let(:officer) { create(:poll_officer) } let!(:user) { create(:user, :in_census) }
let(:ba) { create(:poll_booth_assignment, poll: poll) }
let!(:oa) { create(:poll_officer_assignment, officer: officer, booth_assignment: ba) }
scenario "Trying to vote in web and then in booth", :js do scenario "Trying to vote in web and then in booth", :js do
login_as user login_as user

View File

@@ -1,21 +1,23 @@
shared_examples "nested imageable" do |imageable_factory_name, path, imageable_path_arguments, fill_resource_method_name, submit_button, imageable_success_notice| shared_examples "nested imageable" do |imageable_factory_name, path, imageable_path_arguments, fill_resource_method_name, submit_button, imageable_success_notice, has_many_images=false|
include ActionView::Helpers include ActionView::Helpers
include ImagesHelper include ImagesHelper
include ImageablesHelper include ImageablesHelper
let!(:administrator) { create(:user) }
let!(:user) { create(:user, :level_two) } let!(:user) { create(:user, :level_two) }
let!(:administrator) { create(:administrator, user: user) }
let!(:arguments) { {} } let!(:arguments) { {} }
let!(:imageable) { create(imageable_factory_name, author: user) } let!(:imageable) { create(imageable_factory_name) }
before do before do
create(:administrator, user: administrator)
if imageable_path_arguments if imageable_path_arguments
imageable_path_arguments.each do |argument_name, path_to_value| imageable_path_arguments.each do |argument_name, path_to_value|
arguments.merge!("#{argument_name}": imageable.send(path_to_value)) arguments.merge!("#{argument_name}": imageable.send(path_to_value))
end end
end end
if imageable.respond_to?(:author)
imageable.update(author: user)
end
end end
describe "at #{path}" do describe "at #{path}" do
@@ -66,8 +68,12 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
image_input = find(".image").find("input[type=file]", visible: false) image_input = find(".image").find("input[type=file]", visible: false)
attach_file(image_input[:id], "spec/fixtures/files/clippy.jpg", make_visible: true) attach_file(image_input[:id], "spec/fixtures/files/clippy.jpg", make_visible: true)
if has_many_images
expect(find("input[id$='_title']").value).to eq "Title"
else
expect(find("##{imageable_factory_name}_image_attributes_title").value).to eq "Title" expect(find("##{imageable_factory_name}_image_attributes_title").value).to eq "Title"
end end
end
scenario "Should update loading bar style after valid file upload", :js do scenario "Should update loading bar style after valid file upload", :js do
login_as user login_as user
@@ -78,7 +84,7 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
expect(page).to have_selector ".loading-bar.complete" expect(page).to have_selector ".loading-bar.complete"
end end
scenario "Should update loading bar style after unvalid file upload", :js do scenario "Should update loading bar style after invalid file upload", :js do
login_as user login_as user
visit send(path, arguments) visit send(path, arguments)
@@ -112,10 +118,14 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
click_link "Add image" click_link "Add image"
click_on submit_button click_on submit_button
if has_many_images
#Pending. Review soon and test
else
within "#nested-image .image" do within "#nested-image .image" do
expect(page).to have_content("can't be blank", count: 2) expect(page).to have_content("can't be blank", count: 2)
end end
end end
end
scenario "Should remove nested image after valid file upload and click on remove button", :js do scenario "Should remove nested image after valid file upload and click on remove button", :js do
login_as user login_as user
@@ -159,9 +169,13 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
click_on submit_button click_on submit_button
imageable_redirected_to_resource_show_or_navigate_to imageable_redirected_to_resource_show_or_navigate_to
if has_many_images
#Pending. Review soon and test
else
expect(page).to have_selector "figure img" expect(page).to have_selector "figure img"
expect(page).to have_selector "figure figcaption" expect(page).to have_selector "figure figcaption"
end end
end
if path.include? "edit" if path.include? "edit"