diff --git a/Gemfile.lock b/Gemfile.lock index a6437663e..c33459f75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -199,7 +199,7 @@ GEM terminal-table (>= 1.5.1) initialjs-rails (0.2.0.5) railties (>= 3.1, < 6.0) - invisible_captcha (0.9.2) + invisible_captcha (0.9.3) rails (>= 3.2.0) jquery-fileupload-rails (0.4.7) actionpack (>= 3.1) @@ -251,7 +251,7 @@ GEM mime-types-data (3.2016.0521) mimemagic (0.3.2) mini_portile2 (2.2.0) - minitest (5.10.2) + minitest (5.10.3) mixlib-cli (1.7.0) mixlib-config (2.2.4) multi_json (1.12.1) @@ -368,7 +368,7 @@ GEM rspec-mocks (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) - rspec-rails (3.6.0) + rspec-rails (3.6.1) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) @@ -398,7 +398,7 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - savon (2.11.1) + savon (2.11.2) akami (~> 1.2) builder (>= 2.1.2) gyoku (~> 1.2) @@ -430,7 +430,7 @@ GEM babel-source (>= 5.8.11) babel-transpiler sprockets (>= 3.0.0) - sprockets-rails (3.2.0) + sprockets-rails (3.2.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) @@ -565,6 +565,5 @@ DEPENDENCIES web-console (~> 3.3.0) whenever (~> 0.9.7) - BUNDLED WITH 1.15.3 diff --git a/app/assets/images/help/help_icon_budgets.png b/app/assets/images/help/help_icon_budgets.png index f8a909d7e..fc5e3022f 100644 Binary files a/app/assets/images/help/help_icon_budgets.png and b/app/assets/images/help/help_icon_budgets.png differ diff --git a/app/assets/images/help/help_icon_debates.png b/app/assets/images/help/help_icon_debates.png index c8d59e4c1..afc729671 100644 Binary files a/app/assets/images/help/help_icon_debates.png and b/app/assets/images/help/help_icon_debates.png differ diff --git a/app/assets/images/help/help_icon_legislation_processes.png b/app/assets/images/help/help_icon_legislation_processes.png index 9dd93ad8c..00872c247 100644 Binary files a/app/assets/images/help/help_icon_legislation_processes.png and b/app/assets/images/help/help_icon_legislation_processes.png differ diff --git a/app/assets/images/help/help_icon_polls.png b/app/assets/images/help/help_icon_polls.png index 503f8642d..b7f7cf479 100644 Binary files a/app/assets/images/help/help_icon_polls.png and b/app/assets/images/help/help_icon_polls.png differ diff --git a/app/assets/images/help/help_icon_proposals.png b/app/assets/images/help/help_icon_proposals.png index 05861d042..e41db1cf8 100644 Binary files a/app/assets/images/help/help_icon_proposals.png and b/app/assets/images/help/help_icon_proposals.png differ diff --git a/app/assets/images/logo_header.png b/app/assets/images/logo_header.png index 9bce3cef8..c178ec781 100644 Binary files a/app/assets/images/logo_header.png and b/app/assets/images/logo_header.png differ diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 6db475365..19c73de32 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -9,6 +9,7 @@ @import 'pages'; @import 'legislation'; @import 'legislation_process'; +@import 'community'; @import 'custom'; @import 'c3'; @import 'annotator.min'; diff --git a/app/assets/stylesheets/community.scss b/app/assets/stylesheets/community.scss new file mode 100644 index 000000000..0dddf4cdb --- /dev/null +++ b/app/assets/stylesheets/community.scss @@ -0,0 +1,44 @@ +.communities-show { + .button.disabled, .button[disabled] { + pointer-events: none; + } + + .wide-order-selector { + margin-top: 0; + } + + .panel { + min-height: auto; + margin: 0.375rem 0; + + .button { + margin-top: $line-height; + } + } +} + +.communities-participant { + + .comment-body { + display: inline-block; + float: left; + margin-right: $line-height; + margin-bottom: $line-height; + } +} + +.topic-show { + + p, + ul li { + margin-bottom: 0; + } + + .comments { + + .first-comment { + margin-top: $line-height; + margin-bottom: $line-height; + } + } +} diff --git a/app/assets/stylesheets/legislation_process.scss b/app/assets/stylesheets/legislation_process.scss index eda341185..2ec9f8ee9 100644 --- a/app/assets/stylesheets/legislation_process.scss +++ b/app/assets/stylesheets/legislation_process.scss @@ -13,37 +13,29 @@ // // 01. Utils -// ----------------- +// --------- + +$grey-heading: #e6e6e6; +$border-dark: darken($border, 10%); .grey-heading { - background: #e6e6e6; + background: $grey-heading; } -$epigraph-font-size: rem-calc(15); -$epigraph-line-height: rem-calc(22); - // 02. Hero -// ----------------- +// -------- + .legislation-hero { - padding-top: 1.5rem; - - @include breakpoint(medium) { - padding-top: 3.5rem; - } - - h4 { - text-transform: uppercase; - } ul { list-style: none; margin-left: 0; li::before { - vertical-align: text-bottom; - padding-right: 0.5rem; - content: '■'; color: #8aa8be; + content: '■'; + padding-right: $line-height / 4; + vertical-align: text-bottom; } } @@ -52,79 +44,33 @@ $epigraph-line-height: rem-calc(22); } .debate-add-info { - margin-top: 3rem; - padding-top: 4rem; - border-top: 1px solid darken($border, 10%); + border-top: 1px solid $border-dark; + margin-top: $line-height; + padding-top: $line-height; - @include breakpoint(medium) { - margin-bottom: 2rem; - } - - .debate-info-wrapper { - - h2 { - font-size: $lead-font-size; - - @include breakpoint(medium) { - float: left; - } - } - } } - .half-gradient { - background: #e6e6e6; - background: linear-gradient(to bottom, #e6e6e6 0%, #e6e6e6 50%, #fff 50%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e6e6e6', endColorstr='#fff', GradientType=0); - } - - .text-center .button { - background: $brand; - margin-bottom: 0; - } - - .headline { - margin-bottom: 1rem; - - @include breakpoint(medium) { - margin-bottom: 4rem; - - } + .title { + font-weight: bold; + text-transform: uppercase; } .description { - margin-bottom: 1rem; - - p { - font-size: $epigraph-font-size; - line-height: $epigraph-line-height; - } - - ul { - font-size: $epigraph-font-size; - line-height: $epigraph-line-height; - } li { - margin-bottom: 1rem; p { display: inline; - margin-bottom: 0; } } - - h4 { - font-size: $base-font-size; - } } .button-subscribe { - margin-top: 1rem; + margin-top: $line-height; @include breakpoint(medium) { + margin-top: $line-height * 2; padding: 0.5em 1em; - margin-top: 3rem; } h3 { @@ -132,8 +78,8 @@ $epigraph-line-height: rem-calc(22); } p { - margin-bottom: 0; font-size: $small-font-size; + margin-bottom: 0; } &:hover h3 { @@ -143,41 +89,21 @@ $epigraph-line-height: rem-calc(22); } // 03. Legislation process navigation -// ----------------- +// ---------------------------------- + .legislation-process-categories { position: relative; .legislation-process-list { border-bottom: 1px solid $medium-gray; margin: 0 1rem 1rem; - padding-top: 4rem; - - @include breakpoint(medium) { - margin-left: 0; - } ul { - position: relative; - max-width: 75rem; - margin-left: auto; - margin-right: auto; + list-style: none; - padding-left: 0; + margin: 0 auto; margin-bottom: 0; - - @include breakpoint(medium) { - padding-left: 1rem; - } - - svg { - position: absolute; - top: 1.25rem; - - @include breakpoint(1280px) { - transform: rotate(-6deg); - left: -1rem; - } - } + padding-left: 0; } li { @@ -187,6 +113,10 @@ $epigraph-line-height: rem-calc(22); transition: all 0.4s; border-bottom: 2px solid transparent; + @include breakpoint(medium) { + margin-left: $line-height * 2; + } + &:first-of-type { margin-left: 0; } @@ -197,29 +127,25 @@ $epigraph-line-height: rem-calc(22); border-bottom: 2px solid $brand; } - @media (min-width: 950px) { - margin: 0 0 0 3rem; - } - a, h4 { display: block; color: #6d6d6d; margin-bottom: 0; } + } - a { - &:hover, - &:active { - text-decoration: none; - } + a { + &:hover, + &:active { + text-decoration: none; + } - p { - margin-bottom: 0; + p { + margin-bottom: 0; - @include breakpoint(medium) { - margin-bottom: 1rem; - } + @include breakpoint(medium) { + margin-bottom: 1rem; } } } @@ -231,7 +157,8 @@ $epigraph-line-height: rem-calc(22); } // 04. Debate list -// ----------------- +// ---------------- + .debate-chooser { padding: 2rem 1rem; @@ -277,38 +204,43 @@ $epigraph-line-height: rem-calc(22); } // 05. Debate quiz -// ----------------- +// --------------- + .debate-questions { + .comments { - margin-top: 4rem; + margin-top: $line-height * 2.5; } .quiz-header { - margin-bottom: 2rem; + margin-bottom: $line-height; .quiz-title, .quiz-next { - padding: 1rem; - height: 6rem; + padding: $line-height; + + @include breakpoint(medium) { + height: $line-height * 4; + } } .quiz-title { background: #e5ecf2; .quiz-header-title { + font-size: $small-font-size; + font-weight: 700; margin-bottom: 0; text-transform: uppercase; - font-weight: 700; - font-size: $small-font-size; } } h4 a { color: $brand; - } - h4 a:hover { - text-decoration: none; + &:hover { + text-decoration: none; + } } .quiz-next-link { @@ -318,57 +250,49 @@ $epigraph-line-height: rem-calc(22); &:active { text-decoration: none; } + } - .quiz-next { - background: #ccdbe5; - font-weight: 700; - color: $brand; - font-size: $small-font-size; - text-align: right; - text-transform: uppercase; - transition: background 0.25s ease-out, background 0.25s ease-out; + .quiz-next { + background: #ccdbe5; + color: $brand; + font-size: $small-font-size; + font-weight: bold; + text-align: right; + text-transform: uppercase; + transition: background 0.25s ease-out, background 0.25s ease-out; - .icon-angle-right { - vertical-align: sub; - } + .icon-angle-right { + vertical-align: middle; + } - &:hover, - &:active { - text-decoration: none; - background: $brand; - color: #fff; - - .icon-angle-right { - color: #fff; - } - } + &:hover, + &:active { + background: $brand; + color: #fff; + text-decoration: none; } } } .quiz-question { - margin-bottom: 2rem; + margin-bottom: $line-height; } .debate-questions { position: relative; list-style: none; - .participation-not-allowed { - padding-bottom: 3rem; - } - .control { - position: relative; - display: inline-block; - color: #555; - cursor: pointer; background: #fff; border: 1px solid $border; - border-radius: 4px; - padding: 0.75rem 2.5rem; - margin-right: 1.5rem; - margin-bottom: 0.5rem; + border-radius: rem-calc(4); + color: #555; + cursor: pointer; + display: inline-block; + margin-bottom: $line-height / 2; + margin-right: $line-height; + padding: $line-height / 2 $line-height * 2; + position: relative; } .active { @@ -409,14 +333,15 @@ $epigraph-line-height: rem-calc(22); } // 06. Legislation draft -// ----------------- +// --------------------- + .debate-draft { padding: 10rem 2rem 15rem; display: block; background: #f2f2f2; button { - height: 90px; + height: rem-calc(90); h3 { margin-bottom: 0; @@ -430,7 +355,8 @@ $epigraph-line-height: rem-calc(22); } // 07. Legislation allegations -// ----------------- +// --------------------------- + .legislation-allegation { padding-top: 1rem; @@ -449,12 +375,12 @@ $epigraph-line-height: rem-calc(22); .button-circle { line-height: 0; padding: 0; - width: 30px; - height: 30px; + width: rem-calc(30); + height: rem-calc(30); border-radius: 50%; span { - padding-left: 1px; + padding-left: rem-calc(1); &::before { line-height: 1.55; @@ -580,7 +506,7 @@ $epigraph-line-height: rem-calc(22); .calc-comments { cursor: pointer; background: #f2f2f2; - width: 50px; + width: rem-calc(50); .draft-panel { .panel-title { @@ -733,7 +659,7 @@ $epigraph-line-height: rem-calc(22); .comments-on { .calc-index { - width: 50px; + width: rem-calc(50); background: #f2f2f2; cursor: pointer; @@ -797,11 +723,11 @@ $epigraph-line-height: rem-calc(22); .comments-box-container { position: absolute; - top: 230px; + top: rem-calc(230); } .comment-box { - width: 375px; + width: rem-calc(375); padding: 1rem; background: #f9f9f9; border: 1px solid $border; @@ -852,7 +778,7 @@ $epigraph-line-height: rem-calc(22); .participation-not-allowed { font-size: 0.875rem; - height: 50px; + height: rem-calc(50); padding: 0.85rem 0.75rem; top: -18px; } @@ -891,7 +817,7 @@ $epigraph-line-height: rem-calc(22); border-right: 1px solid #d0d0d0; border-left: 1px solid #d0d0d0; width: 100%; - height: 200px; + height: rem-calc(200); margin-bottom: 0.5rem; } diff --git a/app/assets/stylesheets/pages.scss b/app/assets/stylesheets/pages.scss index d3db7e9b2..7114b01d6 100644 --- a/app/assets/stylesheets/pages.scss +++ b/app/assets/stylesheets/pages.scss @@ -44,7 +44,8 @@ // 03. Content // ---------------------- -.more-info-content { +.more-info-content, +.communities-show { h3 { color: $brand; diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 8d79eca55..e10c0327f 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -249,7 +249,9 @@ .proposal-form, .budget-investment-form, .spending-proposal-form, -.document-form { +.document-form, +.topic-new, +.topic-form { .icon-debates, .icon-proposals, @@ -298,6 +300,8 @@ } .proposal-form, +.topic-form, +.topic-new, .document-form { .recommendations li::before { @@ -316,7 +320,9 @@ .debate-quiz, .budget-investment-show, .draft-panels, -.debate-questions { +.debate-questions, +.communities-show, +.topic-show { p { word-wrap: break-word; @@ -350,7 +356,8 @@ .debate-info, .proposal-info, .investment-project-info, - .budget-investment-show { + .budget-investment-show, + .topic-info { clear: both; color: $text-medium; font-size: $small-font-size; @@ -627,7 +634,8 @@ .proposal, .investment-project, .budget-investment, -.legislation { +.legislation, +.communities-show { margin: $line-height / 4 0; .panel { @@ -699,7 +707,8 @@ .debate-info, .proposal-info, .investment-project-info, - .budget-investment-info { + .budget-investment-info, + .topic-info { color: $text-medium; font-size: $small-font-size; margin: rem-calc(6) 0 0; @@ -885,17 +894,10 @@ } } -.help-link { - margin-left: $line-height; - position: relative; +.help-header { - &::before { - color: $link; - content: '\4e'; - font-family: 'icons'; - position: absolute; - left: -24px; - top: -2px; + h1 { + font-size: rem-calc(24); } } diff --git a/app/controllers/admin/poll/officer_assignments_controller.rb b/app/controllers/admin/poll/officer_assignments_controller.rb index 1f2a7ca2c..45c9a225a 100644 --- a/app/controllers/admin/poll/officer_assignments_controller.rb +++ b/app/controllers/admin/poll/officer_assignments_controller.rb @@ -32,35 +32,6 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController end end - def create - @officer_assignment = ::Poll::OfficerAssignment.new(booth_assignment: @booth_assignment, - officer_id: create_params[:officer_id], - date: create_params[:date]) - @officer_assignment.final = true if @officer_assignment.date > @booth_assignment.poll.ends_at.to_date - - if @officer_assignment.save - notice = t("admin.poll_officer_assignments.flash.create") - else - notice = t("admin.poll_officer_assignments.flash.error_create") - end - - redirect_params = { poll_id: create_params[:poll_id], officer_id: create_params[:officer_id] } - redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice - end - - def destroy - @officer_assignment = ::Poll::OfficerAssignment.includes(:booth_assignment).find(params[:id]) - - if @officer_assignment.destroy - notice = t("admin.poll_officer_assignments.flash.destroy") - else - notice = t("admin.poll_officer_assignments.flash.error_destroy") - end - - redirect_params = { poll_id: @officer_assignment.poll_id, officer_id: @officer_assignment.officer_id } - redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice - end - private def officer_assignment_params diff --git a/app/controllers/admin/poll/shifts_controller.rb b/app/controllers/admin/poll/shifts_controller.rb new file mode 100644 index 000000000..8a808a7a9 --- /dev/null +++ b/app/controllers/admin/poll/shifts_controller.rb @@ -0,0 +1,53 @@ +class Admin::Poll::ShiftsController < Admin::BaseController + + before_action :load_booth + before_action :load_polls + + def new + load_officers + load_shifts + @shift = ::Poll::Shift.new + end + + def create + @shift = ::Poll::Shift.new(shift_params) + if @shift.save + notice = t("admin.poll_shifts.flash.create") + redirect_to new_admin_booth_shift_path(@shift.booth), notice: notice + else + load_officers + load_shifts + render :new + end + end + + def destroy + @shift = Poll::Shift.find(params[:id]) + @shift.destroy + notice = t("admin.poll_shifts.flash.destroy") + redirect_to new_admin_booth_shift_path(@booth), notice: notice + end + + private + + def load_booth + @booth = ::Poll::Booth.find(params[:booth_id]) + end + + def load_polls + @polls = ::Poll.current_or_incoming + end + + def load_officers + @officers = ::Poll::Officer.all + end + + def load_shifts + @shifts = @booth.shifts + end + + def shift_params + params.require(:shift).permit(:booth_id, :officer_id, :date) + end + +end \ No newline at end of file diff --git a/app/controllers/communities_controller.rb b/app/controllers/communities_controller.rb new file mode 100644 index 000000000..3462c8425 --- /dev/null +++ b/app/controllers/communities_controller.rb @@ -0,0 +1,30 @@ +class CommunitiesController < ApplicationController + + before_action :set_order, :set_community, :load_topics, :load_participants, only: :show + + has_orders %w{newest most_commented oldest}, only: :show + + skip_authorization_check + + def show + redirect_to root_path unless Setting['feature.community'].present? + end + + private + + def set_order + @order = params[:order].present? ? params[:order] : "newest" + end + + def set_community + @community = Community.find(params[:id]) + end + + def load_topics + @topics = @community.topics.send("sort_by_#{@order}").page(params[:page]) + end + + def load_participants + @participants = @community.participants + end +end diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb new file mode 100644 index 000000000..f0e57a383 --- /dev/null +++ b/app/controllers/topics_controller.rb @@ -0,0 +1,55 @@ +class TopicsController < ApplicationController + include CommentableActions + include FlagActions + + before_action :load_community + before_action :load_topic, only: [:show, :edit, :update] + + has_orders %w{most_voted newest oldest}, only: :show + + skip_authorization_check + + def new + @topic = Topic.new + end + + def create + @topic = Topic.new(topic_params.merge(author: current_user, community_id: params[:community_id])) + if @topic.save + redirect_to community_path(@community), notice: I18n.t('flash.actions.create.topic') + else + render :new + end + end + + def show + @commentable = @topic + @comment_tree = CommentTree.new(@commentable, params[:page], @current_order) + set_comment_flags(@comment_tree.comments) + end + + def edit + end + + def update + if @topic.update(topic_params) + redirect_to community_path(@community), notice: t('flash.actions.update.topic') + else + render :edit + end + end + + private + + def topic_params + params.require(:topic).permit(:title, :description) + end + + def load_community + @community = Community.find(params[:community_id]) + end + + def load_topic + @topic = Topic.find(params[:id]) + end +end diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb index 1936f843c..1ab6c9826 100644 --- a/app/helpers/comments_helper.rb +++ b/app/helpers/comments_helper.rb @@ -42,7 +42,7 @@ module CommentsHelper def commentable_path(comment) commentable = comment.commentable - + case comment.commentable_type when "Budget::Investment" budget_investment_path(commentable.budget_id, commentable) @@ -50,6 +50,8 @@ module CommentsHelper legislation_process_question_path(commentable.process, commentable) when "Legislation::Annotation" legislation_process_draft_version_annotation_path(commentable.draft_version.process, commentable.draft_version, commentable) + when "Topic" + community_topic_path(comment.commentable.community, comment.commentable) else commentable end diff --git a/app/helpers/communities_helper.rb b/app/helpers/communities_helper.rb new file mode 100644 index 000000000..1d50c5388 --- /dev/null +++ b/app/helpers/communities_helper.rb @@ -0,0 +1,42 @@ +module CommunitiesHelper + + def community_title(community) + if community.from_proposal? + community.proposal.title + else + investment = Budget::Investment.where(community_id: community.id).first + investment.title + end + end + + def community_text(community) + community.from_proposal? ? t("community.show.title.proposal") : t("community.show.title.investment") + end + + def community_description(community) + community.from_proposal? ? t("community.show.description.proposal") : t("community.show.description.investment") + end + + def is_author?(community, participant) + if community.from_proposal? + community.proposal.author_id == participant.id + else + investment = Budget::Investment.where(community_id: community.id).first + investment.author_id == participant.id + end + end + + def community_back_link_path(community) + if community.from_proposal? + proposal_path(community.proposal) + else + investment = Budget::Investment.where(community_id: community.id).first + budget_investment_path(investment.budget_id, investment) + end + end + + def community_access_text(community) + community.from_proposal? ? t("community.sidebar.description.proposal") : t("community.sidebar.description.investment") + end + +end diff --git a/app/helpers/shifts_helper.rb b/app/helpers/shifts_helper.rb new file mode 100644 index 000000000..37f22a3e2 --- /dev/null +++ b/app/helpers/shifts_helper.rb @@ -0,0 +1,23 @@ +module ShiftsHelper + + def shift_dates_select_options(polls) + options = [] + (start_date(polls)..end_date(polls)).each do |date| + options << [l(date, format: :long), l(date)] + end + options_for_select(options, params[:date]) + end + + def start_date(polls) + polls.map(&:starts_at).min.to_date + end + + def end_date(polls) + polls.map(&:ends_at).max.to_date + end + + def officer_select_options(officers) + officers.collect { |officer| [officer.name, officer.id] } + end + +end diff --git a/app/helpers/topics_helper.rb b/app/helpers/topics_helper.rb new file mode 100644 index 000000000..1d5f1964f --- /dev/null +++ b/app/helpers/topics_helper.rb @@ -0,0 +1,11 @@ +module TopicsHelper + + def disabled_create_topic + "disabled" unless current_user + end + + def disabled_info_title + t("community.show.sidebar.disabled_info_title") unless current_user + end + +end diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index b8f80c0cd..db4cee09d 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -33,7 +33,7 @@ module Abilities can :unmark_featured, Debate can :comment_as_administrator, [Debate, Comment, Proposal, Poll::Question, Budget::Investment, - Legislation::Question, Legislation::Annotation] + Legislation::Question, Legislation::Annotation, Topic] can [:search, :create, :index, :destroy], ::Administrator can [:search, :create, :index, :destroy], ::Moderator diff --git a/app/models/abilities/moderator.rb b/app/models/abilities/moderator.rb index 796bb185a..4e1427c12 100644 --- a/app/models/abilities/moderator.rb +++ b/app/models/abilities/moderator.rb @@ -6,7 +6,7 @@ module Abilities merge Abilities::Moderation.new(user) can :comment_as_moderator, [Debate, Comment, Proposal, Budget::Investment, Poll::Question, - Legislation::Question, Legislation::Annotation] + Legislation::Question, Legislation::Annotation, Topic] end end end diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 0dfd7836c..d658e7ab2 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -6,6 +6,7 @@ class Budget include Searchable include Reclassification include Followable + include Communitable include Documentable documentable max_documents_allowed: 3, max_file_size: 3.megabytes, diff --git a/app/models/comment.rb b/app/models/comment.rb index 1db9809ee..8b68e11ad 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -3,7 +3,7 @@ class Comment < ActiveRecord::Base include HasPublicAuthor include Graphqlable - COMMENTABLE_TYPES = %w(Debate Proposal Budget::Investment Poll::Question Legislation::Question Legislation::Annotation).freeze + COMMENTABLE_TYPES = %w(Debate Proposal Budget::Investment Poll::Question Legislation::Question Legislation::Annotation Topic).freeze acts_as_paranoid column: :hidden_at include ActsAsParanoidAliases diff --git a/app/models/community.rb b/app/models/community.rb new file mode 100644 index 000000000..710982200 --- /dev/null +++ b/app/models/community.rb @@ -0,0 +1,39 @@ +class Community < ActiveRecord::Base + has_one :proposal + has_one :investment + has_many :topics + + def participants + users_participants = users_who_commented_by + + users_who_topics_author_by + + author_from_community + users_participants.uniq + end + + def from_proposal? + self.proposal.present? + end + + private + + def users_who_commented_by + topics_ids = topics.pluck(:id) + query = "comments.commentable_id IN (?)and comments.commentable_type = 'Topic'" + User.by_comments(query, topics_ids) + end + + def users_who_topics_author_by + author_ids = topics.pluck(:author_id) + User.by_authors(author_ids) + end + + def author_from_community + if from_proposal? + User.where(id: proposal.author_id) + else + investment = Budget::Investment.where(community_id: id).first + User.where(id: investment.author_id) + end + end + +end diff --git a/app/models/concerns/communitable.rb b/app/models/concerns/communitable.rb new file mode 100644 index 000000000..6f0a10f43 --- /dev/null +++ b/app/models/concerns/communitable.rb @@ -0,0 +1,14 @@ +module Communitable + extend ActiveSupport::Concern + + included do + belongs_to :community + before_create :associate_community + end + + def associate_community + community = Community.create + self.community_id = community.id + end + +end diff --git a/app/models/poll.rb b/app/models/poll.rb index 6d033f514..4ba313963 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -35,6 +35,10 @@ class Poll < ActiveRecord::Base ends_at < timestamp end + def self.current_or_incoming + current + incoming + end + def answerable_by?(user) user.present? && user.level_two_or_three_verified? && diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb index c7fb63efc..9edbcbaf0 100644 --- a/app/models/poll/booth.rb +++ b/app/models/poll/booth.rb @@ -2,6 +2,7 @@ class Poll class Booth < ActiveRecord::Base has_many :booth_assignments, class_name: "Poll::BoothAssignment" has_many :polls, through: :booth_assignments + has_many :shifts validates :name, presence: true, uniqueness: true diff --git a/app/models/poll/shift.rb b/app/models/poll/shift.rb new file mode 100644 index 000000000..8ee646ea4 --- /dev/null +++ b/app/models/poll/shift.rb @@ -0,0 +1,22 @@ +class Poll + class Shift < ActiveRecord::Base + belongs_to :booth + belongs_to :officer + + validates :booth_id, presence: true + validates :officer_id, presence: true + validates :date, presence: true + validates :date, uniqueness: { scope: [:officer_id, :booth_id] } + + after_create :create_officer_assignments + + def create_officer_assignments + booth.booth_assignments.each do |booth_assignment| + attrs = { officer_id: officer_id, + date: date, + booth_assignment_id: booth_assignment.id } + Poll::OfficerAssignment.create!(attrs) + end + end + end + end \ No newline at end of file diff --git a/app/models/proposal.rb b/app/models/proposal.rb index bb8ddfa29..82aa627cc 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -9,6 +9,7 @@ class Proposal < ActiveRecord::Base include HasPublicAuthor include Graphqlable include Followable + include Communitable include Documentable documentable max_documents_allowed: 3, max_file_size: 3.megabytes, diff --git a/app/models/topic.rb b/app/models/topic.rb new file mode 100644 index 000000000..8c8f3f6c9 --- /dev/null +++ b/app/models/topic.rb @@ -0,0 +1,20 @@ +class Topic < ActiveRecord::Base + include Flaggable + + acts_as_paranoid column: :hidden_at + include ActsAsParanoidAliases + + belongs_to :community + belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' + + has_many :comments, as: :commentable + + validates :title, presence: true + validates :description, presence: true + validates :author, presence: true + + scope :sort_by_newest, -> { order(created_at: :desc) } + scope :sort_by_oldest, -> { order(created_at: :asc) } + scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } + +end diff --git a/app/models/user.rb b/app/models/user.rb index 21b526963..427683298 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -57,11 +57,13 @@ class User < ActiveRecord::Base scope :officials, -> { where("official_level > 0") } scope :newsletter, -> { where(newsletter: true) } scope :for_render, -> { includes(:organization) } - scope :by_document, ->(document_type, document_number) { where(document_type: document_type, document_number: document_number) } + scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) } scope :email_digest, -> { where(email_digest: true) } scope :active, -> { where(erased_at: nil) } scope :erased, -> { where.not(erased_at: nil) } scope :public_for_api, -> { all } + scope :by_comments, -> (query, topics_ids) { joins(:comments).where(query, topics_ids).uniq } + scope :by_authors, -> (author_ids) { where("users.id IN (?)", author_ids) } before_validation :clean_document_number diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 62638f3b7..b42e717b4 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -73,9 +73,13 @@ <%= link_to t('admin.menu.poll_officers'), admin_officers_path %> -
| <%= t("admin.poll_shifts.new.date") %> | +<%= t("admin.poll_shifts.new.officer") %> | +<%= t("admin.poll_shifts.new.assignment") %> | +
|---|---|---|
| <%= l(shift.date.to_date, format: :long) %> | +<%= shift.officer.name %> | ++ <%= link_to t("admin.poll_shifts.new.remove_assignment"), + admin_booth_shift_path(@booth, shift), + method: :delete, + class: "button hollow alert" %> + | +
+ <%= community_access_text(community) %> +
+ <%= link_to t("community.sidebar.button_to_access"), community_path(community.id), class: 'button hollow expanded' %> +<% end %> diff --git a/app/views/communities/_participants.html.erb b/app/views/communities/_participants.html.erb new file mode 100644 index 000000000..931ebf105 --- /dev/null +++ b/app/views/communities/_participants.html.erb @@ -0,0 +1,41 @@ +<%= community_title(@community) %>
+<%= community_description(@community) %>
+<%= t('legislation.processes.header_full.description') %>
<%= markdown process.description %> <% end %>