Merge branch 'master' into feature/1985#voting_token

This commit is contained in:
BertoCQ
2017-10-07 10:46:13 +02:00
committed by GitHub
46 changed files with 638 additions and 111 deletions

View File

@@ -23,7 +23,8 @@ class Admin::Poll::Questions::Answers::ImagesController < Admin::Poll::BaseContr
private
def images_params
params.permit(images_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
params.require(:poll_question_answer).permit(:answer_id,
images_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
end
def load_answer

View File

@@ -0,0 +1,57 @@
class Admin::Poll::Questions::Answers::VideosController < Admin::Poll::BaseController
before_action :load_answer, only: [:index, :new, :create]
before_action :load_video, only: [:edit, :update, :destroy]
def index
end
def new
@video = ::Poll::Question::Answer::Video.new
end
def create
@video = ::Poll::Question::Answer::Video.new(video_params)
if @video.save
redirect_to admin_answer_videos_path(@answer),
notice: t("flash.actions.create.poll_question_answer_video")
else
render :new
end
end
def edit
end
def update
if @video.update(video_params)
redirect_to admin_answer_videos_path(@video.answer_id),
notice: t("flash.actions.save_changes.notice")
else
render :edit
end
end
def destroy
if @video.destroy
notice = t("flash.actions.destroy.poll_question_answer_video")
else
notice = t("flash.actions.destroy.error")
end
redirect_to :back, notice: notice
end
private
def video_params
params.require(:poll_question_answer_video).permit(:title, :url, :answer_id)
end
def load_answer
@answer = ::Poll::Question::Answer.find(params[:answer_id])
end
def load_video
@video = ::Poll::Question::Answer::Video.find(params[:id])
end
end

View File

@@ -1,5 +1,6 @@
class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
before_action :load_question
before_action :load_question, except: [:show, :edit, :update]
before_action :load_answer, only: [:show, :edit, :update, :documents]
load_and_authorize_resource :question, class: "::Poll::Question"
@@ -18,13 +19,39 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
end
end
def show
end
def edit
end
def update
if @answer.update(answer_params)
redirect_to admin_answer_path(@answer),
notice: t("flash.actions.save_changes.notice")
else
redirect_to :back
end
end
def documents
@documents = @answer.documents
render 'admin/poll/questions/answers/documents'
end
private
def answer_params
params.require(:poll_question_answer).permit(:title, :description, :question_id)
params.require(:poll_question_answer).permit(:title, :description, :question_id, documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
end
def load_answer
@answer = ::Poll::Question::Answer.find(params[:id] || params[:answer_id])
end
def load_question
@question = ::Poll::Question.find(params[:question_id])
end
end

View File

@@ -56,8 +56,7 @@ class Admin::Poll::QuestionsController < Admin::Poll::BaseController
private
def question_params
params.require(:poll_question).permit(:poll_id, :title, :question, :proposal_id, :valid_answers, :video_url,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
params.require(:poll_question).permit(:poll_id, :title, :question, :proposal_id, :valid_answers, :video_url)
end
def search_params

View File

@@ -10,6 +10,7 @@ class Polls::QuestionsController < ApplicationController
token = params[:token]
answer.answer = params[:answer]
answer.touch if answer.persisted?
answer.save!
answer.record_voter_participation(token)

View File

@@ -45,4 +45,8 @@ module PollsHelper
Poll::Voter.where(poll: poll, user: user, origin: "web").first&.token || ''
end
def voted_before_sign_in(question)
question.answers.where(author: current_user).any? { |vote| current_user.current_sign_in_at >= vote.updated_at }
end
end

View File

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

View File

@@ -1,11 +1,6 @@
class Poll::Question < ActiveRecord::Base
include Measurable
include Searchable
include Documentable
documentable max_documents_allowed: 1,
max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ]
accepts_nested_attributes_for :documents, allow_destroy: true
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases

View File

@@ -1,7 +1,13 @@
class Poll::Question::Answer < ActiveRecord::Base
include Galleryable
include Documentable
documentable max_documents_allowed: 3,
max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ]
accepts_nested_attributes_for :documents, allow_destroy: true
belongs_to :question, class_name: 'Poll::Question', foreign_key: 'question_id'
has_many :videos, class_name: 'Poll::Question::Answer::Video'
validates :title, presence: true

View File

@@ -0,0 +1,16 @@
class Poll::Question::Answer::Video < ActiveRecord::Base
belongs_to :answer, class_name: 'Poll::Question::Answer', foreign_key: 'answer_id'
VIMEO_REGEX = /vimeo.*(staffpicks\/|channels\/|videos\/|video\/|\/)([^#\&\?]*).*/
YOUTUBE_REGEX = /youtu.*(be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
validates :title, presence: true
validate :valid_url?
def valid_url?
return if url.blank?
return if url.match(VIMEO_REGEX)
return if url.match(YOUTUBE_REGEX)
errors.add(:url, :invalid)
end
end

View File

@@ -53,7 +53,6 @@
</li>
<% end %>
<% if feature?(:polls) %>
<li class="section-title">
<a href="#">

View File

@@ -21,7 +21,7 @@
<tbody>
<% @officer_assignments.each do |officer_assignment| %>
<tr id="<%= dom_id officer_assignment %>">
<td><%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %></td>
<td><%= l(officer_assignment.date.to_date)%> <%= content_tag :strong, t('polls.final_date') if officer_assignment.final %></td>
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
</tr>
<% end %>

View File

@@ -4,7 +4,6 @@
<%= f.hidden_field :proposal_id %>
<div class="small-12">
<div class="small-12 medium-6 large-4">
<%= f.select :poll_id,
@@ -15,10 +14,6 @@
<%= f.text_field :title, maxlength: Poll::Question.title_max_length %>
<div class="documents small-12">
<%= render 'documents/nested_documents', documentable: @question, f: f %>
</div>
<div class="small-12">
<%= f.label :video_url, t("proposals.form.proposal_video_url") %>
<p class="help-text" id="video-url-help-text"><%= t("proposals.form.proposal_video_url_note") %></p>

View File

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

View File

@@ -0,0 +1,55 @@
<%= back_link_to %>
<h2><%= t("admin.questions.show.answers.documents_list") %></h2>
<ul class="breadcrumbs">
<li><%= @answer.question.title %></li>
<li><%= @answer.title %></li>
</ul>
<div class="poll-question-form">
<%= form_for(Poll::Question::Answer.new,
url: admin_answer_path(@answer),
method: :put) do |f| %>
<%= render 'shared/errors', resource: @answer %>
<div class="row">
<div class="small-12 column">
<div class="documents small-12">
<%= render 'documents/nested_documents', documentable: @answer, f: f %>
</div>
<div class="row">
<div class="actions small-12 medium-4 margin-top">
<%= f.submit(class: "button expanded", value: t("shared.save")) %>
</div>
</div>
</div>
</div>
<% end %>
<% if @answer.documents.present? %>
<table>
<tr>
<th scope="col"><%= t("admin.questions.show.answers.document_title") %></th>
<th scope="col" class="text-right"><%= t("admin.questions.show.answers.document_actions") %></th>
</tr>
<% @answer.documents.each do |document| %>
<tr>
<td>
<%= link_to document.title, document.attachment.url %>
</td>
<td class="text-right">
<%= link_to t('documents.buttons.download_document'),
document.attachment.url,
target: "_blank",
rel: "nofollow",
class: 'button hollow' %>
</td>
</tr>
<% end %>
</table>
<% end %>
</div>

View File

@@ -0,0 +1,14 @@
<%= back_link_to %>
<ul class="breadcrumbs margin-top">
<li><%= @answer.title %></li>
<li><%= t('admin.answers.edit.title') %></li>
</ul>
<h2 class="margin-top">
<%= t("admin.answers.edit.title") %>
</h2>
<div class="poll-question-answer-form">
<%= render "form", form_url: admin_answer_path(@answer) %>
</div>

View File

@@ -0,0 +1,32 @@
<%= back_link_to %>
<%= link_to t('shared.edit'), edit_admin_answer_path(@answer),
class: "button hollow float-right" %>
<ul class="breadcrumbs margin-top">
<li><%= @answer.question.title %></li>
<li><%= @answer.title %></li>
</ul>
<div class="clear"></div>
<div class="small-12 medium-6">
<div class="callout highlight">
<p>
<strong><%= t("admin.answers.show.title") %></strong>
<br>
<%= @answer.title %>
</p>
<p>
<strong><%= t("admin.answers.show.description") %></strong>
<%= @answer.description %>
</p>
<p>
<strong><%= t("admin.answers.show.images") %></strong>
<br>
<%= link_to t("admin.answers.show.images_list"), admin_answer_images_path(@answer) %>
</p>
</div>
</div>

View File

@@ -0,0 +1,21 @@
<%= form_for(@video, url: form_url) do |f| %>
<%= render 'shared/errors', resource: @video %>
<%= f.hidden_field :answer_id, value: @video.answer_id || @answer.id %>
<div class="row">
<div class="small-12 column">
<%= f.text_field :title %>
<%= f.text_field :url %>
<div class="row">
<div class="actions small-12 medium-4 column margin-top">
<%= f.submit(class: "button expanded", value: t("shared.save")) %>
</div>
</div>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,9 @@
<%= back_link_to %>
<h2>
<%= t("admin.answers.videos.edit.title") %>
</h2>
<div class="poll-question-answer-video-form">
<%= render "form", form_url: admin_video_path(@video) %>
</div>

View File

@@ -0,0 +1,47 @@
<%= back_link_to admin_question_path(@answer.question_id) %>
<div class="clear"></div>
<h2 class="inline-block">
<%= t("admin.answers.videos.index.title") %>
</h2>
<%= link_to t("admin.answers.videos.index.add_video"),
new_admin_answer_video_path,
class: "button success float-right" %>
<div>
<table>
<thead>
<tr>
<th><%= t("admin.answers.videos.index.video_title") %></th>
<th><%= t("admin.answers.videos.index.video_url") %></th>
<th class="text-right">
<%= t("admin.actions.actions") %>
</th>
</tr>
</thead>
<tbody>
<% @answer.videos.each do |video| %>
<tr id="<%= dom_id(video) %>" class="poll_question_answer_video">
<td><%= video.title %></td>
<td><%= link_to "#{video.url}", video.url %></td>
<td class="text-right">
<%= link_to t("shared.edit"),
edit_admin_video_path(video),
class: "button hollow" %>
<%= link_to t("shared.delete"),
admin_video_path(video),
class: "button hollow alert",
method: :delete %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,9 @@
<%= back_link_to admin_answer_videos_path(@answer) %>
<h2>
<%= t('admin.answers.videos.new.title') %>
</h2>
<div class="poll-question-answer-video-form">
<%= render "form", form_url: admin_answer_videos_path %>
</div>

View File

@@ -31,7 +31,7 @@
<table class="margin-top">
<tr>
<th colspan="3" scope="col" class="with-button">
<th colspan="5" scope="col" class="with-button">
<%= t('admin.questions.show.valid_answers') %>
<%= link_to t("admin.questions.show.add_answer"),
new_admin_question_answer_path(@question),
@@ -41,19 +41,33 @@
<tr>
<th><%= t("admin.questions.show.answers.title") %></th>
<th class="medium-7"><%= t("admin.questions.show.answers.description") %></th>
<th class="text-center"><%= t("admin.questions.show.answers.images") %></th>
<th scope="col" class="medium-7"><%= t("admin.questions.show.answers.description") %></th>
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.images") %></th>
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.documents") %></th>
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.videos") %></th>
</tr>
<% @question.question_answers.each do |answer| %>
<tr id="<%= dom_id(answer) %>" class="poll_question_answer">
<td><%= answer.title %></td>
<td><%= link_to answer.title, admin_answer_path(answer) %></td>
<td><%= answer.description %></td>
<td class="text-center">
(<%= answer.images.count %>)<br>
(<%= answer.images.count %>)
<br>
<%= link_to t("admin.questions.show.answers.images_list"),
admin_answer_images_path(answer) %>
</td>
<td class="text-center">
(<%= answer.documents.count rescue 0 %>)
<br>
<%= link_to t("admin.questions.show.answers.documents_list"),
admin_answer_documents_path(answer) %>
</td>
<td class="text-center">
<%= link_to t("admin.questions.show.answers.video_list",
count: answer.videos.count),
admin_answer_videos_path(answer) %>
</td>
</tr>
<% end %>
</table>
@@ -65,11 +79,3 @@
<a href="<%= @question.video_url %>"><%= @question.video_url %></a>
</p>
<% end %>
<% if @question.documents.any? %>
<p>
<strong><%= t("admin.questions.show.documents") %></strong>
<br>
<a href="<%= @question.documents.first.attachment.url %>"><%= @question.documents.first.title %></a>
</p>
<% end %>

View File

@@ -16,10 +16,10 @@
</button>
</li>
<% answer.images.each_with_index do |image, index| %>
<% answer.images.reverse.each_with_index do |image, index| %>
<li class="orbit-slide <%= active_class(index) %>">
<%= link_to image.attachment.url(:original), target: "_blank" do %>
<%= image_tag image.attachment.url(:medium),
<%= image_tag image.attachment.url(:large),
class: "orbit-image",
alt: image.title %>
<% end %>

View File

@@ -1,9 +1,9 @@
<div class="poll-question-answers">
<% if can? :answer, question %>
<% question.question_answers.each do |answer| %>
<% if @answers_by_question_id[question.id] == answer.title %>
<% if @answers_by_question_id[question.id] == answer.title && !voted_before_sign_in(question) %>
<span class="button answered"
title="<%= t("poll_questions.show.voted", answer: answer)%>">
title="<%= t("poll_questions.show.voted", answer: answer.title)%>">
<%= answer.title %>
</span>
<% else %>

View File

@@ -45,6 +45,12 @@
</div>
<% end %>
<% if current_user && !@poll.votable_by?(current_user) %>
<div class="callout warning">
<%= t("polls.show.already_voted_in_web") %>
</div>
<% end %>
<% @questions.each do |question| %>
<%= render 'polls/questions/question', question: question, token: @token %>
<% end %>
@@ -59,10 +65,12 @@
<%= safe_html_with_links simple_format(@poll.description) %>
</div>
<aside class="small-12 medium-3 column">
<% if false %>
<aside class="small-12 medium-3 column">
<div class="sidebar-divider"></div>
<h2><%= t("polls.show.documents") %></h2>
</aside>
</aside>
<% end %>
</div>
</div>
@@ -73,19 +81,22 @@
<div class="small-12 medium-6 column end" id="answer_<%= answer.id %>"
data-toggler=".medium-6">
<h3><%= answer.title %></h3>
<% if answer.description.present? %>
<h3><%= answer.title %></h3>
<% end %>
<% if answer.images.any? %>
<%= render "gallery", answer: answer %>
<% end %>
<div class="margin-top">
<%= safe_html_with_links simple_format(answer.description) %>
</div>
<% if answer.description.present? %>
<div class="margin-top">
<%= safe_html_with_links simple_format(answer.description) %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>

View File

@@ -213,9 +213,12 @@ en:
image:
title: Title
attachment: Attachment
poll/question_answer:
title: "Answer"
description: "Description"
poll/question/answer:
title: Answer
description: Description
poll/question/answer/video:
title: Title
url: External video
errors:
models:
user:

View File

@@ -587,9 +587,6 @@ en:
new:
title: "Create Question"
poll_label: "Poll"
form:
title: Title
description: Description
answers:
images:
add_image: "Add image"
@@ -599,17 +596,39 @@ en:
author: Author
title: Title
valid_answers: Valid answers
add_answer: "Add answer"
add_answer: Add answer
video_url: External video
documents: Documents (1)
answers:
title: Answer
description: Description
videos: Videos
video_list: Video list (%{count})
images: Images
images_list: Images list
documents: Documents
documents_list: Documents list
document_title: Title
document_actions: Actions
answers:
new:
title: "New answer"
title: New answer
show:
title: Title
description: Description
images: Images
images_list: Images list
edit:
title: Edit answer
videos:
index:
title: Videos
add_video: Add video
video_title: Title
video_url: External video
new:
title: New video
edit:
title: Edit video
recounts:
index:
title: "Recounts"

View File

@@ -478,7 +478,8 @@ en:
help_text_1: "Voting takes place when a citizen proposal supports reaches 1% of the census with voting rights. Voting can also include questions that the City Council ask to the citizens decision."
help_text_2: "To participate in the next vote you have to sign up on %{org} and verify your account. All registered voters in the city over 16 years old can vote. The results of all votes are binding on the government."
show:
already_voted_in_booth: "You have already participated in a booth for this poll."
already_voted_in_booth: "You have already participated in a physical booth. You can not participate again."
already_voted_in_web: "You have already participated in this poll. If you vote again it will be overwritten."
back: Back to voting
cant_answer_not_logged_in: "You must %{signin} or %{signup} to participate."
signin: Sign in

View File

@@ -9,6 +9,7 @@ en:
poll: "Poll created successfully."
poll_booth: "Booth created successfully."
poll_question_answer: "Answer created successfully"
poll_question_answer_video: "Video created successfully"
proposal: "Proposal created successfully."
proposal_notification: "Your message has been sent correctly."
spending_proposal: "Spending proposal created successfully. You can access it from %{activity}"
@@ -31,3 +32,4 @@ en:
budget_investment: "Investment project deleted succesfully."
error: "Could not delete"
topic: "Topic deleted successfully."
poll_question_answer_video: "Answer video deleted successfully."

View File

@@ -207,9 +207,12 @@ es:
image:
title: Título
attachment: Archivo adjunto
poll/question_answer:
title: "Respuesta"
description: "Descripción"
poll/question/answer:
title: Respuesta
description: Descripción
poll/question/answer/video:
title: Título
url: Vídeo externo
errors:
models:
user:

View File

@@ -587,9 +587,6 @@ es:
new:
title: "Crear pregunta ciudadana"
poll_label: "Votación"
form:
title: Título
description: Descripción
answers:
images:
add_image: "Añadir imagen"
@@ -599,21 +596,41 @@ es:
author: Autor
title: Título
valid_answers: Respuestas válidas
add_answer: "Añadir respuesta"
description: Descripción
add_answer: Añadir respuesta
video_url: Video externo
documents: Documentos (1)
preview: Ver en la web
answers:
title: Respuesta
description: Descripción
videos: Vídeos
video_list: Lista de vídeos (%{count})
images: Imágenes
images_list: Lista de imágenes
documents: Documentos
documents_list: Lista de documentos
document_title: Título
document_actions: Acciones
answers:
new:
title: "Nueva respuesta"
title: Nueva respuesta
video_url: Video externo
documents: Documentos (1)
show:
title: Título
description: Descripción
images: Imágenes
images_list: Lista de imágenes
edit:
title: Editar respuesta
videos:
index:
title: Vídeos
add_video: Añadir vídeo
video_title: Título
video_url: External video
new:
title: Nuevo video
edit:
title: Editar vídeo
recounts:
index:
title: "Recuentos"

View File

@@ -478,7 +478,8 @@ es:
help_text_1: "Las votaciones se convocan cuando una propuesta ciudadana alcanza el 1% de apoyos del censo con derecho a voto. En las votaciones también se pueden incluir cuestiones que el Ayuntamiento somete a decisión directa de la ciudadanía."
help_text_2: "Para participar en la próxima votación tienes que registrarte en %{org} y verificar tu cuenta. Pueden votar todas las personas empadronadas en la ciudad mayores de 16 años. Los resultados de todas las votaciones serán vinculantes para el gobierno."
show:
already_voted_in_booth: "Ya has participado en esta votación en una urna."
already_voted_in_booth: "Ya has participado en esta votación en urnas presenciales, no puedes volver a participar."
already_voted_in_web: "Ya has participado en esta votación. Si vuelves a votar se sobreescribirá tu resultado anterior."
back: Volver a votaciones
cant_answer_not_logged_in: "Necesitas %{signin} o %{signup} para participar."
signin: iniciar sesión

View File

@@ -9,6 +9,7 @@ es:
poll: "Votación creada correctamente."
poll_booth: "Urna creada correctamente."
poll_question_answer: "Respuesta creada correctamente"
poll_question_answer_video: "Vídeo creado correctamente"
proposal: "Propuesta creada correctamente."
proposal_notification: "Tu message ha sido enviado correctamente."
spending_proposal: "Propuesta de inversión creada correctamente. Puedes acceder a ella desde %{activity}"
@@ -31,3 +32,4 @@ es:
budget_investment: "Propuesta de inversión eliminada."
error: "No se pudo borrar"
topic: "Tema eliminado."
poll_question_answer_video: "Vídeo de respuesta eliminado."

View File

@@ -147,9 +147,12 @@ fr:
name: Nom
locale: Langue
body: Contenu
poll/question_answer:
title: "Réponse"
description: "Description"
poll/question/answer:
title: Réponse
description: Description
poll/question/answer/video:
title: Titre
url: Vidéo externe
errors:
models:
user:

View File

@@ -382,13 +382,34 @@ fr:
author: Auteur
title: Titre
valid_answers: Réponses valides
add_answer: "Ajouter une réponse"
answer: "Réponse"
description: Description
add_answer: Ajouter une réponse
documents: Documents (1)
preview: Voir l'aperçu
answers:
title: Réponse
description: Description
videos: Vidéos
video_list: Liste des vidéos (%{count})
answers:
show:
title: Titre
description: Description
images: Images
images_list: Liste des images
new:
title: "Nouvelle réponse"
title: Nouvelle réponse
edit:
title: Modifier réponse
videos:
index:
title: Vidéos
add_video: Ajouter une vidéo
video_title: Titre
video_url: Vidéo externe
new:
title: Nouveau vidéo
edit:
title: Modifier la vidéo
recounts:
index:
title: "Dépouillements"

View File

@@ -8,6 +8,8 @@ fr:
direct_message: "Votre message a été envoyé avec succès."
poll: "Vote créé avec succès."
poll_booth: "Urne créée avec succès."
poll_question_answer: "Réponse créée avec succès"
poll_question_answer_video: "Vidéo créée avec succès"
proposal: "Proposition créée avec succès."
proposal_notification: "Votre message a correctement été envoyé."
spending_proposal: "Proposition de dépense créée avec succès. Vous pouvez y accéder depuis %{activity}"
@@ -27,3 +29,4 @@ fr:
spending_proposal: "Proposition de dépense supprimée avec succès."
budget_investment: "Budget d'investissement supprimé avec succès."
error: "Suppression impossible"
poll_question_answer_video: "Réponse vidéo supprimée avec succès."

View File

@@ -300,11 +300,12 @@ Rails.application.routes.draw do
end
end
resources :questions do
resources :answers, only: [:new, :create], controller: 'questions/answers', shallow: true do
resources :questions, shallow: true do
resources :answers, except: [:index, :destroy], controller: 'questions/answers', shallow: true do
resources :images, controller: 'questions/answers/images'
resources :videos, controller: 'questions/answers/videos'
get :documents, to: 'questions/answers#documents'
end
end
end

View File

@@ -0,0 +1,11 @@
class CreatePollQuestionAnswerVideos < ActiveRecord::Migration
def change
create_table :poll_question_answer_videos do |t|
t.string :title
t.string :url
t.integer :answer_id, index: true
end
add_foreign_key :poll_question_answer_videos, :poll_question_answers, column: :answer_id
end
end

View File

@@ -668,6 +668,14 @@ ActiveRecord::Schema.define(version: 20171006145053) do
add_index "poll_partial_results", ["origin"], name: "index_poll_partial_results_on_origin", using: :btree
add_index "poll_partial_results", ["question_id"], name: "index_poll_partial_results_on_question_id", using: :btree
create_table "poll_question_answer_videos", force: :cascade do |t|
t.string "title"
t.string "url"
t.integer "answer_id"
end
add_index "poll_question_answer_videos", ["answer_id"], name: "index_poll_question_answer_videos_on_answer_id", using: :btree
create_table "poll_question_answers", force: :cascade do |t|
t.string "title"
t.text "description"
@@ -1153,6 +1161,7 @@ ActiveRecord::Schema.define(version: 20171006145053) do
add_foreign_key "poll_partial_results", "poll_officer_assignments", column: "officer_assignment_id"
add_foreign_key "poll_partial_results", "poll_questions", column: "question_id"
add_foreign_key "poll_partial_results", "users", column: "author_id"
add_foreign_key "poll_question_answer_videos", "poll_question_answers", column: "answer_id"
add_foreign_key "poll_question_answers", "poll_questions", column: "question_id"
add_foreign_key "poll_questions", "polls"
add_foreign_key "poll_questions", "proposals"

View File

@@ -0,0 +1,51 @@
require 'rails_helper'
feature 'Answers' do
background do
admin = create(:administrator)
login_as (admin.user)
end
scenario 'Create' do
question = create(:poll_question)
title = 'Whatever the question may be, the answer is always 42'
description = "The Hitchhiker's Guide To The Universe"
visit admin_question_path(question)
click_link 'Add answer'
fill_in 'poll_question_answer_title', with: title
fill_in 'poll_question_answer_description', with: description
click_button 'Save'
expect(page).to have_content(title)
expect(page).to have_content(description)
end
scenario 'Update' do
question = create(:poll_question)
answer = create(:poll_question_answer, question: question)
visit admin_answer_path(answer)
click_link 'Edit'
old_title = answer.title
new_title = 'Ex Machina'
fill_in 'poll_question_answer_title', with: new_title
click_button 'Save'
expect(page).to have_content('Changes saved')
expect(page).to have_content(new_title)
visit admin_question_path(question)
expect(page).to have_content(new_title)
expect(page).to_not have_content(old_title)
end
end

View File

@@ -0,0 +1,33 @@
require 'rails_helper'
feature 'Videos' do
background do
admin = create(:administrator)
login_as(admin.user)
end
scenario "Create" do
question = create(:poll_question)
answer = create(:poll_question_answer, question: question)
video_title = "'Magical' by Junko Ohashi"
video_url = "https://www.youtube.com/watch?v=-JMf43st-1A"
visit admin_question_path(question)
within("#poll_question_answer_#{answer.id}") do
click_link "Video list (#{answer.videos.count})"
end
click_link "Add video"
fill_in 'poll_question_answer_video_title', with: video_title
fill_in 'poll_question_answer_video_url', with: video_url
click_button "Save"
expect(page).to have_content(video_title)
expect(page).to have_content(video_url)
end
end

View File

@@ -111,22 +111,4 @@ feature 'Admin poll questions' do
pending "Mark all city by default when creating a poll question from a successful proposal"
it_behaves_like "nested documentable",
"administrator",
"poll_question",
"new_admin_question_path",
{ },
"documentable_fill_new_valid_poll_question",
"Save",
"Star Wars: Episode IV - A New Hope"
it_behaves_like "nested documentable",
"administrator",
"poll_question",
"edit_admin_question_path",
{ "id": "id" },
nil,
"Save",
"Changes saved"
end

View File

@@ -209,8 +209,7 @@ feature 'Polls' do
visit poll_path(poll)
expect(page).to have_link('Han Solo')
expect(page).to_not have_link('Chewbacca')
expect(page).to have_content('Chewbacca')
expect(page).to have_link('Chewbacca')
end
scenario 'Level 2 users answering', :js do
@@ -256,5 +255,39 @@ feature 'Polls' do
expect(page).to have_link('Han Solo')
end
scenario 'Level 2 votes, signs out, signs in, votes again', :js do
poll.update(geozone_restricted: true)
poll.geozones << geozone
question = create(:poll_question, poll: poll)
answer1 = create(:poll_question_answer, question: question, title: 'Han Solo')
answer2 = create(:poll_question_answer, question: question, title: 'Chewbacca')
user = create(:user, :level_two, geozone: geozone)
login_as user
visit poll_path(poll)
click_link 'Han Solo'
expect(page).to_not have_link('Han Solo')
expect(page).to have_link('Chewbacca')
click_link "Sign out"
login_as user
visit poll_path(poll)
click_link 'Han Solo'
expect(page).to_not have_link('Han Solo')
expect(page).to have_link('Chewbacca')
click_link "Sign out"
login_as user
visit poll_path(poll)
click_link 'Chewbacca'
expect(page).to_not have_link('Chewbacca')
expect(page).to have_link('Han Solo')
end
end
end

View File

@@ -91,9 +91,32 @@ feature "Voter" do
visit poll_path(poll)
expect(page).to_not have_link('Yes')
expect(page).to have_content "You have already participated in a booth for this poll."
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
expect(Poll::Voter.count).to eq(1)
end
scenario "Trying to vote in web again", :js do
login_as user
vote_for_poll_via_web(poll, question)
visit poll_path(poll)
expect(page).to have_content "You have already participated in this poll. If you vote again it will be overwritten."
within("#poll_question_#{question.id}_answers") do
expect(page).to_not have_link('Yes')
end
click_link "Sign out"
login_as user
visit poll_path(poll)
within("#poll_question_#{question.id}_answers") do
expect(page).to have_link('Yes')
expect(page).to have_link('No')
end
end
end
end

View File

@@ -191,9 +191,17 @@ shared_examples "nested documentable" do |login_as_name, documentable_factory_na
documentable_attach_new_file(documentable_factory_name, 0, "spec/fixtures/files/empty.pdf")
click_on submit_button
documentable_redirected_to_resource_show_or_navigate_to
expect(page).to have_content "Documents (1)"
expect(page).to have_content "Documents"
find("#tab-documents-label").click
expect(page).to have_content "empty.pdf"
#Review
#Doble check why the file is stored with a name different to empty.pdf
expect(page).to have_css("a[href$='.pdf']")
end
scenario "Should show resource with new document after successful creation with maximum allowed uploaded files", :js do
@@ -263,7 +271,6 @@ shared_examples "nested documentable" do |login_as_name, documentable_factory_na
end
end
end
@@ -275,7 +282,7 @@ rescue
return
end
def documentable_attach_new_file(documentable_factory_name, index, path, success = true)
def documentable_attach_new_file(_documentable_factory_name, index, path, success = true)
click_link "Add new document"
document = all(".document")[index]
document_input = document.find("input[type=file]", visible: false)
@@ -318,8 +325,3 @@ def documentable_fill_new_valid_budget_investment
fill_in_ckeditor "budget_investment_description", with: "Budget investment description"
check :budget_investment_terms_of_service
end
def documentable_fill_new_valid_poll_question
page.select documentable.poll.name, from: 'poll_question_poll_id'
fill_in 'poll_question_title', with: "Star Wars: Episode IV - A New Hope"
end

View File

@@ -146,7 +146,11 @@ shared_examples "nested imageable" do |imageable_factory_name, path, imageable_p
send(fill_resource_method_name) if fill_resource_method_name
click_on submit_button
expect(page).to have_content imageable_success_notice
if has_many_images
skip "no need to test, there are no attributes for the parent resource"
else
expect(page).to have_content imageable_success_notice
end
end
scenario "Should show successful notice when resource filled correctly and after valid file uploads", :js do