diff --git a/app/controllers/admin/poll/questions/answers/images_controller.rb b/app/controllers/admin/poll/questions/answers/images_controller.rb index 4074eb371..1bf30907d 100644 --- a/app/controllers/admin/poll/questions/answers/images_controller.rb +++ b/app/controllers/admin/poll/questions/answers/images_controller.rb @@ -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 diff --git a/app/controllers/admin/poll/questions/answers/videos_controller.rb b/app/controllers/admin/poll/questions/answers/videos_controller.rb new file mode 100644 index 000000000..a231c1a20 --- /dev/null +++ b/app/controllers/admin/poll/questions/answers/videos_controller.rb @@ -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 diff --git a/app/controllers/admin/poll/questions/answers_controller.rb b/app/controllers/admin/poll/questions/answers_controller.rb index 660339844..45f0abcd7 100644 --- a/app/controllers/admin/poll/questions/answers_controller.rb +++ b/app/controllers/admin/poll/questions/answers_controller.rb @@ -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 diff --git a/app/controllers/admin/poll/questions_controller.rb b/app/controllers/admin/poll/questions_controller.rb index 107c06740..5cf587735 100644 --- a/app/controllers/admin/poll/questions_controller.rb +++ b/app/controllers/admin/poll/questions_controller.rb @@ -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 diff --git a/app/controllers/polls/questions_controller.rb b/app/controllers/polls/questions_controller.rb index 39fc18252..407e6d984 100644 --- a/app/controllers/polls/questions_controller.rb +++ b/app/controllers/polls/questions_controller.rb @@ -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) diff --git a/app/helpers/polls_helper.rb b/app/helpers/polls_helper.rb index acc84b49c..dd4018be7 100644 --- a/app/helpers/polls_helper.rb +++ b/app/helpers/polls_helper.rb @@ -44,5 +44,9 @@ module PollsHelper def poll_voter_token(poll, user) 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 diff --git a/app/models/direct_upload.rb b/app/models/direct_upload.rb index 192f06d04..e597f9f12 100644 --- a/app/models/direct_upload.rb +++ b/app/models/direct_upload.rb @@ -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) diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb index 1e94e0180..e6ef482a9 100644 --- a/app/models/poll/question.rb +++ b/app/models/poll/question.rb @@ -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 diff --git a/app/models/poll/question/answer.rb b/app/models/poll/question/answer.rb index 1746c480c..b3324e57f 100644 --- a/app/models/poll/question/answer.rb +++ b/app/models/poll/question/answer.rb @@ -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 diff --git a/app/models/poll/question/answer/video.rb b/app/models/poll/question/answer/video.rb new file mode 100644 index 000000000..3d214af96 --- /dev/null +++ b/app/models/poll/question/answer/video.rb @@ -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 diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 81e1ae9bd..21dc7cffb 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -53,7 +53,6 @@ <% end %> - <% if feature?(:polls) %>
  • diff --git a/app/views/admin/poll/officer_assignments/by_officer.html.erb b/app/views/admin/poll/officer_assignments/by_officer.html.erb index c9873db96..c6738eba0 100644 --- a/app/views/admin/poll/officer_assignments/by_officer.html.erb +++ b/app/views/admin/poll/officer_assignments/by_officer.html.erb @@ -21,7 +21,7 @@ <% @officer_assignments.each do |officer_assignment| %> - <%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %> + <%= l(officer_assignment.date.to_date)%> <%= content_tag :strong, t('polls.final_date') if officer_assignment.final %> <%= booth_name_with_location(officer_assignment.booth_assignment.booth) %> <% end %> diff --git a/app/views/admin/poll/questions/_form.html.erb b/app/views/admin/poll/questions/_form.html.erb index 5345a64b1..d197112f5 100644 --- a/app/views/admin/poll/questions/_form.html.erb +++ b/app/views/admin/poll/questions/_form.html.erb @@ -4,7 +4,6 @@ <%= f.hidden_field :proposal_id %> -
    <%= f.select :poll_id, @@ -15,10 +14,6 @@ <%= f.text_field :title, maxlength: Poll::Question.title_max_length %> -
    - <%= render 'documents/nested_documents', documentable: @question, f: f %> -
    -
    <%= f.label :video_url, t("proposals.form.proposal_video_url") %>

    <%= t("proposals.form.proposal_video_url_note") %>

    diff --git a/app/views/admin/poll/questions/answers/_form.html.erb b/app/views/admin/poll/questions/answers/_form.html.erb index 72ffb4771..3bb2ebe39 100644 --- a/app/views/admin/poll/questions/answers/_form.html.erb +++ b/app/views/admin/poll/questions/answers/_form.html.erb @@ -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 %>
    - <%= 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 } %>
    -
    +
    <%= f.submit(class: "button expanded", value: t("shared.save")) %>
    diff --git a/app/views/admin/poll/questions/answers/documents.html.erb b/app/views/admin/poll/questions/answers/documents.html.erb new file mode 100644 index 000000000..54dd25a18 --- /dev/null +++ b/app/views/admin/poll/questions/answers/documents.html.erb @@ -0,0 +1,55 @@ +<%= back_link_to %> + +

    <%= t("admin.questions.show.answers.documents_list") %>

    + + + +
    + <%= form_for(Poll::Question::Answer.new, + url: admin_answer_path(@answer), + method: :put) do |f| %> + + <%= render 'shared/errors', resource: @answer %> + +
    +
    +
    + <%= render 'documents/nested_documents', documentable: @answer, f: f %> +
    + +
    +
    + <%= f.submit(class: "button expanded", value: t("shared.save")) %> +
    +
    +
    +
    + <% end %> + + <% if @answer.documents.present? %> + + + + + + + <% @answer.documents.each do |document| %> + + + + + <% end %> +
    <%= t("admin.questions.show.answers.document_title") %><%= t("admin.questions.show.answers.document_actions") %>
    + <%= link_to document.title, document.attachment.url %> + + <%= link_to t('documents.buttons.download_document'), + document.attachment.url, + target: "_blank", + rel: "nofollow", + class: 'button hollow' %> +
    + <% end %> +
    diff --git a/app/views/admin/poll/questions/answers/edit.html.erb b/app/views/admin/poll/questions/answers/edit.html.erb new file mode 100644 index 000000000..48fb4ad5d --- /dev/null +++ b/app/views/admin/poll/questions/answers/edit.html.erb @@ -0,0 +1,14 @@ +<%= back_link_to %> + + + +

    + <%= t("admin.answers.edit.title") %> +

    + +
    + <%= render "form", form_url: admin_answer_path(@answer) %> +
    diff --git a/app/views/admin/poll/questions/answers/show.html.erb b/app/views/admin/poll/questions/answers/show.html.erb new file mode 100644 index 000000000..e6e0244a0 --- /dev/null +++ b/app/views/admin/poll/questions/answers/show.html.erb @@ -0,0 +1,32 @@ +<%= back_link_to %> + +<%= link_to t('shared.edit'), edit_admin_answer_path(@answer), + class: "button hollow float-right" %> + + + +
    + +
    +
    +

    + <%= t("admin.answers.show.title") %> +
    + <%= @answer.title %> +

    + +

    + <%= t("admin.answers.show.description") %> + <%= @answer.description %> +

    + +

    + <%= t("admin.answers.show.images") %> +
    + <%= link_to t("admin.answers.show.images_list"), admin_answer_images_path(@answer) %> +

    +
    +
    diff --git a/app/views/admin/poll/questions/answers/videos/_form.html.erb b/app/views/admin/poll/questions/answers/videos/_form.html.erb new file mode 100644 index 000000000..28035c397 --- /dev/null +++ b/app/views/admin/poll/questions/answers/videos/_form.html.erb @@ -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 %> + +
    +
    + + <%= f.text_field :title %> + <%= f.text_field :url %> + +
    +
    + <%= f.submit(class: "button expanded", value: t("shared.save")) %> +
    +
    + +
    +
    +<% end %> diff --git a/app/views/admin/poll/questions/answers/videos/edit.html.erb b/app/views/admin/poll/questions/answers/videos/edit.html.erb new file mode 100644 index 000000000..31b59c2dd --- /dev/null +++ b/app/views/admin/poll/questions/answers/videos/edit.html.erb @@ -0,0 +1,9 @@ +<%= back_link_to %> + +

    + <%= t("admin.answers.videos.edit.title") %> +

    + +
    + <%= render "form", form_url: admin_video_path(@video) %> +
    diff --git a/app/views/admin/poll/questions/answers/videos/index.html.erb b/app/views/admin/poll/questions/answers/videos/index.html.erb new file mode 100644 index 000000000..0ea64c570 --- /dev/null +++ b/app/views/admin/poll/questions/answers/videos/index.html.erb @@ -0,0 +1,47 @@ +<%= back_link_to admin_question_path(@answer.question_id) %> + +
    + +

    + <%= t("admin.answers.videos.index.title") %> +

    + +<%= link_to t("admin.answers.videos.index.add_video"), + new_admin_answer_video_path, + class: "button success float-right" %> + +
    + + + + + + + + + + + + <% @answer.videos.each do |video| %> + + + + + + <% end %> + +
    <%= t("admin.answers.videos.index.video_title") %><%= t("admin.answers.videos.index.video_url") %> + <%= t("admin.actions.actions") %> +
    <%= video.title %><%= link_to "#{video.url}", video.url %> + + <%= 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 %> +
    + +
    diff --git a/app/views/admin/poll/questions/answers/videos/new.html.erb b/app/views/admin/poll/questions/answers/videos/new.html.erb new file mode 100644 index 000000000..d114b9104 --- /dev/null +++ b/app/views/admin/poll/questions/answers/videos/new.html.erb @@ -0,0 +1,9 @@ +<%= back_link_to admin_answer_videos_path(@answer) %> + +

    + <%= t('admin.answers.videos.new.title') %> +

    + +
    + <%= render "form", form_url: admin_answer_videos_path %> +
    diff --git a/app/views/admin/poll/questions/show.html.erb b/app/views/admin/poll/questions/show.html.erb index 64c30de1e..123d2ec13 100644 --- a/app/views/admin/poll/questions/show.html.erb +++ b/app/views/admin/poll/questions/show.html.erb @@ -31,7 +31,7 @@ - - - + + + + <% @question.question_answers.each do |answer| %> - + + + <% end %>
    + <%= t('admin.questions.show.valid_answers') %> <%= link_to t("admin.questions.show.add_answer"), new_admin_question_answer_path(@question), @@ -41,19 +41,33 @@
    <%= t("admin.questions.show.answers.title") %><%= t("admin.questions.show.answers.description") %><%= t("admin.questions.show.answers.images") %><%= t("admin.questions.show.answers.description") %><%= t("admin.questions.show.answers.images") %><%= t("admin.questions.show.answers.documents") %><%= t("admin.questions.show.answers.videos") %>
    <%= answer.title %><%= link_to answer.title, admin_answer_path(answer) %> <%= answer.description %> - (<%= answer.images.count %>)
    + (<%= answer.images.count %>) +
    <%= link_to t("admin.questions.show.answers.images_list"), admin_answer_images_path(answer) %>
    + (<%= answer.documents.count rescue 0 %>) +
    + <%= link_to t("admin.questions.show.answers.documents_list"), + admin_answer_documents_path(answer) %> +
    + <%= link_to t("admin.questions.show.answers.video_list", + count: answer.videos.count), + admin_answer_videos_path(answer) %> +
    @@ -65,11 +79,3 @@
    <%= @question.video_url %>

    <% end %> - -<% if @question.documents.any? %> -

    - <%= t("admin.questions.show.documents") %> -
    - <%= @question.documents.first.title %> -

    -<% end %> diff --git a/app/views/polls/_gallery.html.erb b/app/views/polls/_gallery.html.erb index ba6cfc2e6..d3da43b88 100644 --- a/app/views/polls/_gallery.html.erb +++ b/app/views/polls/_gallery.html.erb @@ -16,10 +16,10 @@
  • - <% answer.images.each_with_index do |image, index| %> + <% answer.images.reverse.each_with_index do |image, 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 %> diff --git a/app/views/polls/questions/_answers.html.erb b/app/views/polls/questions/_answers.html.erb index 3801a1964..540eb46f3 100644 --- a/app/views/polls/questions/_answers.html.erb +++ b/app/views/polls/questions/_answers.html.erb @@ -1,9 +1,9 @@
    <% 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) %> "> + title="<%= t("poll_questions.show.voted", answer: answer.title)%>"> <%= answer.title %> <% else %> diff --git a/app/views/polls/show.html.erb b/app/views/polls/show.html.erb index be743f2f1..1fd305e71 100644 --- a/app/views/polls/show.html.erb +++ b/app/views/polls/show.html.erb @@ -45,6 +45,12 @@
    <% end %> + <% if current_user && !@poll.votable_by?(current_user) %> +
    + <%= t("polls.show.already_voted_in_web") %> +
    + <% 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) %> - + <% end %> @@ -73,19 +81,22 @@
    -

    <%= answer.title %>

    + <% if answer.description.present? %> +

    <%= answer.title %>

    + <% end %> <% if answer.images.any? %> <%= render "gallery", answer: answer %> <% end %> -
    - <%= safe_html_with_links simple_format(answer.description) %> -
    + <% if answer.description.present? %> +
    + <%= safe_html_with_links simple_format(answer.description) %> +
    + <% end %>
    <% end %> - diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 5ef1917d3..bf2cbb712 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -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: diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 02d8bacdd..b16214a2a 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -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" diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 8f999d0ec..28da4e1c1 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -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 diff --git a/config/locales/en/responders.yml b/config/locales/en/responders.yml index fd187c495..88f68a955 100644 --- a/config/locales/en/responders.yml +++ b/config/locales/en/responders.yml @@ -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." diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 9b3260680..f61e3bd53 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -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: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 9e0de770e..75fa73dff 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -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" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 677b03a4a..6d4056f17 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -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 diff --git a/config/locales/es/responders.yml b/config/locales/es/responders.yml index a35387ff3..01f19d96e 100644 --- a/config/locales/es/responders.yml +++ b/config/locales/es/responders.yml @@ -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." diff --git a/config/locales/fr/activerecord.yml b/config/locales/fr/activerecord.yml index d6ab5db80..82e9d180e 100644 --- a/config/locales/fr/activerecord.yml +++ b/config/locales/fr/activerecord.yml @@ -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: diff --git a/config/locales/fr/admin.yml b/config/locales/fr/admin.yml index e000c8a28..d80e55fc9 100644 --- a/config/locales/fr/admin.yml +++ b/config/locales/fr/admin.yml @@ -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" diff --git a/config/locales/fr/responders.yml b/config/locales/fr/responders.yml index 9897e3455..1d1cfae0c 100644 --- a/config/locales/fr/responders.yml +++ b/config/locales/fr/responders.yml @@ -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." diff --git a/config/routes.rb b/config/routes.rb index 387983d4b..83b5754d7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/migrate/20171004210108_create_poll_question_answer_videos.rb b/db/migrate/20171004210108_create_poll_question_answer_videos.rb new file mode 100644 index 000000000..7cce33b29 --- /dev/null +++ b/db/migrate/20171004210108_create_poll_question_answer_videos.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index cafec3a82..b68467ce8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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" diff --git a/spec/features/admin/poll/questions/answers/answers_spec.rb b/spec/features/admin/poll/questions/answers/answers_spec.rb new file mode 100644 index 000000000..b3b3ad420 --- /dev/null +++ b/spec/features/admin/poll/questions/answers/answers_spec.rb @@ -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 diff --git a/spec/features/admin/poll/questions/answers/videos/videos_spec.rb b/spec/features/admin/poll/questions/answers/videos/videos_spec.rb new file mode 100644 index 000000000..ee04ce128 --- /dev/null +++ b/spec/features/admin/poll/questions/answers/videos/videos_spec.rb @@ -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 diff --git a/spec/features/admin/poll/questions_spec.rb b/spec/features/admin/poll/questions_spec.rb index 7e103c647..5c8cba9c1 100644 --- a/spec/features/admin/poll/questions_spec.rb +++ b/spec/features/admin/poll/questions_spec.rb @@ -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 diff --git a/spec/features/polls/polls_spec.rb b/spec/features/polls/polls_spec.rb index 22b90740a..91b90c23f 100644 --- a/spec/features/polls/polls_spec.rb +++ b/spec/features/polls/polls_spec.rb @@ -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 diff --git a/spec/features/polls/voter_spec.rb b/spec/features/polls/voter_spec.rb index 453924674..e558b7261 100644 --- a/spec/features/polls/voter_spec.rb +++ b/spec/features/polls/voter_spec.rb @@ -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 diff --git a/spec/shared/features/nested_documentable.rb b/spec/shared/features/nested_documentable.rb index 8780936a7..24d6631a8 100644 --- a/spec/shared/features/nested_documentable.rb +++ b/spec/shared/features/nested_documentable.rb @@ -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 diff --git a/spec/shared/features/nested_imageable.rb b/spec/shared/features/nested_imageable.rb index bd519a5bb..1eef9a269 100644 --- a/spec/shared/features/nested_imageable.rb +++ b/spec/shared/features/nested_imageable.rb @@ -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