diff --git a/app/assets/javascripts/answers.js.coffee b/app/assets/javascripts/answers.js.coffee new file mode 100644 index 000000000..183e1c628 --- /dev/null +++ b/app/assets/javascripts/answers.js.coffee @@ -0,0 +1,20 @@ +App.Answers = + + initializeAnswers: (answers) -> + $(answers).on 'cocoon:after-insert', (e, new_answer) -> + given_order = App.Answers.maxGivenOrder(answers) + 1 + $(new_answer).find("[name$='[given_order]']").val(given_order) + + maxGivenOrder: (answers) -> + max_order = 0 + $(answers).find("[name$='[given_order]']").each (index, answer) -> + value = parseFloat($(answer).val()) + max_order = if value > max_given_order then value else max_given_order + return max_given_order + + nestedAnswers: -> + $('.js-answers').each (index, answers) -> + App.Answers.initializeAnswers(answers) + + initialize: -> + App.Answers.nestedAnswers() diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index dd02ee6ee..82b40edc9 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -59,6 +59,8 @@ //= require markdown-it //= require markdown_editor //= require cocoon +//= require answers +//= require questions //= require legislation_admin //= require legislation //= require legislation_allegations @@ -87,6 +89,8 @@ //= require send_admin_notification_alert var initialize_modules = function() { + App.Answers.initialize(); + App.Questions.initialize(); App.Comments.initialize(); App.Users.initialize(); App.Votes.initialize(); diff --git a/app/assets/javascripts/questions.js.coffee b/app/assets/javascripts/questions.js.coffee new file mode 100644 index 000000000..72023a841 --- /dev/null +++ b/app/assets/javascripts/questions.js.coffee @@ -0,0 +1,8 @@ +App.Questions = + + nestedQuestions: -> + $('.js-questions').on 'cocoon:after-insert', (e, new_question) -> + App.Answers.initializeAnswers($(new_question).find('.js-answers')) + + initialize: -> + App.Questions.nestedQuestions() diff --git a/app/assets/stylesheets/dashboard.scss b/app/assets/stylesheets/dashboard.scss index 6ebeba105..62931a13c 100644 --- a/app/assets/stylesheets/dashboard.scss +++ b/app/assets/stylesheets/dashboard.scss @@ -97,6 +97,18 @@ margin-left: $line-height / 4; max-width: 90%; + h4 { + display: inline-block; + } + + .label { + margin-left: $line-height / 2; + } + + a { + display: block; + } + h4, p { margin-bottom: 0; @@ -164,6 +176,15 @@ width: rem-calc(36); } + .label { + position: absolute; + top: 20px; + left: 0; + } + + h4 { + margin-top: $line-height; + } .resource-description { min-height: $line-height * 4; } diff --git a/app/controllers/admin/poll/questions/answers_controller.rb b/app/controllers/admin/poll/questions/answers_controller.rb index 225665b94..1d549ba3f 100644 --- a/app/controllers/admin/poll/questions/answers_controller.rb +++ b/app/controllers/admin/poll/questions/answers_controller.rb @@ -50,7 +50,8 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController def answer_params documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] - attributes = [:title, :description, :question_id, documents_attributes: documents_attributes] + attributes = [:title, :description, :given_order, :question_id, + documents_attributes: documents_attributes] params.require(:poll_question_answer).permit(*attributes, *translation_params(Poll::Question::Answer)) end diff --git a/app/controllers/dashboard/base_controller.rb b/app/controllers/dashboard/base_controller.rb index 2755e74c9..14a4f7ff6 100644 --- a/app/controllers/dashboard/base_controller.rb +++ b/app/controllers/dashboard/base_controller.rb @@ -1,5 +1,5 @@ class Dashboard::BaseController < ApplicationController - before_action :authenticate_user! + before_action :authenticate_user!, :detect_new_actions_after_last_login include Dashboard::HasProposal @@ -35,4 +35,9 @@ class Dashboard::BaseController < ApplicationController def next_goal @next_goal ||= Dashboard::Action.next_goal_for(proposal) end + + def detect_new_actions_after_last_login + author_last_login = proposal.author.last_sign_in_at.to_date + @new_actions_since_last_login = Dashboard::Action.detect_new_actions_since(author_last_login, proposal) + end end diff --git a/app/controllers/dashboard/polls_controller.rb b/app/controllers/dashboard/polls_controller.rb index 9f38c3459..40057230f 100644 --- a/app/controllers/dashboard/polls_controller.rb +++ b/app/controllers/dashboard/polls_controller.rb @@ -1,4 +1,4 @@ -class Dashboard::PollsController < Dashboard::BaseController +class Dashboard::PollsController < Dashboard::BaseController helper_method :poll def index @@ -62,7 +62,8 @@ class Dashboard::PollsController < Dashboard::BaseController end def question_answers_attributes - [:id, :_destroy, :title, :description, :question_id, documents_attributes: documents_attributes] + [:id, :_destroy, :title, :description, :given_order, :question_id, + documents_attributes: documents_attributes] end def documents_attributes diff --git a/app/helpers/proposals_dashboard_helper.rb b/app/helpers/proposals_dashboard_helper.rb index 58d468e1b..a96a09d84 100644 --- a/app/helpers/proposals_dashboard_helper.rb +++ b/app/helpers/proposals_dashboard_helper.rb @@ -83,4 +83,22 @@ module ProposalsDashboardHelper return t("dashboard.resource.resource_requested") if resource.requested_for?(proposal) t("dashboard.resource.request_resource") end + + def is_new_action_since_last_login?(proposed_action, new_actions_since_last_login) + new_actions_since_last_login.include?(proposed_action.id) if new_actions_since_last_login.present? + end + + def new_resources_since_last_login?(resources, new_actions_since_last_login) + resources.pluck(:id).any? {|id| new_actions_since_last_login.include?(id) } if resources.present? + end + + def active_resources_for(proposal) + default_resources_count = 3 #resources: mail, poster, poll + Dashboard::Action.active.resources.active_for(proposal).count + default_resources_count + end + + def active_resources_count(proposal) + default_resources_count = 3 #resources: mail, poster, poll + Dashboard::Action.active.resources.by_proposal(proposal).count + default_resources_count + end end diff --git a/app/mailers/dashboard/mailer.rb b/app/mailers/dashboard/mailer.rb index e246fb914..f60119a50 100644 --- a/app/mailers/dashboard/mailer.rb +++ b/app/mailers/dashboard/mailer.rb @@ -5,4 +5,32 @@ class Dashboard::Mailer < ApplicationMailer @proposal = proposal mail to: proposal.author.email, subject: proposal.title end + + def new_actions_notification_rake_published(proposal, new_actions_ids) + @proposal = proposal + @new_actions = get_new_actions(new_actions_ids) + mail to: proposal.author.email, subject: I18n.t("mailers.new_actions_notification_rake_published.subject") + end + + def new_actions_notification_rake_created(proposal, new_actions_ids) + @proposal = proposal + @new_actions = get_new_actions(new_actions_ids) + mail to: proposal.author.email, subject: I18n.t("mailers.new_actions_notification_rake_created.subject") + end + + def new_actions_notification_on_create(proposal) + @proposal = proposal + mail to: proposal.author.email, subject: I18n.t("mailers.new_actions_notification_on_create.subject") + end + + def new_actions_notification_on_published(proposal, new_actions_ids) + @proposal = proposal + @new_actions = get_new_actions(new_actions_ids) + mail to: proposal.author.email, subject: I18n.t("mailers.new_actions_notification_on_published.subject") + end + + private + def get_new_actions(new_actions_ids) + Dashboard::Action.where(id: new_actions_ids) + end end diff --git a/app/models/dashboard/action.rb b/app/models/dashboard/action.rb index d0199acd1..3e553d0de 100644 --- a/app/models/dashboard/action.rb +++ b/app/models/dashboard/action.rb @@ -46,6 +46,9 @@ class Dashboard::Action < ActiveRecord::Base scope :by_proposal, lambda { |proposal| return where(published_proposal: false) if proposal.draft? } + scope :by_published_proposal, lambda { |published| + return where(published_proposal: published) + } def self.active_for(proposal) published_at = proposal.published_at&.to_date || Date.today @@ -85,4 +88,44 @@ class Dashboard::Action < ActiveRecord::Base def self.next_goal_for(proposal) course_for(proposal).first end + + def self.detect_new_actions_since(date, proposal) + actions_for_today = get_actions_for_today(proposal) + actions_for_date = get_actions_for_date(proposal, date) + + actions_for_today_ids = actions_for_today.pluck(:id) + actions_for_date_ids = actions_for_date.pluck(:id) + + actions_for_today_ids - actions_for_date_ids + end + + private + def self.get_actions_for_today(proposal) + proposal_votes = proposal.cached_votes_up + day_offset = calculate_day_offset(proposal, Date.today) + + calculate_actions(proposal_votes, day_offset, proposal) + end + + def self.get_actions_for_date(proposal, date) + proposal_votes = calculate_votes(proposal, date) + day_offset = calculate_day_offset(proposal, date) + + calculate_actions(proposal_votes, day_offset, proposal) + end + + def self.calculate_day_offset(proposal, date) + start_date = proposal.published? ? proposal.published_at : proposal.created_at + (date - start_date.to_date).to_i + end + + def self.calculate_actions(proposal_votes, day_offset, proposal) + Dashboard::Action.active.where("required_supports <= ?", proposal_votes) + .where("day_offset <= ?", day_offset) + .by_published_proposal(proposal.published?) + end + + def self.calculate_votes(proposal, date) + Vote.where(votable: proposal).where("created_at <= ?", date).count + end end diff --git a/app/models/poll/question/answer.rb b/app/models/poll/question/answer.rb index 56655e457..48abdd9b8 100644 --- a/app/models/poll/question/answer.rb +++ b/app/models/poll/question/answer.rb @@ -17,8 +17,6 @@ class Poll::Question::Answer < ActiveRecord::Base validates :title, presence: true validates :given_order, presence: true, uniqueness: { scope: :question_id } - before_validation :set_order, on: :create - def description self[:description].try :html_safe end @@ -29,10 +27,6 @@ class Poll::Question::Answer < ActiveRecord::Base end end - def set_order - self.given_order = self.class.last_position(question_id) + 1 - end - def self.last_position(question_id) where(question_id: question_id).maximum('given_order') || 0 end diff --git a/app/models/proposal.rb b/app/models/proposal.rb index e96e49592..95473ed15 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -55,6 +55,8 @@ class Proposal < ActiveRecord::Base before_save :calculate_hot_score, :calculate_confidence_score + after_create :send_new_actions_notification_on_create + scope :for_render, -> { includes(:tags) } scope :sort_by_hot_score, -> { reorder(hot_score: :desc) } scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) } @@ -84,6 +86,7 @@ class Proposal < ActiveRecord::Base def publish update(published_at: Time.now) + send_new_actions_notification_on_published end def published? @@ -236,6 +239,22 @@ class Proposal < ActiveRecord::Base Setting["feature.user.skip_verification"].present? end + def send_new_actions_notification_on_create + new_actions = Dashboard::Action.detect_new_actions_since(Date.yesterday, self) + + if new_actions.present? + Dashboard::Mailer.new_actions_notification_on_create(self).deliver_later + end + end + + def send_new_actions_notification_on_published + new_actions_ids = Dashboard::Action.detect_new_actions_since(Date.yesterday, self) + + if new_actions_ids.present? + Dashboard::Mailer.new_actions_notification_on_published(self, new_actions_ids).deliver_later + end + end + protected def set_responsible_name diff --git a/app/views/admin/poll/questions/answers/_form.html.erb b/app/views/admin/poll/questions/answers/_form.html.erb index 1ca05d9ab..912e6bd42 100644 --- a/app/views/admin/poll/questions/answers/_form.html.erb +++ b/app/views/admin/poll/questions/answers/_form.html.erb @@ -4,6 +4,9 @@ <%= render 'shared/errors', resource: @answer %> + <%= f.hidden_field :given_order, + value: @answer.persisted? ? @answer.given_order : @answer.class.last_position(@answer.question_id || @question.id) + 1 %> + <%= f.hidden_field :question_id, value: @answer.question_id || @question.id %> <%= f.translatable_text_field :title %> diff --git a/app/views/dashboard/_menu.html.erb b/app/views/dashboard/_menu.html.erb index 463ad470c..c6d633e79 100644 --- a/app/views/dashboard/_menu.html.erb +++ b/app/views/dashboard/_menu.html.erb @@ -18,12 +18,18 @@ <%= link_to recommended_actions_proposal_dashboard_path(proposal.to_param) do %> <%= t("dashboard.menu.recommended_actions") %> <% end %> + <% if new_resources_since_last_login?(proposed_actions, @new_actions_since_last_login) %> + <%= t("dashboard.progress.new_action" ) %> + <% end %> <% if resources_menu_visible?(proposal, resources) %>
<%= l(proposed_action.executed_actions.find_by(proposal: proposal).executed_at.to_date) %> diff --git a/app/views/dashboard/_resource.html.erb b/app/views/dashboard/_resource.html.erb index d9a66ac67..7b0f77d35 100644 --- a/app/views/dashboard/_resource.html.erb +++ b/app/views/dashboard/_resource.html.erb @@ -3,12 +3,15 @@ data-equalizer-watch="resources" title="<%= resource_tooltip(resource, proposal) %>">
<%= resource.short_description %>
<%= t("mailers.new_actions_notification_on_create.hi", name: @proposal.author.name) %>
+<%= t("mailers.new_actions_notification_on_create.introduction", title: @proposal.title) %>
+
+ <%= t("mailers.new_actions_notification_on_create.text_1") %>
+
+ <%= t("mailers.new_actions_notification_on_create.text_2", link: proposal_dashboard_url(@proposal)).html_safe %>
+
<%= t("mailers.new_actions_notification_on_create.text_3") %>
+<%= t("mailers.new_actions_notification_on_create.text_4") %>
+
+ <%= t("mailers.new_actions_notification_on_create.text_5") %>
+
+ <%= t("mailers.new_actions_notification_on_create.text_6") %>
+
| + <%= link_to progress_proposal_dashboard_url(@proposal), + style: "font-family: 'Open Sans',arial,sans-serif; background: #3700fd; + border-radius: 6px; color: #fff !important; font-weight: bold; + padding: 17px 20px; text-align: center; text-decoration: none; + font-size: 20px; min-width: 200px; display: inline-block;", + target: "_blank" do %> + <%= t("mailers.new_actions_notification_on_create.dashboard_button") %> + <% end %> + | +
+ <%= t("mailers.new_actions_notification_on_published.hi", + name: @proposal.author.name, + title: @proposal.title) %> +
+
+ <%= t("mailers.new_actions_notification_on_published.text_1") %>
+
+ <%= t("mailers.new_actions_notification_on_published.text_2") %>
+
<%= t("mailers.new_actions_notification_on_published.text_3") %>
+<%= t("mailers.new_actions_notification_on_published.text_4") %>
+<%= t("mailers.new_actions_notification_on_published.text_5") %>
+<%= t("mailers.new_actions_notification_on_published.text_6") %>
+<%= t("mailers.new_actions_notification_on_published.text_7") %>
+ <% first_resource = @new_actions.resources.first %> + <% if first_resource.present? %> +<%= t("mailers.new_actions_notification_on_published.text_8") %>
+<%= t("mailers.new_actions_notification_on_published.text_9") %>
+<%= first_proposed_action.short_description.html_safe %>
+ <% end %> +<%= t("mailers.new_actions_notification_on_published.text_10") %>
+ +| + <%= link_to progress_proposal_dashboard_url(@proposal), + style: "font-family: 'Open Sans',arial,sans-serif; background: #3700fd; + border-radius: 6px; color: #fff !important; font-weight: bold; + padding: 17px 20px; text-align: center; text-decoration: none; + font-size: 20px; min-width: 200px; display: inline-block;", + target: "_blank" do %> + <%= t("mailers.new_actions_notification_on_published.dashboard_button") %> + <% end %> + | +
<%= t("mailers.new_actions_notification_rake_created.hi", name: @proposal.author.name) %>
+ ++ <%= t("mailers.new_actions_notification_rake_created.introduction", + created_at_day: @proposal.created_at.day, + created_at_month: @proposal.created_at.strftime("%B"), + title: @proposal.title) %> +
++ <%= t("mailers.new_actions_notification_rake_created.text_1", + link_to_published: link_to(proposal_dashboard_url(@proposal), + proposal_dashboard_url(@proposal))).html_safe %> +
+<%= t("mailers.new_actions_notification_rake_created.text_2") %>
+<%= t("mailers.new_actions_notification_rake_created.text_3") %>
+ +<%= t("mailers.new_actions_notification_rake_created.text_4") %>
+<%= first_proposed_action.description.html_safe %>
+ <% end %> +<%= t("mailers.new_actions_notification_rake_created.text_5") %>
+<%= t("mailers.new_actions_notification_rake_created.footer_text") %>
+ +| + <%= link_to proposal_dashboard_url(@proposal), + style: "font-family: 'Open Sans',arial,sans-serif; background: #3700fd; + border-radius: 6px; color: #fff !important; font-weight: bold; + padding: 17px 20px; text-align: center; text-decoration: none; + font-size: 20px; min-width: 200px; display: inline-block;", + target: "_blank" do %> + <%= t("mailers.new_actions_notification_rake_created.dashboard_button") %> + <% end %> + | +
<%= t("mailers.new_actions_notification_rake_published.hi", name: @proposal.author.name) %>
++ <%= t("mailers.new_actions_notification_rake_published.introduction", + published_at_day: @proposal.published_at.day, + published_at_month: @proposal.published_at.strftime("%B"), + title: @proposal.title) %> +
+<%= t("mailers.new_actions_notification_rake_published.text_1", votes_count: @proposal.cached_votes_up) %>
+<%= t("mailers.new_actions_notification_rake_published.text_2") %>
+<%= t("mailers.new_actions_notification_rake_published.new_resource") %>
++ <%= t("mailers.new_actions_notification_rake_published.text_3", + days_count: (limit_to_archive_proposal - Date.today).to_i, + max_votes_count: Setting["votes_for_proposal_success"]) %> +
+ + <% first_proposed_action = @new_actions.proposed_actions.first %> + <% if first_proposed_action.present? %> +<%= t("mailers.new_actions_notification_rake_published.text_4") %>
+<%= first_proposed_action.description.html_safe %>
+ <% end %> +<%= t("mailers.new_actions_notification_rake_published.text_5") %>
+<%= t("mailers.new_actions_notification_rake_published.footer_text") %>
+ +| + <%= link_to proposal_dashboard_url(@proposal), + style: "font-family: 'Open Sans',arial,sans-serif; background: #3700fd; + border-radius: 6px; color: #fff !important; font-weight: bold; + padding: 17px 20px; text-align: center; text-decoration: none; + font-size: 20px; min-width: 200px; display: inline-block;", + target: "_blank" do %> + <%= t("mailers.new_actions_notification_rake_published.dashboard_button") %> + <% end %> + | +