Merge branch 'master' into community-design

This commit is contained in:
decabeza
2017-11-21 20:52:05 +01:00
553 changed files with 14905 additions and 5928 deletions

View File

@@ -11,3 +11,6 @@ insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.yml]
insert_final_newline = false

View File

@@ -1,6 +1,8 @@
inherit_from: .rubocop_todo.yml
AllCops:
DisplayCopNames: true
DisplayStyleGuide: true
Include:
- '**/Rakefile'
- '**/config.ru'

View File

@@ -1,12 +1,12 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2017-07-07 21:23:30 +0200 using RuboCop version 0.49.1.
# on 2017-10-17 22:05:23 +0200 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 45
# Offense count: 40
# Cop supports --auto-correct.
# Configuration parameters: EnforcedHashRocketStyle, SupportedHashRocketStyles, EnforcedColonStyle, SupportedColonStyles, EnforcedLastArgumentHashStyle, SupportedLastArgumentHashStyles.
# SupportedHashRocketStyles: key, separator, table
@@ -14,11 +14,10 @@
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
Layout/AlignHash:
Exclude:
- 'app/controllers/officing/results_controller.rb'
- 'spec/controllers/legislation/annotations_controller_spec.rb'
- 'spec/features/admin/banners_spec.rb'
# Offense count: 50
# Offense count: 52
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation
@@ -33,7 +32,7 @@ Layout/ClosingParenthesisIndentation:
- 'spec/models/legislation/annotation_spec.rb'
- 'spec/rails_helper.rb'
# Offense count: 51
# Offense count: 37
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: leading, trailing
@@ -68,11 +67,10 @@ Layout/EmptyLines:
Exclude:
- 'app/controllers/admin/budget_investment_milestones_controller.rb'
# Offense count: 2
# Offense count: 1
# Cop supports --auto-correct.
Layout/EmptyLinesAroundMethodBody:
Exclude:
- 'app/models/abilities/administrator.rb'
- 'lib/graph_ql/api_types_creator.rb'
# Offense count: 2
@@ -126,13 +124,13 @@ Layout/IndentationConsistency:
- 'spec/models/legislation/draft_version_spec.rb'
- 'spec/models/proposal_spec.rb'
# Offense count: 23
# Offense count: 48
# Cop supports --auto-correct.
# Configuration parameters: Width, IgnoredPatterns.
Layout/IndentationWidth:
Enabled: false
# Offense count: 7
# Offense count: 6
# Cop supports --auto-correct.
Layout/LeadingCommentSpace:
Exclude:
@@ -140,7 +138,6 @@ Layout/LeadingCommentSpace:
- 'app/controllers/budgets/ballot/lines_controller.rb'
- 'spec/features/budgets/ballots_spec.rb'
- 'spec/features/comments/poll_questions_spec.rb'
- 'spec/features/officing/voters_spec.rb'
- 'spec/support/common_actions.rb'
# Offense count: 3
@@ -181,7 +178,7 @@ Layout/MultilineMethodCallBraceLayout:
- 'spec/models/legislation/annotation_spec.rb'
- 'spec/rails_helper.rb'
# Offense count: 71
# Offense count: 59
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
@@ -201,7 +198,7 @@ Layout/MultilineMethodCallIndentation:
- 'spec/models/proposal_spec.rb'
- 'spec/models/user_spec.rb'
# Offense count: 8
# Offense count: 7
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented
@@ -264,29 +261,11 @@ Lint/LiteralInCondition:
Exclude:
- 'app/models/budget/investment.rb'
# Offense count: 51
Lint/ParenthesesAsGroupedExpression:
Exclude:
- 'spec/factories.rb'
- 'spec/features/admin/organizations_spec.rb'
- 'spec/features/budgets/investments_spec.rb'
- 'spec/features/campaigns_spec.rb'
- 'spec/features/debates_spec.rb'
- 'spec/features/management/managed_users_spec.rb'
- 'spec/features/management/proposals_spec.rb'
- 'spec/features/management/spending_proposals_spec.rb'
- 'spec/features/management/users_spec.rb'
- 'spec/features/proposals_spec.rb'
- 'spec/models/debate_spec.rb'
# Offense count: 13
# Offense count: 3
# Cop supports --auto-correct.
Lint/StringConversionInInterpolation:
Exclude:
- 'app/models/poll/null_result.rb'
- 'app/models/poll/partial_result.rb'
- 'app/models/poll/white_result.rb'
- 'app/models/poll/total_result.rb'
# Offense count: 15
# Cop supports --auto-correct.
@@ -311,7 +290,7 @@ Lint/UnusedMethodArgument:
- 'app/mailers/mailer.rb'
- 'app/models/abilities/everyone.rb'
# Offense count: 278
# Offense count: 325
Lint/UselessAssignment:
Enabled: false
@@ -320,35 +299,46 @@ Lint/Void:
Exclude:
- 'app/controllers/polls_controller.rb'
# Offense count: 74
# Offense count: 86
Metrics/AbcSize:
Max: 54
Max: 64
# Offense count: 454
# Offense count: 487
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 1071
# Offense count: 8
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 256
Max: 1227
# Offense count: 10
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 262
# Offense count: 13
Metrics/CyclomaticComplexity:
Max: 10
# Offense count: 53
# Offense count: 25
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 248
# Offense count: 67
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 49
Max: 56
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/ModuleLength:
Max: 214
Max: 242
# Offense count: 7
# Offense count: 3
# Configuration parameters: CountKeywordArgs.
Metrics/ParameterLists:
Max: 7
# Offense count: 8
Metrics/PerceivedComplexity:
Max: 11
@@ -402,20 +392,20 @@ Rails/HttpPositionalArguments:
- 'spec/controllers/pages_controller_spec.rb'
- 'spec/controllers/users/registrations_controller_spec.rb'
# Offense count: 20
# Offense count: 18
Rails/OutputSafety:
Exclude:
- 'app/controllers/admin/legislation/draft_versions_controller.rb'
- 'app/controllers/admin/legislation/processes_controller.rb'
- 'app/controllers/admin/legislation/questions_controller.rb'
- 'app/controllers/budgets/investments_controller.rb'
- 'app/controllers/direct_uploads_controller.rb'
- 'app/controllers/spending_proposals_controller.rb'
- 'app/helpers/application_helper.rb'
- 'app/helpers/text_with_links_helper.rb'
- 'app/helpers/users_helper.rb'
- 'app/helpers/valuation_helper.rb'
# Offense count: 70
# Offense count: 71
# Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations:
@@ -431,7 +421,7 @@ Style/AccessorMethodName:
- 'app/controllers/proposals_controller.rb'
- 'lib/merged_comment_tree.rb'
# Offense count: 1
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent
@@ -441,7 +431,7 @@ Style/BracesAroundHashParameters:
- 'spec/features/budgets/investments_spec.rb'
- 'spec/features/proposals_spec.rb'
# Offense count: 119
# Offense count: 123
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
@@ -454,20 +444,13 @@ Style/ClassVars:
- 'app/models/organization.rb'
- 'app/models/user.rb'
# Offense count: 6
# Cop supports --auto-correct.
Style/ColonMethodCall:
Exclude:
- 'spec/models/budget/investment_spec.rb'
# Offense count: 12
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Exclude:
- 'app/controllers/admin/poll/booth_assignments_controller.rb'
- 'app/controllers/admin/poll/officer_assignments_controller.rb'
- 'app/controllers/admin/poll/questions_controller.rb'
- 'app/controllers/comments_controller.rb'
- 'app/controllers/management/spending_proposals_controller.rb'
@@ -480,12 +463,6 @@ Style/DoubleNegation:
Exclude:
- 'app/models/flag.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/EmptyCaseCondition:
Exclude:
- 'app/models/concerns/verification.rb'
# Offense count: 2
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
@@ -499,7 +476,7 @@ Style/FileName:
Style/GuardClause:
Enabled: false
# Offense count: 12
# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: MaxLineLength.
Style/IfUnlessModifier:
@@ -510,37 +487,23 @@ Style/IfUnlessModifier:
- 'app/controllers/legislation/annotations_controller.rb'
- 'app/controllers/valuation/budget_investments_controller.rb'
- 'app/controllers/verification/letter_controller.rb'
- 'app/controllers/welcome_controller.rb'
- 'app/helpers/embed_videos_helper.rb'
- 'app/mailers/mailer.rb'
- 'app/models/proposal.rb'
- 'app/models/spending_proposal.rb'
# Offense count: 4
# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: line_count_dependent, lambda, literal
Style/Lambda:
Exclude:
- 'app/models/comment.rb'
- 'app/models/concerns/followable.rb'
- 'app/models/direct_message.rb'
- 'app/models/vote.rb'
- 'lib/graph_ql/api_types_creator.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/MethodCallWithoutArgsParentheses:
Exclude:
- 'app/controllers/management/document_verifications_controller.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline
Style/MethodDefParentheses:
Exclude:
- 'spec/helpers/comments_helper_spec.rb'
# Offense count: 1
Style/MultilineBlockChain:
Exclude:
@@ -552,17 +515,14 @@ Style/MultilineIfThen:
Exclude:
- 'app/controllers/management/users_controller.rb'
# Offense count: 15
# Offense count: 13
# Cop supports --auto-correct.
Style/MutableConstant:
Exclude:
- 'app/models/activity.rb'
- 'app/models/budget/reclassified_vote.rb'
- 'app/models/legislation/draft_version.rb'
- 'app/models/poll/null_result.rb'
- 'app/models/poll/partial_result.rb'
- 'app/models/poll/white_result.rb'
- 'app/models/poll/total_result.rb'
- 'app/models/proposal.rb'
- 'app/models/signature_sheet.rb'
- 'app/models/site_customization/content_block.rb'
@@ -572,32 +532,13 @@ Style/MutableConstant:
- 'lib/tag_sanitizer.rb'
- 'lib/wysiwyg_sanitizer.rb'
# Offense count: 29
# Cop supports --auto-correct.
Style/NestedParenthesizedCalls:
Exclude:
- 'spec/features/debates_spec.rb'
- 'spec/features/emails_spec.rb'
- 'spec/features/valuation/budget_investments_spec.rb'
- 'spec/features/valuation/spending_proposals_spec.rb'
- 'spec/helpers/settings_helper_spec.rb'
- 'spec/helpers/verification_helper_spec.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Exclude:
- 'app/controllers/officing/results_controller.rb'
# Offense count: 54
# Cop supports --auto-correct.
# Configuration parameters: Strict.
Style/NumericLiterals:
MinDigits: 9
# Offense count: 19
# Offense count: 20
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
@@ -625,16 +566,7 @@ Style/ParallelAssignment:
- 'lib/active_model/dates.rb'
- 'spec/support/common_actions.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: AllowSafeAssignment.
Style/ParenthesesAroundCondition:
Exclude:
- 'app/controllers/proposals_controller.rb'
- 'app/models/debate.rb'
- 'app/models/proposal.rb'
# Offense count: 11
# Offense count: 10
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
# NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_
@@ -648,7 +580,6 @@ Style/PredicateName:
- 'app/helpers/debates_helper.rb'
- 'app/models/budget/ballot.rb'
- 'app/models/user.rb'
- 'lib/census_api.rb'
# Offense count: 4
# Cop supports --auto-correct.
@@ -668,18 +599,14 @@ Style/RedundantBegin:
- 'app/controllers/graphql_controller.rb'
- 'app/models/legislation/annotation.rb'
# Offense count: 55
# Cop supports --auto-correct.
Style/RedundantParentheses:
Enabled: false
# Offense count: 3
# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Exclude:
- 'app/helpers/embed_videos_helper.rb'
- 'app/models/poll/question/answer/video.rb'
- 'spec/customization_engine_spec.rb'
# Offense count: 6
@@ -698,38 +625,16 @@ Style/SafeNavigation:
Exclude:
- 'app/models/signature.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation:
Exclude:
- 'spec/features/budgets/investments_spec.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Exclude:
- 'app/controllers/legislation/answers_controller.rb'
# Offense count: 9
# Configuration parameters: SupportedStyles.
# SupportedStyles: snake_case, camelCase
Style/VariableName:
EnforcedStyle: snake_case
# Offense count: 107
# Offense count: 93
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: snake_case, normalcase, non_integer
Style/VariableNumber:
Enabled: false
# Offense count: 31
# Offense count: 34
# Cop supports --auto-correct.
# Configuration parameters: SupportedStyles, WordRegex.
# SupportedStyles: percent, brackets
Style/WordArray:
EnforcedStyle: percent
MinSize: 9
MinSize: 8

View File

@@ -4,6 +4,7 @@ addons:
rvm:
- "2.3.2"
cache: bundler
bundler_args: --without development
before_script:
- "for i in config/*.example; do cp \"$i\" \"${i/.example}\"; done"
- bundle exec rake db:setup
@@ -15,4 +16,4 @@ env:
- CI_NODE_TOTAL=2
matrix:
- CI_NODE_INDEX=0
- CI_NODE_INDEX=1
- CI_NODE_INDEX=1

View File

@@ -5,8 +5,9 @@
* Raimond García [github](https://github.com/voodoorai2000) | [twitter](https://twitter.com/voodoorai2000)
* Juanjo Bazán [github](https://github.com/xuanxu) | [twitter](https://twitter.com/xuanxu)
* Enrique García Cota [github](https://github.com/kikito) | [twitter](https://twitter.com/otikik)
* Alberto García Cabeza [github](https://github.com/decabeza) | [twitter](https://twitter.com/decabeza)
* Alberto García Cabeza [github](https://github.com/decabeza)
* Alberto Calderón [github](https://github.com/bertocq) | [twitter](https://twitter.com/bertocq)
* Maria Checa [github](https://github.com/MariaCheca)
## Code of conduct

View File

@@ -5,8 +5,9 @@
* Raimond García [github](https://github.com/voodoorai2000) | [twitter](https://twitter.com/voodoorai2000)
* Juanjo Bazán [github](https://github.com/xuanxu) | [twitter](https://twitter.com/xuanxu)
* Enrique García Cota [github](https://github.com/kikito) | [twitter](https://twitter.com/otikik)
* Alberto García Cabeza [github](https://github.com/decabeza) | [twitter](https://twitter.com/decabeza)
* Alberto García Cabeza [github](https://github.com/decabeza)
* Alberto Calderón [github](https://github.com/bertocq) | [twitter](https://twitter.com/bertocq)
* Maria Checa [github](https://github.com/MariaCheca)
## Código de conducta

37
Dockerfile Normal file
View File

@@ -0,0 +1,37 @@
# # Select ubuntu as the base image
FROM coreapps/ruby2.3
# Install essential Linux packages
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev postgresql-client nodejs
# Define where our application will live inside the image
ENV RAILS_ROOT /var/www/consul
# Create application home. App server will need the pids dir so just create everything in one shot
RUN mkdir -p $RAILS_ROOT/tmp/pids
# Set our working directory inside the image
WORKDIR $RAILS_ROOT
# Use the Gemfiles as Docker cache markers. Always bundle before copying app src.
# (the src likely changed and we don't want to invalidate Docker's cache too early)
# http://ilikestuffblog.com/2014/01/06/how-to-skip-bundle-install-when-deploying-a-rails-app-to-docker/
COPY Gemfile Gemfile
COPY Gemfile.lock Gemfile.lock
COPY Gemfile_custom Gemfile_custom
# Prevent bundler warnings; ensure that the bundler version executed is >= that which created Gemfile.lock
RUN gem install bundler
# Finish establishing our Ruby enviornment
RUN bundle install --full-index
# Copy the Rails application into place
COPY . .
# Define the script we want run once the container boots
# Use the "exec" form of CMD so our script shuts down gracefully on SIGTERM (i.e. `docker stop`)
#CMD [ "config/containers/app_cmd.sh" ]
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]

18
Gemfile
View File

@@ -1,6 +1,6 @@
source 'https://rubygems.org'
gem 'rails', '4.2.9'
gem 'rails', '4.2.10'
gem 'acts-as-taggable-on', '~> 4.0.0'
gem 'acts_as_votable', '~> 0.10.0'
@@ -37,7 +37,6 @@ gem 'paperclip', '~> 5.1.0'
gem 'paranoia', '~> 2.3.1'
gem 'pg', '~> 0.21.0'
gem 'pg_search', '~> 2.0.1'
gem 'rails-assets-markdown-it', '~> 8.2.1', source: 'https://rails-assets.org'
gem 'redcarpet', '~> 3.4.0'
gem 'responders', '~> 2.4.0'
gem 'rinku', '~> 2.0.2', require: 'rails_rinku'
@@ -54,17 +53,21 @@ gem 'uglifier', '~> 3.2.0'
gem 'unicorn', '~> 5.3.0'
gem 'whenever', '~> 0.9.7', require: false
source 'https://rails-assets.org' do
gem 'rails-assets-leaflet'
gem 'rails-assets-markdown-it', '~> 8.2.1'
end
group :development, :test do
gem "bullet", '~> 5.5.1'
gem 'byebug', '~> 9.0.6'
gem 'bullet', '~> 5.5.1'
gem 'byebug', '~> 9.1.0'
gem 'factory_girl_rails', '~> 4.8.0'
gem "faker", '~> 1.7.3'
gem 'faker', '~> 1.7.3'
gem 'i18n-tasks', '~> 0.9.15'
gem 'knapsack', '~> 1.13.3'
gem 'launchy', '~> 2.4.3'
gem 'letter_opener_web', '~> 1.3.1'
gem 'quiet_assets', '~> 1.1.0'
gem 'rubocop', '~> 0.49.1', require: false
gem 'spring', '~> 2.0.1'
gem 'spring-commands-rspec', '~> 1.0.4'
end
@@ -81,9 +84,10 @@ end
group :development do
gem 'capistrano', '~> 3.8.1', require: false
gem 'capistrano-bundler', '~> 1.2', require: false
gem "capistrano-rails", '~> 1.2.3', require: false
gem 'capistrano-rails', '~> 1.2.3', require: false
gem 'capistrano3-delayed-job', '~> 1.7.3'
gem 'mdl', '~> 0.4.0', require: false
gem 'rubocop', '~> 0.49.1', require: false
gem 'rvm1-capistrano3', '~> 1.4.0', require: false
gem 'scss_lint', '~> 0.54.0', require: false
gem 'web-console', '~> 3.3.0'

View File

@@ -2,36 +2,36 @@ GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
specs:
actionmailer (4.2.9)
actionpack (= 4.2.9)
actionview (= 4.2.9)
activejob (= 4.2.9)
actionmailer (4.2.10)
actionpack (= 4.2.10)
actionview (= 4.2.10)
activejob (= 4.2.10)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.9)
actionview (= 4.2.9)
activesupport (= 4.2.9)
actionpack (4.2.10)
actionview (= 4.2.10)
activesupport (= 4.2.10)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.9)
activesupport (= 4.2.9)
actionview (4.2.10)
activesupport (= 4.2.10)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (4.2.9)
activesupport (= 4.2.9)
activejob (4.2.10)
activesupport (= 4.2.10)
globalid (>= 0.3.0)
activemodel (4.2.9)
activesupport (= 4.2.9)
activemodel (4.2.10)
activesupport (= 4.2.10)
builder (~> 3.1)
activerecord (4.2.9)
activemodel (= 4.2.9)
activesupport (= 4.2.9)
activerecord (4.2.10)
activemodel (= 4.2.10)
activesupport (= 4.2.10)
arel (~> 6.0)
activesupport (4.2.9)
activesupport (4.2.10)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
@@ -71,7 +71,7 @@ GEM
bullet (5.5.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
byebug (9.0.6)
byebug (9.1.0)
cancancan (1.16.0)
capistrano (3.8.2)
airbrussh (>= 1.0.0)
@@ -117,6 +117,7 @@ GEM
term-ansicolor (~> 1.3)
thor (~> 0.19.4)
tins (~> 1.6)
crass (1.0.3)
daemons (1.2.4)
dalli (2.7.6)
database_cleaner (1.6.1)
@@ -172,7 +173,7 @@ GEM
railties (>= 4.1)
tzinfo (~> 1.2, >= 1.2.2)
geocoder (1.4.4)
globalid (0.4.0)
globalid (0.4.1)
activesupport (>= 4.2.0)
graphiql-rails (1.4.2)
rails
@@ -187,7 +188,8 @@ GEM
httpi (2.4.2)
rack
socksify
i18n (0.8.6)
i18n (0.9.1)
concurrent-ruby (~> 1.0)
i18n-tasks (0.9.18)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
@@ -239,10 +241,11 @@ GEM
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
loofah (2.0.3)
loofah (2.1.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.6.6)
mime-types (>= 1.16, < 4)
mail (2.7.0)
mini_mime (>= 0.1.1)
mdl (0.4.0)
kramdown (~> 1.12, >= 1.12.0)
mixlib-cli (~> 1.7, >= 1.7.0)
@@ -251,7 +254,8 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_portile2 (2.2.0)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.10.3)
mixlib-cli (1.7.0)
mixlib-config (2.2.4)
@@ -262,8 +266,8 @@ GEM
net-ssh (>= 2.6.5)
net-ssh (4.1.0)
newrelic_rpm (4.1.0.333)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
nori (2.6.0)
oauth (0.5.3)
oauth2 (1.4.0)
@@ -323,17 +327,18 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.9)
actionmailer (= 4.2.9)
actionpack (= 4.2.9)
actionview (= 4.2.9)
activejob (= 4.2.9)
activemodel (= 4.2.9)
activerecord (= 4.2.9)
activesupport (= 4.2.9)
rails (4.2.10)
actionmailer (= 4.2.10)
actionpack (= 4.2.10)
actionview (= 4.2.10)
activejob (= 4.2.10)
activemodel (= 4.2.10)
activerecord (= 4.2.10)
activesupport (= 4.2.10)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.9)
railties (= 4.2.10)
sprockets-rails
rails-assets-leaflet (1.1.0)
rails-assets-markdown-it (8.2.2)
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
@@ -343,15 +348,15 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
railties (4.2.9)
actionpack (= 4.2.9)
activesupport (= 4.2.9)
railties (4.2.10)
actionpack (= 4.2.10)
activesupport (= 4.2.10)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
raindrops (0.18.0)
rake (12.0.0)
rake (12.2.1)
redcarpet (3.4.0)
referer-parser (0.3.0)
request_store (1.3.2)
@@ -455,7 +460,7 @@ GEM
rack (>= 1.3, < 3)
rack-accept (~> 0.4)
tilt (>= 1.4, < 3)
tzinfo (1.2.3)
tzinfo (1.2.4)
thread_safe (~> 0.1)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
@@ -493,7 +498,7 @@ DEPENDENCIES
ancestry (~> 2.2.2)
browser (~> 2.3.0)
bullet (~> 5.5.1)
byebug (~> 9.0.6)
byebug (~> 9.1.0)
cancancan (~> 1.16.0)
capistrano (~> 3.8.1)
capistrano-bundler (~> 1.2)
@@ -541,7 +546,8 @@ DEPENDENCIES
pg_search (~> 2.0.1)
poltergeist (~> 1.15.0)
quiet_assets (~> 1.1.0)
rails (= 4.2.9)
rails (= 4.2.10)
rails-assets-leaflet!
rails-assets-markdown-it (~> 8.2.1)!
redcarpet (~> 3.4.0)
responders (~> 2.4.0)
@@ -567,4 +573,4 @@ DEPENDENCIES
whenever (~> 0.9.7)
BUNDLED WITH
1.15.3
1.15.4

View File

@@ -76,3 +76,8 @@ Code published under AFFERO GPL v3 (see [LICENSE-AGPLv3.txt](LICENSE-AGPLv3.txt)
## Contributions
See [CONTRIBUTING.md](CONTRIBUTING.md)
## Local development with Docker
Please check the documentation at https://consul_docs.gitbooks.io/docs/content

Binary file not shown.

View File

@@ -62,4 +62,12 @@
<glyph glyph-name="expand" unicode="&#48;" d="M26 168l-26-158c0-2 1-5 3-7 0 0 0 0 0 0 2-2 5-3 7-3l158 27c3 0 6 3 7 6 1 3 0 7-3 9l-30 31 82 82c4 4 4 9 0 13l-57 57c-3 3-9 3-12 0l-83-83-31 31c-2 2-5 3-9 2-3-1-5-4-6-7z m460 176l26 158c0 2-1 5-3 7 0 0 0 0 0 0-2 2-5 3-7 3l-158-27c-3 0-6-3-7-6-1-3 0-7 3-9l30-31-82-82c-4-4-4-9 0-13l57-57c3-3 9-3 12 0l83 83 31-31c2-2 5-3 9-2 3 1 5 4 6 7z"/>
<glyph glyph-name="telegram" unicode="&#49;" d="M504 509c6-5 9-11 8-18l-73-439c-1-6-4-10-10-13-2-2-5-2-8-2-3 0-5 0-7 1l-130 53-69-84c-3-5-8-7-14-7-2 0-4 0-6 1-4 1-7 4-9 7-2 3-3 6-3 10l0 100 247 303-306-265-113 47c-7 2-10 7-11 15 0 8 3 14 9 17l476 274c2 2 5 3 9 3 4 0 7-1 10-3z"/>
<glyph glyph-name="instagram" unicode="&#50;" d="M426 105l0 185-39 0c4-12 6-25 6-38 0-24-6-46-18-66-13-20-29-36-50-48-21-12-44-18-69-18-37 0-69 13-96 39-27 26-40 57-40 93 0 13 2 26 6 38l-41 0 0-185c0-5 2-10 5-13 4-3 8-5 13-5l305 0c5 0 9 2 13 5 3 3 5 8 5 13z m-81 152c0 23-9 44-26 60-18 17-38 25-63 25-24 0-45-8-62-25-17-16-26-37-26-60 0-24 9-44 26-61 17-16 38-25 62-25 25 0 45 9 63 25 17 17 26 37 26 61z m81 103l0 47c0 5-2 10-6 14-4 4-8 6-14 6l-50 0c-5 0-10-2-14-6-4-4-5-9-5-14l0-47c0-6 1-10 5-14 4-4 9-6 14-6l50 0c6 0 10 2 14 6 4 4 6 8 6 14z m49 59l0-326c0-16-5-29-16-40-11-11-24-16-40-16l-326 0c-16 0-29 5-40 16-11 11-16 24-16 40l0 326c0 16 5 29 16 40 11 11 24 16 40 16l326 0c16 0 29-5 40-16 11-11 16-24 16-40z"/>
<glyph glyph-name="image" unicode="&#51;" d="M165 347c0-15-6-28-16-38-11-11-24-16-39-16-16 0-28 5-39 16-11 10-16 23-16 38 0 16 5 29 16 39 11 11 23 16 39 16 15 0 28-5 39-16 10-10 16-23 16-39z m292-109l0-128-402 0 0 55 91 91 46-46 146 147z m28 201l-458 0c-2 0-4-1-6-3-2-2-3-4-3-6l0-348c0-2 1-4 3-6 2-2 4-3 6-3l458 0c2 0 4 1 6 3 2 2 3 4 3 6l0 348c0 2-1 4-3 6-2 2-4 3-6 3z m45-9l0-348c0-12-4-23-13-32-9-9-20-13-32-13l-458 0c-12 0-23 4-32 13-9 9-13 20-13 32l0 348c0 12 4 23 13 32 9 9 20 13 32 13l458 0c12 0 23-4 32-13 9-9 13-20 13-32z"/>
<glyph glyph-name="search-plus" unicode="&#52;" d="M311 283l0-18c0-2-1-4-3-6-2-2-4-3-6-3l-64 0 0-64c0-2-1-5-3-6-2-2-4-3-6-3l-19 0c-2 0-4 1-6 3-2 1-3 4-3 6l0 64-64 0c-2 0-4 1-6 3-2 2-3 4-3 6l0 18c0 3 1 5 3 7 2 2 4 3 6 3l64 0 0 64c0 2 1 4 3 6 2 2 4 3 6 3l19 0c2 0 4-1 6-3 2-2 3-4 3-6l0-64 64 0c2 0 4-1 6-3 2-2 3-4 3-7z m36-9c0 36-12 66-37 91-25 25-55 37-91 37-35 0-65-12-90-37-25-25-38-55-38-91 0-35 13-65 38-90 25-25 55-38 90-38 36 0 66 13 91 38 25 25 37 55 37 90z m147-237c0-11-4-19-11-26-7-7-16-11-26-11-10 0-19 4-26 11l-98 98c-34-24-72-36-114-36-27 0-53 5-78 16-25 11-46 25-64 43-18 18-32 39-43 64-10 25-16 51-16 78 0 28 6 54 16 78 11 25 25 47 43 65 18 18 39 32 64 43 25 10 51 15 78 15 28 0 54-5 79-15 24-11 46-25 64-43 18-18 32-40 43-65 10-24 16-50 16-78 0-42-12-80-36-114l98-98c7-7 11-15 11-25z"/>
<glyph glyph-name="search-minus" unicode="&#53;" d="M311 283l0-18c0-2-1-4-3-6-2-2-4-3-6-3l-165 0c-2 0-4 1-6 3-2 2-3 4-3 6l0 18c0 3 1 5 3 7 2 2 4 3 6 3l165 0c2 0 4-1 6-3 2-2 3-4 3-7z m36-9c0 36-12 66-37 91-25 25-55 37-91 37-35 0-65-12-90-37-25-25-38-55-38-91 0-35 13-65 38-90 25-25 55-38 90-38 36 0 66 13 91 38 25 25 37 55 37 90z m147-237c0-11-4-19-11-26-7-7-16-11-26-11-10 0-19 4-26 11l-98 98c-34-24-72-36-114-36-27 0-53 5-78 16-25 11-46 25-64 43-18 18-32 39-43 64-10 25-16 51-16 78 0 28 6 54 16 78 11 25 25 47 43 65 18 18 39 32 64 43 25 10 51 15 78 15 28 0 54-5 79-15 24-11 46-25 64-43 18-18 32-40 43-65 10-24 16-50 16-78 0-42-12-80-36-114l98-98c7-7 11-15 11-25z"/>
<glyph glyph-name="calculator" unicode="&#54;" d="M110 73c0 10-4 19-11 26-7 7-16 11-26 11-10 0-19-4-26-11-7-7-10-16-10-26 0-10 3-19 10-26 7-7 16-10 26-10 10 0 19 3 26 10 7 7 11 16 11 26z m109 0c0 10-3 19-10 26-7 7-16 11-26 11-10 0-19-4-26-11-7-7-11-16-11-26 0-10 4-19 11-26 7-7 16-10 26-10 10 0 19 3 26 10 7 7 10 16 10 26z m-109 110c0 10-4 19-11 26-7 7-16 10-26 10-10 0-19-3-26-10-7-7-10-16-10-26 0-10 3-19 10-26 7-7 16-11 26-11 10 0 19 4 26 11 7 7 11 16 11 26z m219-110c0 10-3 19-11 26-7 7-15 11-25 11-11 0-19-4-26-11-7-7-11-16-11-26 0-10 4-19 11-26 7-7 15-10 26-10 10 0 18 3 25 10 8 7 11 16 11 26z m-110 110c0 10-3 19-10 26-7 7-16 10-26 10-10 0-19-3-26-10-7-7-11-16-11-26 0-10 4-19 11-26 7-7 16-11 26-11 10 0 19 4 26 11 7 7 10 16 10 26z m-109 110c0 10-4 18-11 25-7 8-16 11-26 11-10 0-19-3-26-11-7-7-10-15-10-25 0-11 3-19 10-26 7-7 16-11 26-11 10 0 19 4 26 11 7 7 11 15 11 26z m219-110c0 10-3 19-11 26-7 7-15 10-25 10-11 0-19-3-26-10-7-7-11-16-11-26 0-10 4-19 11-26 7-7 15-11 26-11 10 0 18 4 25 11 8 7 11 16 11 26z m-110 110c0 10-3 18-10 25-7 8-16 11-26 11-10 0-19-3-26-11-7-7-11-15-11-25 0-11 4-19 11-26 7-7 16-11 26-11 10 0 19 4 26 11 7 7 10 15 10 26z m220-220l0 110c0 10-4 18-11 26-7 7-16 10-26 10-10 0-18-3-25-10-8-8-11-16-11-26l0-110c0-10 3-18 11-26 7-7 15-10 25-10 10 0 19 3 26 10 7 8 11 16 11 26z m-110 220c0 10-3 18-11 25-7 8-15 11-25 11-11 0-19-3-26-11-7-7-11-15-11-25 0-11 4-19 11-26 7-7 15-11 26-11 10 0 18 4 25 11 8 7 11 15 11 26z m110 91l0 73c0 5-2 9-6 13-3 4-7 5-12 5l-366 0c-5 0-9-1-13-5-4-4-5-8-5-13l0-73c0-5 1-9 5-13 4-3 8-5 13-5l366 0c5 0 9 2 12 5 4 4 6 8 6 13z m0-91c0 10-4 18-11 25-7 8-16 11-26 11-10 0-18-3-26-11-7-7-10-15-10-25 0-11 3-19 10-26 8-7 16-11 26-11 10 0 19 4 26 11 7 7 11 15 11 26z m36 182l0-438c0-10-3-19-10-26-8-7-16-11-26-11l-402 0c-10 0-19 4-26 11-7 7-11 16-11 26l0 438c0 10 4 19 11 26 7 7 16 11 26 11l402 0c10 0 18-4 26-11 7-7 10-16 10-26z"/>
<glyph glyph-name="map-marker" unicode="&#55;" d="M329 329c0 20-7 38-21 52-15 14-32 21-52 21-20 0-37-7-52-21-14-14-21-32-21-52 0-20 7-37 21-52 15-14 32-21 52-21 20 0 37 7 52 21 14 15 21 32 21 52z m73 0c0-21-3-38-9-51l-104-221c-3-6-8-11-14-15-6-4-12-5-19-5-7 0-13 1-19 5-6 4-11 9-14 15l-104 221c-6 13-9 30-9 51 0 41 14 75 43 104 28 28 63 42 103 42 40 0 75-14 103-42 29-29 43-63 43-104z"/>
<glyph glyph-name="user-plus" unicode="&#56;" d="M165 256c-31 0-57 11-78 32-21 22-32 47-32 78 0 30 11 56 32 77 21 22 47 32 78 32 30 0 56-10 77-32 22-21 32-47 32-77 0-31-10-56-32-78-21-21-47-32-77-32z m274-37l100 0c3 0 5 0 7-2 2-2 3-4 3-7l0-55c0-2-1-4-3-6-2-2-4-3-7-3l-100 0 0-100c0-3-1-5-3-7-2-2-4-2-6-2l-55 0c-3 0-5 0-7 2-1 2-2 4-2 7l0 100-101 0c-2 0-4 1-6 3-2 2-3 4-3 6l0 55c0 3 1 5 3 7 2 2 4 2 6 2l101 0 0 101c0 2 1 5 2 6 2 2 4 3 7 3l55 0c2 0 4-1 6-3 2-1 3-4 3-6z m-210-64c0-9 3-18 10-25 8-8 16-11 26-11l73 0 0-68c-13-10-29-14-49-14l-249 0c-23 0-42 6-56 19-14 13-21 32-21 55 0 10 1 20 1 29 1 10 2 20 4 31 2 11 5 22 8 31 3 10 7 19 12 28 5 9 11 17 18 23 7 7 15 12 24 16 10 3 21 5 32 5 4 0 8-1 11-5 15-11 30-20 45-26 14-6 30-8 47-8 17 0 32 2 47 8 14 6 29 15 44 26 4 4 7 5 11 5 25 0 46-9 62-27l-64 0c-10 0-18-4-26-11-7-7-10-16-10-26z"/>
<glyph glyph-name="file-text-o" unicode="&#57;" d="M456 403c5-5 10-12 14-21 4-9 5-18 5-25l0-330c0-7-2-14-8-19-5-5-11-8-19-8l-384 0c-8 0-14 3-19 8-6 5-8 12-8 19l0 458c0 7 2 14 8 19 5 5 11 8 19 8l256 0c8 0 16-2 25-6 9-4 17-8 22-13z m-127 70l0-107 108 0c-2 5-4 9-7 11l-89 90c-2 2-6 4-12 6z m110-436l0 292-119 0c-8 0-14 3-19 8-6 5-8 12-8 20l0 118-220 0 0-438z m-293 246c0 3 1 5 3 7 2 2 4 3 6 3l202 0c2 0 4-1 6-3 2-2 3-4 3-7l0-18c0-3-1-5-3-6-2-2-4-3-6-3l-202 0c-2 0-4 1-6 3-2 1-3 3-3 6z m211-64c2 0 4 0 6-2 2-2 3-4 3-7l0-18c0-3-1-5-3-7-2-1-4-2-6-2l-202 0c-2 0-4 1-6 2-2 2-3 4-3 7l0 18c0 3 1 5 3 7 2 2 4 2 6 2z m0-73c2 0 4-1 6-2 2-2 3-4 3-7l0-18c0-3-1-5-3-7-2-1-4-2-6-2l-202 0c-2 0-4 1-6 2-2 2-3 4-3 7l0 18c0 3 1 5 3 7 2 1 4 2 6 2z"/>
<glyph glyph-name="file-text" unicode="&#33;" d="M456 376c3-3 5-6 8-10l-135 0 0 135c4-3 8-6 10-8z m-136-47l155 0 0-302c0-7-2-14-8-19-5-5-11-8-19-8l-384 0c-8 0-14 3-19 8-6 5-8 12-8 19l0 458c0 7 2 14 8 19 5 5 11 8 19 8l229 0 0-155c0-8 2-15 8-20 5-5 11-8 19-8z m46-210l0 18c0 3-1 5-3 7-2 1-4 2-6 2l-202 0c-2 0-4-1-6-2-2-2-3-4-3-7l0-18c0-3 1-5 3-7 2-1 4-2 6-2l202 0c2 0 4 1 6 2 2 2 3 4 3 7z m0 73l0 18c0 3-1 5-3 7-2 2-4 2-6 2l-202 0c-2 0-4 0-6-2-2-2-3-4-3-7l0-18c0-3 1-5 3-7 2-1 4-2 6-2l202 0c2 0 4 1 6 2 2 2 3 4 3 7z m0 73l0 18c0 3-1 5-3 7-2 2-4 3-6 3l-202 0c-2 0-4-1-6-3-2-2-3-4-3-7l0-18c0-3 1-5 3-6 2-2 4-3 6-3l202 0c2 0 4 1 6 3 2 1 3 3 3 6z"/>
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -14,6 +14,8 @@
//= require jquery_ujs
//= require jquery-ui/widgets/datepicker
//= require jquery-ui/i18n/datepicker-es
//= require jquery-ui/widgets/autocomplete
//= require jquery-ui/widgets/sortable
//= require jquery-fileupload/basic
//= require foundation
//= require turbolinks
@@ -62,8 +64,15 @@
//= require followable
//= require flaggable
//= require documentable
//= require imageable
//= require tree_navigator
//= require custom
//= require tag_autocomplete
//= require polls_admin
//= require leaflet
//= require map
//= require polls
//= require sortable
var initialize_modules = function() {
App.Comments.initialize();
@@ -98,10 +107,16 @@ var initialize_modules = function() {
App.WatchFormChanges.initialize();
App.TreeNavigator.initialize();
App.Documentable.initialize();
App.Imageable.initialize();
App.TagAutocomplete.initialize();
App.PollsAdmin.initialize();
App.Map.initialize();
App.Polls.initialize();
App.Sortable.initialize();
};
$(function(){
Turbolinks.enableProgressBar()
Turbolinks.enableProgressBar();
$(document).ready(initialize_modules);
$(document).on('page:load', initialize_modules);

View File

@@ -1,101 +1,156 @@
App.Documentable =
initialize: ->
@initializeDirectUploads()
@initializeInterface()
initializeDirectUploads: ->
inputFiles = $('.js-document-attachment')
$.each inputFiles, (index, input) ->
App.Documentable.initializeDirectUploadInput(input)
$('input.js-document-attachment[type=file]').fileupload
$('#nested-documents').on 'cocoon:after-remove', (e, insertedItem) ->
App.Documentable.unlockUploads()
paramName: "document[attachment]"
$('#nested-documents').on 'cocoon:after-insert', (e, nested_document) ->
input = $(nested_document).find('.js-document-attachment')
App.Documentable.initializeDirectUploadInput(input)
if $(nested_document).closest('#nested-documents').find('.document:visible').length >= $('#nested-documents').data('max-documents-allowed')
App.Documentable.lockUploads()
initializeDirectUploadInput: (input) ->
inputData = @buildData([], input)
@initializeRemoveCachedDocumentLink(input, inputData)
$(input).fileupload
paramName: "attachment"
formData: null
add: (e, data) ->
wrapper = $(e.target).closest('.document')
index = $(e.target).data('index')
is_nested_document = $(e.target).data('nested-document')
$(wrapper).find('.progress-bar-placeholder').empty()
data.progressBar = $(wrapper).find('.progress-bar-placeholder').html('<div class="progress-bar"><div class="loading-bar uploading"></div></div>')
$(wrapper).find('.progress-bar-placeholder').css('display','block')
data.formData = {
"document[title]": $(wrapper).find('input.document-title').val() || data.files[0].name
"index": index,
"nested_document": is_nested_document
}
data = App.Documentable.buildFileUploadData(e, data)
App.Documentable.clearProgressBar(data)
App.Documentable.setProgressBar(data, 'uploading')
data.submit()
change: (e, data) ->
wrapper = $(e.target).parent()
$.each(data.files, (index, file)->
$(wrapper).find('.file-name').text(file.name)
)
$.each data.files, (index, file) ->
App.Documentable.setFilename(inputData, file.name)
fail: (e, data) ->
$(data.cachedAttachmentField).val("")
App.Documentable.clearFilename(data)
App.Documentable.setProgressBar(data, 'errors')
App.Documentable.clearInputErrors(data)
App.Documentable.setInputErrors(data)
$(data.destroyAttachmentLinkContainer).find("a.delete:not(.remove-nested)").remove()
$(data.addAttachmentLabel).addClass('error')
$(data.addAttachmentLabel).show()
done: (e, data) ->
$(data.cachedAttachmentField).val(data.result.cached_attachment)
App.Documentable.setTitleFromFile(data, data.result.filename)
App.Documentable.setProgressBar(data, 'complete')
App.Documentable.setFilename(data, data.result.filename)
App.Documentable.clearInputErrors(data)
$(data.addAttachmentLabel).hide()
$(data.wrapper).find(".attachment-actions").removeClass('small-12').addClass('small-6 float-right')
$(data.wrapper).find(".attachment-actions .action-remove").removeClass('small-3').addClass('small-12')
destroyAttachmentLink = $(data.result.destroy_link)
$(data.destroyAttachmentLinkContainer).html(destroyAttachmentLink)
$(destroyAttachmentLink).on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
App.Documentable.doDeleteCachedAttachmentRequest(this.href, data)
progress: (e, data) ->
progress = parseInt(data.loaded / data.total * 100, 10)
$(data.progressBar).find('.loading-bar').css 'width', progress + '%'
return
initializeInterface: ->
input_files = $('input.js-document-attachment[type=file]')
buildFileUploadData: (e, data) ->
data = @buildData(data, e.target)
return data
$.each input_files, (index, file) ->
wrapper = $(file).parent()
App.Documentable.watchRemoveDocumentbutton(wrapper)
buildData: (data, input) ->
wrapper = $(input).closest('.direct-upload')
data.input = input
data.wrapper = wrapper
data.progressBar = $(wrapper).find('.progress-bar-placeholder')
data.errorContainer = $(wrapper).find('.attachment-errors')
data.fileNameContainer = $(wrapper).find('p.file-name')
data.destroyAttachmentLinkContainer = $(wrapper).find('.action-remove')
data.addAttachmentLabel = $(wrapper).find('.action-add label')
data.cachedAttachmentField = $(wrapper).find("input[name$='[cached_attachment]']")
data.titleField = $(wrapper).find("input[name$='[title]']")
$(wrapper).find('.progress-bar-placeholder').css('display', 'block')
return data
watchRemoveDocumentbutton: (wrapper) ->
remove_document_button = $(wrapper).find('.remove-document')
$(remove_document_button).on 'click', (e) ->
clearFilename: (data) ->
$(data.fileNameContainer).text('')
$(data.fileNameContainer).hide()
clearInputErrors: (data) ->
$(data.errorContainer).find('small.error').remove()
clearProgressBar: (data) ->
$(data.progressBar).find('.loading-bar').removeClass('complete errors uploading').css('width', "0px")
setFilename: (data, file_name) ->
$(data.fileNameContainer).text(file_name)
$(data.fileNameContainer).show()
setProgressBar: (data, klass) ->
$(data.progressBar).find('.loading-bar').addClass(klass)
setTitleFromFile: (data, title) ->
if $(data.titleField).val() == ""
$(data.titleField).val(title)
setInputErrors: (data) ->
errors = '<small class="error">' + data.jqXHR.responseJSON.errors + '</small>'
$(data.errorContainer).append(errors)
lockUploads: ->
$('#max-documents-notice').removeClass('hide')
$('#new_document_link').addClass('hide')
unlockUploads: ->
$('#max-documents-notice').addClass('hide')
$('#new_document_link').removeClass('hide')
doDeleteCachedAttachmentRequest: (url, data) ->
$.ajax
type: "POST"
url: url
dataType: "json"
data: { "_method": "delete" }
complete: ->
$(data.cachedAttachmentField).val("")
$(data.addAttachmentLabel).show()
App.Documentable.clearFilename(data)
App.Documentable.clearInputErrors(data)
App.Documentable.clearProgressBar(data)
App.Documentable.unlockUploads()
$(data.wrapper).find(".attachment-actions").addClass('small-12').removeClass('small-6 float-right')
$(data.wrapper).find(".attachment-actions .action-remove").addClass('small-3').removeClass('small-12')
if $(data.input).data('nested-document') == true
$(data.wrapper).remove()
else
$(data.wrapper).find('a.remove-cached-attachment').remove()
initializeRemoveCachedDocumentLink: (input, data) ->
wrapper = $(input).closest(".direct-upload")
remove_document_link = $(wrapper).find('a.remove-cached-attachment')
$(remove_document_link).on 'click', (e) ->
e.preventDefault()
$(wrapper).remove()
$('#new_document_link').show()
$('.max-documents-notice').hide()
e.stopPropagation()
App.Documentable.doDeleteCachedAttachmentRequest(this.href, data)
uploadNestedDocument: (id, nested_document, result) ->
$('#' + id).replaceWith(nested_document)
@updateLoadingBar(id, result)
@initialize()
uploadPlainDocument: (id, nested_document, result) ->
$('#' + id).replaceWith(nested_document)
@updateLoadingBar(id, result)
@initialize()
updateLoadingBar: (id, result) ->
if result
$('#' + id).find('.loading-bar').addClass 'complete'
else
$('#' + id).find('.loading-bar').addClass 'errors'
$('#' + id).find('.progress-bar-placeholder').css('display','block')
new: (nested_fields) ->
$(".documents-list").append(nested_fields)
@initialize()
destroyNestedDocument: (id, notice) ->
removeDocument: (id) ->
$('#' + id).remove()
@updateNotice(notice)
replacePlainDocument: (id, notice, plain_document) ->
$('#' + id).replaceWith(plain_document)
@updateNotice(notice)
@initialize()
updateNotice: (notice) ->
if $('[data-alert]').length > 0
$('[data-alert]').replaceWith(notice)
else
$("body").append(notice)
updateNewDocumentButton: (link) ->
if $('.document').length >= $('.documents').data('max-documents')
$('#new_document_link').hide()
$('.max-documents-notice').removeClass('hide')
$('.max-documents-notice').show()
else if $('#new_document_link').length > 0
$('#new_document_link').replaceWith(link)
$('.max-documents-notice').hide()
else
$('.max-documents-notice').hide()
$(link).insertBefore('.documents hr:last')

View File

@@ -0,0 +1,166 @@
App.Imageable =
initialize: ->
inputFiles = $('.js-image-attachment')
$.each inputFiles, (index, input) ->
App.Imageable.initializeDirectUploadInput(input)
$('#nested-image').on 'cocoon:after-remove', (e, item) ->
$("#new_image_link").removeClass('hide')
$('#nested-image').on 'cocoon:before-insert', (e, nested_image) ->
if $(".js-image-attachment").length > 0
$(".js-image-attachment").closest('.image').remove()
$('#nested-image').on 'cocoon:after-insert', (e, nested_image) ->
$("#new_image_link").addClass('hide')
input = $(nested_image).find('.js-image-attachment')
App.Imageable.initializeDirectUploadInput(input)
initializeDirectUploadInput: (input) ->
inputData = @buildData([], input)
@initializeRemoveCachedImageLink(input, inputData)
$(input).fileupload
paramName: "attachment"
formData: null
add: (e, data) ->
data = App.Imageable.buildFileUploadData(e, data)
App.Imageable.clearProgressBar(data)
App.Imageable.setProgressBar(data, 'uploading')
data.submit()
change: (e, data) ->
$.each data.files, (index, file) ->
App.Imageable.setFilename(inputData, file.name)
fail: (e, data) ->
$(data.cachedAttachmentField).val("")
App.Imageable.clearFilename(data)
App.Imageable.setProgressBar(data, 'errors')
App.Imageable.clearInputErrors(data)
App.Imageable.setInputErrors(data)
App.Imageable.clearPreview(data)
$(data.destroyAttachmentLinkContainer).find("a.delete:not(.remove-nested)").remove()
$(data.addAttachmentLabel).addClass('error')
$(data.addAttachmentLabel).show()
done: (e, data) ->
$(data.cachedAttachmentField).val(data.result.cached_attachment)
App.Imageable.setTitleFromFile(data, data.result.filename)
App.Imageable.setProgressBar(data, 'complete')
App.Imageable.setFilename(data, data.result.filename)
App.Imageable.clearInputErrors(data)
$(data.addAttachmentLabel).hide()
$(data.wrapper).find(".attachment-actions").removeClass('small-12').addClass('small-6 float-right')
$(data.wrapper).find(".attachment-actions .action-remove").removeClass('small-3').addClass('small-12')
App.Imageable.setPreview(data)
destroyAttachmentLink = $(data.result.destroy_link)
$(data.destroyAttachmentLinkContainer).html(destroyAttachmentLink)
$(destroyAttachmentLink).on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
App.Imageable.doDeleteCachedAttachmentRequest(this.href, data)
progress: (e, data) ->
progress = parseInt(data.loaded / data.total * 100, 10)
$(data.progressBar).find('.loading-bar').css 'width', progress + '%'
return
buildFileUploadData: (e, data) ->
data = @buildData(data, e.target)
return data
buildData: (data, input) ->
wrapper = $(input).closest('.direct-upload')
data.input = input
data.wrapper = wrapper
data.progressBar = $(wrapper).find('.progress-bar-placeholder')
data.preview = $(wrapper).find('.image-preview')
data.errorContainer = $(wrapper).find('.attachment-errors')
data.fileNameContainer = $(wrapper).find('p.file-name')
data.destroyAttachmentLinkContainer = $(wrapper).find('.action-remove')
data.addAttachmentLabel = $(wrapper).find('.action-add label')
data.cachedAttachmentField = $(wrapper).find("input[name$='[cached_attachment]']")
data.titleField = $(wrapper).find("input[name$='[title]']")
$(wrapper).find('.progress-bar-placeholder').css('display', 'block')
return data
clearFilename: (data) ->
$(data.fileNameContainer).text('')
$(data.fileNameContainer).hide()
clearInputErrors: (data) ->
$(data.errorContainer).find('small.error').remove()
clearProgressBar: (data) ->
$(data.progressBar).find('.loading-bar').removeClass('complete errors uploading').css('width', "0px")
clearPreview: (data) ->
$(data.wrapper).find('.image-preview').remove()
setFilename: (data, file_name) ->
$(data.fileNameContainer).text(file_name)
$(data.fileNameContainer).show()
setProgressBar: (data, klass) ->
$(data.progressBar).find('.loading-bar').addClass(klass)
setTitleFromFile: (data, title) ->
if $(data.titleField).val() == ""
$(data.titleField).val(title)
setInputErrors: (data) ->
errors = '<small class="error">' + data.jqXHR.responseJSON.errors + '</small>'
$(data.errorContainer).append(errors)
setPreview: (data) ->
image_preview = '<div class="small-12 column text-center image-preview"><figure><img src="' + data.result.attachment_url + '" class="cached-image"/></figure></div>'
if $(data.preview).length > 0
$(data.preview).replaceWith(image_preview)
else
$(image_preview).insertBefore($(data.wrapper).find(".attachment-actions"))
data.preview = $(data.wrapper).find('.image-preview')
doDeleteCachedAttachmentRequest: (url, data) ->
$.ajax
type: "POST"
url: url
dataType: "json"
data: { "_method": "delete" }
complete: ->
$(data.cachedAttachmentField).val("")
$(data.addAttachmentLabel).show()
App.Imageable.clearFilename(data)
App.Imageable.clearInputErrors(data)
App.Imageable.clearProgressBar(data)
App.Imageable.clearPreview(data)
$('#new_image_link').removeClass('hide')
$(data.wrapper).find(".attachment-actions").addClass('small-12').removeClass('small-6 float-right')
$(data.wrapper).find(".attachment-actions .action-remove").addClass('small-3').removeClass('small-12')
if $(data.input).data('nested-image') == true
$(data.wrapper).remove()
else
$(data.wrapper).find('a.remove-cached-attachment').remove()
initializeRemoveCachedImageLink: (input, data) ->
wrapper = $(input).closest(".direct-upload")
remove_image_link = $(wrapper).find('a.remove-cached-attachment')
$(remove_image_link).on 'click', (e) ->
e.preventDefault()
e.stopPropagation()
App.Imageable.doDeleteCachedAttachmentRequest(this.href, data)
removeImage: (id) ->
$('#' + id).remove()
$("#new_image_link").removeClass('hide')

View File

@@ -0,0 +1,78 @@
App.Map =
initialize: ->
maps = $('*[data-map]')
if maps.length > 0
$.each maps, (index, map) ->
App.Map.initializeMap map
initializeMap: (element) ->
mapCenterLatitude = $(element).data('map-center-latitude')
mapCenterLongitude = $(element).data('map-center-longitude')
markerLatitude = $(element).data('marker-latitude')
markerLongitude = $(element).data('marker-longitude')
zoom = $(element).data('map-zoom')
mapTilesProvider = $(element).data('map-tiles-provider')
mapAttribution = $(element).data('map-tiles-provider-attribution')
latitudeInputSelector = $(element).data('latitude-input-selector')
longitudeInputSelector = $(element).data('longitude-input-selector')
zoomInputSelector = $(element).data('zoom-input-selector')
removeMarkerSelector = $(element).data('marker-remove-selector')
editable = $(element).data('marker-editable')
marker = null;
markerIcon = L.divIcon(
className: 'map-marker'
iconSize: [30, 30]
iconAnchor: [15, 40]
html: '<div class="map-icon"></div>')
createMarker = (latitude, longitude) ->
markerLatLng = new (L.LatLng)(latitude, longitude)
marker = L.marker(markerLatLng, { icon: markerIcon, draggable: editable })
if editable
marker.on 'dragend', updateFormfields
marker.addTo(map)
return marker
removeMarker = (e) ->
e.preventDefault()
if marker
map.removeLayer(marker)
marker = null;
clearFormfields()
return
moveOrPlaceMarker = (e) ->
if marker
marker.setLatLng(e.latlng)
else
marker = createMarker(e.latlng.lat, e.latlng.lng)
updateFormfields()
return
updateFormfields = ->
$(latitudeInputSelector).val marker.getLatLng().lat
$(longitudeInputSelector).val marker.getLatLng().lng
$(zoomInputSelector).val map.getZoom()
return
clearFormfields = ->
$(latitudeInputSelector).val ''
$(longitudeInputSelector).val ''
$(zoomInputSelector).val ''
return
mapCenterLatLng = new (L.LatLng)(mapCenterLatitude, mapCenterLongitude)
map = L.map(element.id).setView(mapCenterLatLng, zoom)
L.tileLayer(mapTilesProvider, attribution: mapAttribution).addTo map
if markerLatitude && markerLongitude
marker = createMarker(markerLatitude, markerLongitude)
if editable
$(removeMarkerSelector).on 'click', removeMarker
map.on 'zoomend', updateFormfields
map.on 'click', moveOrPlaceMarker

View File

@@ -0,0 +1,44 @@
App.Polls =
generateToken: ->
token = ''
rand = ''
for n in [0..5]
rand = Math.random().toString(36).substr(2) # remove `0.`
token = token + rand;
token = token.substring(0, 64)
return token
replaceToken: ->
for link in $('.js-question-answer')
token_param = link.search.slice(-6)
if token_param == "token="
link.href = link.href + @token
initialize: ->
@token = App.Polls.generateToken()
App.Polls.replaceToken()
$(".js-question-answer").on
click: =>
token_message = $(".js-token-message")
if !token_message.is(':visible')
token_message.html(token_message.html() + "<br><strong>" + @token + "</strong>");
token_message.show()
false
$(".zoom-link").on "click", (event) ->
element = event.target
answer = $(element).closest('div.answer')
if $(answer).hasClass('medium-6')
$(answer).removeClass("medium-6");
$(answer).addClass("answer-divider");
unless $(answer).hasClass('first')
$(answer).insertBefore($(answer).prev('div.answer'));
else
$(answer).addClass("medium-6");
$(answer).removeClass("answer-divider");
unless $(answer).hasClass('first')
$(answer).insertAfter($(answer).next('div.answer'));

View File

@@ -0,0 +1,12 @@
App.PollsAdmin =
initialize: ->
$("select[class='js-poll-shifts']").on
change: ->
switch ($(this).val())
when 'vote_collection'
$("select[class='js-shift-vote-collection-dates']").show();
$("select[class='js-shift-recount-scrutiny-dates']").hide();
when 'recount_scrutiny'
$("select[class='js-shift-recount-scrutiny-dates']").show();
$("select[class='js-shift-vote-collection-dates']").hide();

View File

@@ -22,11 +22,13 @@ App.PreventDoubleSubmission =
initialize: ->
$('form').on('submit', (event) ->
buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.disable_buttons(buttons)
).on('ajax:success', ->
buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.reset_buttons(buttons)
unless event.target.id == "new_officing_voter"
buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.disable_buttons(buttons)
).on('ajax:success', (event) ->
unless event.target.id == "new_officing_voter"
buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.reset_buttons(buttons)
)
false

View File

@@ -0,0 +1,9 @@
App.Sortable =
initialize: ->
$(".sortable").sortable
update: (event, ui) ->
new_order = $(this).sortable('toArray', {attribute: 'data-answer-id'});
$.ajax
url: $('.sortable').data('js-url'),
data: {ordered_list: new_order},
type: 'POST'

View File

@@ -0,0 +1,34 @@
App.TagAutocomplete =
split: ( val ) ->
return (val.split( /,\s*/ ))
extractLast: ( term ) ->
return (App.TagAutocomplete.split( term ).pop())
init_autocomplete: ->
$('.tag-autocomplete').autocomplete
source: (request, response) ->
$.ajax
url: $('.tag-autocomplete').data('js-url'),
data: {search: App.TagAutocomplete.extractLast( request.term )},
type: 'GET',
dataType: 'json'
success: ( data ) ->
response( data );
minLength: 0,
search: ->
App.TagAutocomplete.extractLast( this.value );
focus: ->
return false;
select: ( event, ui ) -> (
terms = App.TagAutocomplete.split( this.value );
terms.pop();
terms.push( ui.item.value );
terms.push( "" );
this.value = terms.join( ", " );
return false;);
initialize: ->
App.TagAutocomplete.init_autocomplete();

View File

@@ -75,3 +75,5 @@ $accordion-content-color: foreground($accordion-background, $text);
$tab-item-font-size: $base-font-size;
$tab-item-padding: $line-height / 2 0;
$tab-content-border: $border;
$orbit-bullet-diameter: 0.8rem;

View File

@@ -8,38 +8,105 @@
// 06. Polls
// 07. Legislation
// 08. CMS
// 09. Map
//
// 01. Global styles
// -----------------
$admin-color: #cf3638;
$admin-color: #245b80;
$sidebar: #245b80;
$sidebar-hover: #25597c;
$sidebar-active: #f4fcd0;
.admin {
h2 {
font-weight: 100;
margin-bottom: $line-height;
&.title {
text-transform: uppercase;
}
}
.back {
float: none;
}
.header {
border: 0;
}
.top-links {
background: darken($admin-color, 15%);
}
.back-web {
padding-top: $line-height / 4;
text-decoration: underline;
background: #000;
}
.top-bar {
background: $admin-color !important;
background: #fff !important;
border-bottom: 1px solid #eee;
box-shadow: 0 2px 2px #eee;
color: #000;
height: auto;
[class^="icon-"]:not(.icon-circle) {
font-size: $base-font-size;
}
}
.top-bar-title {
h1 {
margin-bottom: 0;
margin-top: $line-height / 2;
@include breakpoint(medium) {
margin-left: $line-height / 2;
}
small {
color: #000;
text-transform: uppercase;
}
}
a {
color: #000 !important;
line-height: $line-height !important;
@include breakpoint(medium) {
line-height: $line-height !important;
}
}
}
.top-bar .menu > li {
@include breakpoint(medium) {
height: auto !important;
padding-top: $line-height / 2;
}
a {
color: #000 !important;
}
}
.menu-icon.dark {
&::after,
&:hover::after {
background: #000 !important;
box-shadow: 0 7px 0 #000, 0 14px 0 #000 !important;
}
}
.notifications .icon-circle {
color: $admin-color;
}
.dropdown.menu > .is-dropdown-submenu-parent > a::after {
border-color: #000 transparent transparent;
}
.fieldset {
@@ -54,7 +121,8 @@ $admin-color: #cf3638;
}
}
th, td {
th,
td {
text-align: left;
&.text-center {
@@ -81,6 +149,7 @@ $admin-color: #cf3638;
}
table {
.break {
word-break: break-word;
}
@@ -107,9 +176,19 @@ $admin-color: #cf3638;
max-width: none;
}
.menu.simple .active {
border-bottom: 2px solid $admin-color;
color: $admin-color;
.menu.simple {
margin-bottom: $line-height / 2;
h2 {
font-weight: bold;
margin-bottom: $line-height / 3;
}
.active {
border-bottom: 2px solid $admin-color;
color: $admin-color;
font-weight: bold;
}
}
.tabs-panel {
@@ -195,6 +274,8 @@ $admin-color: #cf3638;
// -----------
.admin-sidebar {
background: $sidebar;
background: linear-gradient(to bottom, #245b80 0%, #488fb5 100%);
border-right: 1px solid $border;
@include breakpoint(medium) {
@@ -208,7 +289,7 @@ $admin-color: #cf3638;
padding: 0;
[class^="icon-"] {
color: $admin-color;
color: #fff;
display: inline-block;
font-size: rem-calc(24);
line-height: $line-height;
@@ -219,39 +300,32 @@ $admin-color: #cf3638;
}
li {
background: #fff;
margin: 0;
outline: 0;
ul {
margin-left: $line-height / 1.5;
border-left: 1px solid $border;
border-left: 1px solid $sidebar-hover;
padding-left: $line-height / 2;
}
&.section-title {
border-bottom: 1px solid $border;
}
&.active a {
background: #f3f6f7;
border-radius: rem-calc(6);
color: $admin-color;
background: $sidebar-hover;
border-left: 2px solid $sidebar-active;
font-weight: bold;
}
}
li a {
color: $text;
color: #fff;
display: block;
line-height: rem-calc(48);
padding-left: rem-calc(12);
vertical-align: top;
&:hover {
background: #f3f6f7;
border-radius: rem-calc(6);
color: $admin-color;
background: $sidebar-hover;
color: #fff;
text-decoration: none;
}
}
@@ -259,7 +333,13 @@ $admin-color: #cf3638;
.is-accordion-submenu-parent {
> a::after {
border-color: $admin-color transparent transparent;
border: 0;
content: '\61' !important;
font-family: "icons" !important;
height: auto;
position: absolute !important;
right: 30px;
top: 6px !important;
}
}
@@ -525,6 +605,7 @@ table {
.callout {
height: $line-height * 2;
line-height: $line-height * 2;
margin: 0;
padding: 0 $line-height / 2;
}
}
@@ -898,3 +979,51 @@ table {
border: 0;
}
}
// 09. Map
// --------------
.map {
width: 100%;
height: 350px;
.map-marker {
visibility: visible;
position: absolute;
left: 50%;
top: 50%;
margin-top: -5px;
.map-icon {
width: 30px;
height: 30px;
border-radius: 50% 50% 50% 0;
background: #00cae9;
transform: rotate(-45deg);
}
.map-icon::after {
content: '';
width: 14px;
height: 14px;
margin: 8px 0 0 8px;
background: #fff;
position: absolute;
border-radius: 50%;
}
}
.map-attributtion {
visibility: visible;
height: auto;
}
}
.map-marker {
visibility: hidden;
}
.map-attributtion {
visibility: hidden;
height: 0;
}

View File

@@ -16,4 +16,7 @@
@import 'annotator_overrides';
@import 'jquery-ui/datepicker';
@import 'datepicker_overrides';
@import 'documentable';
@import 'jquery-ui/autocomplete';
@import 'autocomplete_overrides';
@import 'jquery-ui/sortable';
@import 'leaflet';

View File

@@ -0,0 +1,40 @@
// Overrides styles of jquery-ui/autocomplete
//
/* Autocomplete
----------------------------------*/
.ui-autocomplete {
position: absolute;
cursor: default;
}
/* workarounds */
* html .ui-autocomplete {
width: 1px;
} /* without this, the menu expands to 100% in IE6 */
/* Menu
----------------------------------*/
.ui-menu {
list-style: none;
padding: $line-height / 4 $line-height / 3;
display: block;
background: #fff;
border: 1px solid $border;
font-size: $small-font-size;
.ui-menu-item {
.ui-menu-item-wrapper {
padding: $line-height / 4 $line-height / 3;
position: relative;
}
.ui-state-hover,
.ui-state-active {
background: #ececec;
border-radius: rem-calc(6);
}
}
}

View File

@@ -1,63 +0,0 @@
.progress-bar-placeholder {
display: none;
}
.document-form {
.document .file-name {
margin-top: 0;
}
.progress-bar-placeholder {
margin-bottom: 15px;
}
.document .loading-bar.errors {
margin-top: $line-height * 2;
}
}
.document {
.button {
font-weight: normal;
}
.progress-bar {
width: 100%;
background-color: $light-gray;
}
.js-document-attachment {
display: none;
}
.file-name {
margin-top: $line-height / 2;
}
.loading-bar {
height: 5px;
width: 0;
transition: width 500ms ease-out;
&.uploading {
background-color: $dark-gray;
}
&.complete {
background-color: $success-color;
width: 100%;
}
&.errors {
background-color: $alert-color;
width: 100%;
margin-top: $line-height / 2;
}
}
.loading-bar.no-transition {
transition: none;
}
}

View File

@@ -4,6 +4,7 @@
@import 'consul_settings';
@import 'custom_settings';
@import 'foundation';
@import 'motion-ui/motion-ui';
@include foundation-global-styles;
@include foundation-grid;
@@ -37,3 +38,7 @@
@include foundation-title-bar;
@include foundation-top-bar;
@include foundation-menu-icon;
@include foundation-orbit;
@include motion-ui-transitions;
@include motion-ui-animations;

View File

@@ -97,10 +97,6 @@
content: '\72';
}
.icon-documents::before {
content: '\68';
}
.icon-proposals::before {
content: '\68';
}
@@ -260,3 +256,35 @@
.icon-instagram::before {
content: '\32';
}
.icon-image::before {
content: '\33';
}
.icon-search-plus::before {
content: '\34';
}
.icon-search-minus::before {
content: '\35';
}
.icon-calculator::before {
content: '\36';
}
.icon-map-marker::before {
content: '\37';
}
.icon-user-plus::before {
content: '\38';
}
.icon-file-text-o::before {
content: '\39';
}
.icon-file-text::before {
content: '\21';
}

View File

@@ -18,7 +18,8 @@
// 16. Flags
// 17. Activity
// 18. Banners
// 19. Documents
// 19. Recommended Section Home
// 20. Documents
//
// 01. Global styles
@@ -154,6 +155,10 @@ a {
margin-bottom: $line-height;
}
.margin-left {
margin-left: $line-height;
}
.margin-right {
margin-right: $line-height;
}
@@ -205,19 +210,42 @@ a {
.menu.simple {
border-bottom: 1px solid $border;
margin-bottom: $line-height;
clear: both;
margin-bottom: $line-height / 2;
li {
padding-bottom: rem-calc(7);
font-size: $base-font-size;
margin-bottom: 0;
margin-right: $line-height / 2;
@include breakpoint(medium) {
margin-right: $line-height * 1.5;
}
a {
color: $text-medium;
color: $text;
display: inline-block;
font-weight: bold;
position: relative;
text-align: left;
&:hover {
color: $link;
}
}
&.active {
border-bottom: 2px solid $brand;
color: $brand;
}
&:not(.active) {
margin-bottom: $line-height / 3;
}
}
h2 {
font-size: $base-font-size;
}
}
@@ -281,18 +309,25 @@ a {
display: inline-block;
}
.back:not([class^="icon-"]) {
text-decoration: underline;
}
.tabs-content {
border: 0;
}
.tabs {
border: {
left: 0;
right: 0;
top: 0;
};
border-left: 0;
border-right: 0;
border-top: 0;
margin-bottom: $line-height;
.tabs-title {
font-size: $base-font-size;
margin-bottom: 0;
}
.tabs-title > a {
color: $text-medium;
margin-bottom: rem-calc(-1);
@@ -320,10 +355,32 @@ a {
background: $brand;
}
.truncate-horizontal-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.align-top {
vertical-align: top;
}
.aling-middle {
vertical-align: middle;
}
.table {
display: table;
}
.table-cell {
display: table-cell;
}
.off-canvas-content {
box-shadow: none;
}
.uppercase {
text-transform: uppercase;
}
@@ -371,7 +428,11 @@ header {
.top-bar-title a {
@include logo;
line-height: rem-calc(80) !important;
line-height: rem-calc(80);
@include breakpoint(medium) {
line-height: rem-calc(80);
}
&:hover {
text-decoration: none;
@@ -591,7 +652,7 @@ header {
text-align: left;
@include breakpoint(medium) {
margin-right: $line-height * 1.5;
margin-right: $line-height;
}
&:hover {
@@ -1087,8 +1148,13 @@ form {
color: #ecf00b;
font-size: rem-calc(10);
position: absolute;
right: 8px;
left: 12px;
top: 6px;
@include breakpoint(medium) {
left: auto;
right: 8px;
}
}
}
@@ -1976,7 +2042,6 @@ table {
// ------------
.activity {
margin-bottom: $line-height * 2;
.accordion li {
margin-bottom: $line-height / 2;
@@ -2008,62 +2073,15 @@ table {
}
}
table {
border: 0;
margin-bottom: 0;
}
td {
position: relative;
&:first-child {
padding-left: $line-height * 1.5;
width: 75%;
}
&::before {
color: $brand;
font-family: "icons" !important;
font-size: rem-calc(24);
left: 4px;
position: absolute;
}
}
.activity-comments td:first-child::before {
content: 'e';
top: 18px;
}
.activity-debates td:first-child::before {
content: 'i';
top: 14px;
}
.activity-proposals {
td:first-child::before {
content: 'h';
top: 18px;
}
.retired {
text-decoration: line-through;
}
}
.activity-investment-projects td:first-child::before,
.activity-ballot td:first-child::before {
content: '\53';
top: 10px;
.retired {
text-decoration: line-through;
}
}
.public-interests {
margin-top: $line-height;
.column {
padding-left: 0;
li {
margin-right: $line-height / 4;
}
}
@@ -2140,68 +2158,146 @@ table {
}
}
// 19. Documents
.document-form form {
// 19. Recommended Section Home
// ----------------------------
.radio-buttons {
label {
margin-right: $line-height;
}
.home-page {
.push {
display: none;
}
}
.section-recommended {
padding: $line-height * 2 0;
h2 {
margin-bottom: $line-height * 2;
}
.source-option-link {
input {
padding-bottom: 0;
.debates,
.proposals,
.budget-investments {
@include breakpoint(medium) {
margin-bottom: 0;
}
.error {
@include breakpoint(small) {
margin-bottom: $line-height;
}
label {
&.error {
margin-bottom: 0;
}
.button.hollow {
margin-top: rem-calc(15);
}
}
.source-option-file {
.file-name {
label {
.card {
@include breakpoint(small medium) {
float: none;
}
@include breakpoint(large) {
float: left;
}
}
.card-section {
padding: $line-height 0;
max-width: rem-calc(300);
margin: 0 auto;
p {
font-size: rem-calc(15);
text-align: left;
}
}
@include breakpoint(small medium) {
float: none;
margin-top: 0;
margin-left: 0;
margin-bottom: 0;
}
.orbit {
height: rem-calc(300);
@include breakpoint(large) {
float: left;
margin-bottom: 0;
margin-top: $line-height / 2;
margin-left: $line-height;
}
.orbit-wrapper {
max-height: rem-calc(250);
overflow: hidden;
position: relative;
}
.orbit-bullets {
@include orbit-bullets;
width: 100%;
}
}
}
.attachment-errors {
margin-bottom: $line-height;
.card .orbit .orbit-wrapper .truncate {
background: image-url('truncate.png');
background-repeat: repeat-x;
bottom: 0;
height: rem-calc(20);
position: absolute;
width: 100%;
}
.debates-inner {
border-top: 4px solid $debates;
}
.proposals-inner {
border-top: 4px solid $proposals;
}
.budget-investments-inner {
border-top: 4px solid $budget;
}
.debates-inner,
.proposals-inner,
.budget-investments-inner {
background: #fff;
max-height: rem-calc(350);
@include breakpoint(small) {
max-height: rem-calc(400);
}
h4 {
margin-top: $line-height;
margin-bottom: 0;
font-size: rem-calc(18);
min-height: rem-calc(50);
}
h5 {
font-size: $small-font-size;
text-align: left;
}
}
.carousel-image {
.card .orbit {
height: rem-calc(480);
.orbit-wrapper {
max-height: rem-calc(450);
}
}
.debates-inner,
.proposals-inner,
.budget-investments-inner {
max-height: rem-calc(500);
@include breakpoint(small) {
max-height: rem-calc(600);
}
}
}
.carousel-image .orbit-wrapper img {
display: block;
@include breakpoint(small) {
margin: 0 auto;
}
}
}
// 20. Documents
// -------------
.documents-list {
table {
@@ -2258,6 +2354,31 @@ table {
}
}
}
}
.additional-document-link {
background: $highlight-soft;
border: 1px solid $highlight;
display: block;
margin: $line-height / 2 0;
padding: $line-height / 2;
position: relative;
a {
word-wrap: break-word;
}
.icon-document {
color: #007bb7;
display: inline-block;
font-size: rem-calc(24);
line-height: $line-height;
vertical-align: middle;
}
}
.document-divider {
background: #fafafa;
border-bottom: 1px solid #eee;
}

View File

@@ -109,16 +109,13 @@ $border-dark: darken($border, 10%);
li {
cursor: pointer;
display: inline-block;
margin: 0 1rem 1rem 0;
margin-bottom: $line-height;
margin-right: $line-height;
transition: all 0.4s;
border-bottom: 2px solid transparent;
@include breakpoint(medium) {
margin-left: $line-height * 2;
}
&:first-of-type {
margin-left: 0;
margin-bottom: 0;
}
&:hover,
@@ -459,11 +456,11 @@ $border-dark: darken($border, 10%);
span {
vertical-align: inherit;
font-style: normal;
}
a {
text-decoration: underline;
color: $text-medium;
}
.see-changes {
color: $text-medium;
text-decoration: underline;
}
}
@@ -477,6 +474,7 @@ $border-dark: darken($border, 10%);
}
.draft-allegation {
@include breakpoint(medium) {
display: flex;
padding-left: 0.9375rem;
@@ -493,7 +491,6 @@ $border-dark: darken($border, 10%);
}
}
// Panel calcs for desktop
@media screen and (min-width: 40em) {
.calc-index {
width: calc(35% - 25px);
@@ -509,6 +506,7 @@ $border-dark: darken($border, 10%);
width: rem-calc(50);
.draft-panel {
.panel-title {
display: none;
}
@@ -912,19 +910,15 @@ $border-dark: darken($border, 10%);
display: inline-block;
}
}
.show-for-medium {
.panel-title {
display: none;
}
}
}
}
}
// 08. Legislation changes
// -----------------
.legislation-changes {
ul {
list-style: none;
margin-left: 0;
@@ -936,35 +930,36 @@ $border-dark: darken($border, 10%);
margin-right: 0.25rem;
content: '';
}
}
}
.changes-link {
display: block;
margin-left: 1rem;
font-size: $small-font-size;
.changes-link {
display: block;
margin-left: 1rem;
font-size: $small-font-size;
@include breakpoint(medium) {
display: inline-block;
}
@include breakpoint(medium) {
display: inline-block;
}
a {
span {
text-decoration: underline;
}
a {
.icon-external {
text-decoration: none;
color: #999;
line-height: 0;
vertical-align: sub;
margin-left: 0.5rem;
}
span {
text-decoration: underline;
}
&:active,
&:focus,
&:hover {
text-decoration: none;
}
}
.icon-external {
text-decoration: none;
color: #999;
line-height: 0;
vertical-align: sub;
margin-left: 0.5rem;
}
&:active,
&:focus,
&:hover {
text-decoration: none;
}
}
}
@@ -972,6 +967,7 @@ $border-dark: darken($border, 10%);
// 09. Legislation comments
// -----------------
.legislation-comments {
.pull-right {
@@ -1020,6 +1016,7 @@ $border-dark: darken($border, 10%);
// 10. Legislation draft comment
// -----------------
.legislation-comment {
.annotation-share-comment {

View File

@@ -1,7 +1,9 @@
// Table of Contents
//
// 01. Logo
//
// 02. Orbit bullets
// 03. Direct uploads
// ------------------
// 01. Logo
// --------
@@ -30,3 +32,108 @@
}
}
}
// 02. Orbit bullet
// ----------------
@mixin orbit-bullets {
@include disable-mouse-outline;
position: relative;
margin-top: $orbit-bullet-margin-top;
margin-bottom: $orbit-bullet-margin-bottom;
text-align: center;
button {
width: $orbit-bullet-diameter;
height: $orbit-bullet-diameter;
margin: $orbit-bullet-margin;
border-radius: 50%;
background-color: $orbit-bullet-background;
&:hover {
background-color: $orbit-bullet-background-active;
}
&.is-active {
background-color: $orbit-bullet-background-active;
}
}
}
// 03. Direct uploads
// ------------------
@mixin direct-uploads {
.cached-image {
max-width: rem-calc(150);
max-height: rem-calc(150);
}
.progress-bar-placeholder {
display: none;
margin-bottom: $line-height;
}
.document,
.image {
.document-attachment,
.image-attachment {
padding-left: 0;
p {
margin-bottom: 0;
}
}
.attachment-errors {
> .js-image-attachment,
> .js-document-attachment {
display: none;
~ .error {
display: inline-block;
}
}
}
}
.button {
font-weight: normal;
}
.progress-bar {
width: 100%;
background-color: $light-gray;
}
.file-name {
margin-top: 0;
}
.loading-bar {
height: 5px;
width: 0;
transition: width 500ms ease-out;
&.uploading {
background-color: $dark-gray;
}
&.complete {
background-color: $success-color;
}
&.errors {
background-color: $alert-color;
margin-top: $line-height / 2;
}
}
.loading-bar.no-transition {
transition: none;
}
}

View File

@@ -8,6 +8,7 @@
// 06. Budget
// 07. Proposals successful
// 08. Polls
// 09. Polls results and stats
//
// 01. Votes and supports
@@ -249,12 +250,14 @@
.proposal-form,
.budget-investment-form,
.spending-proposal-form,
.document-form {
.document-form,
.topic-new,
.topic-form {
.icon-debates,
.icon-proposals,
.icon-budget,
.icon-documents {
.icon-image {
font-size: rem-calc(50);
line-height: $line-height;
opacity: 0.5;
@@ -265,7 +268,7 @@
}
.icon-proposals,
.icon-documents {
.icon-image {
color: $proposals;
}
@@ -298,13 +301,25 @@
}
.proposal-form,
.document-form {
.document-form,
.topic-form,
.topic-new {
.recommendations li::before {
color: $proposals;
}
}
.budget-investment-new,
.proposal-form,
.proposal-edit,
.polls-form,
.poll-question-form,
.legislation-process-new,
.legislation-process-edit {
@include direct-uploads;
}
// 03. Show participation
// ----------------------
@@ -325,8 +340,16 @@
word-wrap: break-word;
}
.callout.proposal-retired {
font-size: $base-font-size;
.callout {
&.token-message {
background-color: #fff;
border-color: $info-border;
color: $color-info;
}
&.proposal-retired {
font-size: $base-font-size;
}
}
.social-share-full .social-share-button {
@@ -345,11 +368,6 @@
width: rem-calc(48);
}
.edit-debate,
.edit-proposal {
margin-bottom: 0;
}
.debate-info,
.proposal-info,
.investment-project-info,
@@ -636,6 +654,71 @@
}
}
.budget-investments-list .budget-investment,
.proposals-list .proposal {
.no-image {
background: $brand;
}
}
.budget-investments-list .budget-investment,
.proposals-list .proposal {
@include breakpoint(small) {
.no-image {
width: 100%;
max-width: rem-calc(300);
margin: 0 auto;
&::before {
content: '';
display: block;
padding-top: 100%;
}
}
}
@include breakpoint(medium) {
.panel {
&.with-image {
padding: 0 $line-height / 2 0 0;
}
.no-image {
height: 100%;
min-height: rem-calc(245);
width: rem-calc(140);
}
}
.column:first-child {
overflow: hidden;
}
.column:nth-child(2) {
float: left;
}
.column:last-child:not(:first-child) {
padding-top: $line-height / 2;
}
img {
max-width: 12rem;
}
.budget-investment-content {
ul {
margin-bottom: 0;
}
}
}
}
.debate,
.proposal,
.investment-project,
@@ -751,7 +834,7 @@
background: image-url('truncate.png');
background-repeat: repeat-x;
bottom: 0;
height: 24px;
height: rem-calc(24);
position: absolute;
width: 100%;
}
@@ -765,12 +848,6 @@
display: none;
}
.document-form {
max-width: 75rem;
margin-left: auto;
margin-right: auto;
}
.more-info {
clear: both;
color: $text-medium;
@@ -782,7 +859,9 @@
}
.debate,
.debate-show {
.debate-show,
.proposal-show,
.legislation-proposals {
.votes {
@include votes;
@@ -797,6 +876,7 @@
}
}
.proposal-show .votes,
.debate-show .votes {
border: 0;
padding: $line-height / 2 0;
@@ -855,6 +935,19 @@
}
}
.budget-investment-show {
figure {
margin: rem-calc(10) 0 0;
display: inline-block;
figcaption {
font-size: $small-font-size;
margin-top: rem-calc(10);
}
}
}
.investment-project-show .supports,
.budget-investment-show .supports {
border: 0;
@@ -1389,33 +1482,6 @@
}
}
.featured-proposals-ballot-banner,
.sucessfull-proposals-banner {
background: #2d3e50 image-url('ballot_tiny.gif') no-repeat;
background-position: 75% 0;
position: relative;
@include breakpoint(medium) {
margin-left: 0 !important;
margin-right: 0 !important;
}
@include breakpoint(large) {
background: #2d3e50 image-url('ballot.gif') no-repeat;
background-position: 90% 0;
}
h2,
a:hover h2 {
color: #ffd200 !important;
}
p {
color: #fff;
}
}
.sucessfull-proposals-banner,
.successful .panel {
.icon-successful {
@@ -1464,18 +1530,8 @@
// 08. Polls
// ----------------------
.dark-heading {
background: #2d3e50;
color: #fff;
.title {
color: #92ba48;
}
.button {
background: #fff;
color: $brand;
}
.polls-show-header {
background: #fafafa;
.callout {
@@ -1491,28 +1547,117 @@
color: $color-alert;
}
}
}
.info {
background: #314253;
padding: $line-height;
.poll-more-info,
.poll-more-info-answers {
border-top: 1px solid #eee;
}
@include breakpoint(medium) {
border-top: rem-calc(6) solid #92ba48;
.poll-more-info-answers {
background: #fafafa;
border-bottom: 1px solid #eee;
.column:nth-child(odd) {
border-right: 2px solid $text;
}
.answer-divider {
border-bottom: 2px solid $text;
border-right: 0 !important;
margin-bottom: $line-height;
padding-bottom: $line-height;
}
.answer-description {
height: 100%;
&.short {
height: rem-calc(300);
overflow: hidden;
}
}
}
a:not(.button) {
color: #fff;
text-decoration: underline;
.orbit-bullets button {
background-color: #ccc;
height: $line-height / 2;
width: $line-height / 2;
&.is-active {
background-color: $brand;
}
}
.back,
.icon-angle-left {
color: #fff;
.orbit-container {
height: 100% !important;
max-height: none !important;
li {
margin-bottom: 0 !important;
}
}
&.polls-show-header {
min-height: $line-height * 8;
.orbit-slide {
max-height: none !important;
img {
image-rendering: pixelated;
}
}
.orbit-caption {
background: #eee;
color: $text;
}
.orbit-next,
.orbit-previous {
background: rgba(34, 34, 34, 0.25);
}
.zoom-link {
background: #fff;
border-radius: rem-calc(48);
color: #000;
font-size: rem-calc(24);
font-weight: bold;
height: rem-calc(48);
line-height: rem-calc(48);
right: 12px;
padding-top: rem-calc(4);
position: absolute;
text-align: center;
top: 24px;
width: rem-calc(48);
z-index: 9;
&:hover {
background: $dark;
color: #fff;
text-decoration: none;
}
}
.image-container {
background: #fafafa;
overflow: hidden;
position: relative;
}
.poll {
&.with-image {
@include breakpoint(medium) {
padding: 0 $line-height / 2 0 0;
}
img {
height: 100%;
max-width: none;
position: absolute;
}
}
}
@@ -1610,9 +1755,13 @@
}
.section-title-divider {
border-bottom: 2px solid $brand;
color: $brand;
margin-bottom: $line-height;
border-bottom: 1px solid #eee;
color: #000;
margin: $line-height 0;
span {
border-bottom: 1px solid #000;
}
}
.poll-question {
@@ -1633,6 +1782,10 @@
margin-right: $line-height / 4;
min-width: rem-calc(168);
@include breakpoint(medium down) {
width: 100%;
}
&.answered {
background: #f4f8ec;
border: 2px solid #92ba48;
@@ -1654,3 +1807,59 @@
}
}
}
// 09. Polls results and stats
// ---------------------------
.polls-results-stats {
.sidebar {
border-bottom: 1px solid $border;
margin-bottom: $line-height;
@include breakpoint(medium) {
border-bottom: 0;
border-right: 1px solid $border;
}
.menu {
padding: 0;
li a {
color: $link;
line-height: $line-height;
}
}
}
table {
table-layout: fixed;
caption {
padding: $line-height / 2 0;
text-align: left;
}
th {
text-align: left;
&.win {
background: #009fde;
}
}
td {
&.win {
background: #ccedf8;
font-weight: bold;
}
}
}
.number {
font-size: rem-calc(60);
font-weight: bold;
line-height: rem-calc(60);
}
}

View File

@@ -12,7 +12,7 @@
#print_link { display: none !important; }
#responsive-menu { display: none !important; }
#responsive_menu { display: none !important; }
.admin-sidebar { display: none !important; }

View File

@@ -6,16 +6,10 @@ class Admin::AdministratorsController < Admin::BaseController
end
def search
@user = User.find_by(email: params[:email])
respond_to do |format|
if @user
@administrator = Administrator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
@users = User.search(params[:name_or_email])
.includes(:administrator)
.page(params[:page])
.for_render
end
def create

View File

@@ -51,7 +51,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
def budget_investment_params
params.require(:budget_investment)
.permit(:title, :description, :external_url, :heading_id, :administrator_id, :valuation_tag_list, :incompatible,
.permit(:title, :description, :external_url, :heading_id, :administrator_id, :tag_list, :valuation_tag_list, :incompatible,
:selected, valuator_ids: [])
end

View File

@@ -19,8 +19,10 @@ class Admin::Legislation::ProcessesController < Admin::Legislation::BaseControll
def update
if @process.update(process_params)
set_tag_list
link = legislation_process_path(@process).html_safe
redirect_to edit_admin_legislation_process_path(@process), notice: t('admin.legislation.processes.update.notice', link: link)
redirect_to :back, notice: t('admin.legislation.processes.update.notice', link: link)
else
flash.now[:error] = t('admin.legislation.processes.update.error')
render :edit
@@ -47,12 +49,23 @@ class Admin::Legislation::ProcessesController < Admin::Legislation::BaseControll
:draft_publication_date,
:allegations_start_date,
:allegations_end_date,
:proposals_phase_start_date,
:proposals_phase_end_date,
:result_publication_date,
:debate_phase_enabled,
:allegations_phase_enabled,
:proposals_phase_enabled,
:draft_publication_enabled,
:result_publication_enabled,
:published
:published,
:proposals_description,
:custom_list,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
)
end
def set_tag_list
@process.set_tag_list_on(:customs, process_params[:custom_list])
@process.save
end
end

View File

@@ -0,0 +1,7 @@
class Admin::Legislation::ProposalsController < Admin::Legislation::BaseController
load_and_authorize_resource :process, class: "Legislation::Process"
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
def index
end
end

View File

@@ -6,16 +6,10 @@ class Admin::ManagersController < Admin::BaseController
end
def search
@user = User.find_by(email: params[:email])
respond_to do |format|
if @user
@manager = Manager.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
@users = User.search(params[:name_or_email])
.includes(:manager)
.page(params[:page])
.for_render
end
def create

View File

@@ -6,16 +6,10 @@ class Admin::ModeratorsController < Admin::BaseController
end
def search
@user = User.find_by(email: params[:email])
respond_to do |format|
if @user
@moderator = Moderator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
@users = User.search(params[:name_or_email])
.includes(:moderator)
.page(params[:page])
.for_render
end
def create

View File

@@ -15,24 +15,32 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
end
def show
@booth_assignment = @poll.booth_assignments.includes(:total_results, :voters,
@booth_assignment = @poll.booth_assignments.includes(:recounts, :voters,
officer_assignments: [officer: [:user]]).find(params[:id])
@voters_by_date = @booth_assignment.voters.group_by {|v| v.created_at.to_date}
@partial_results = @booth_assignment.partial_results
@recounts = @booth_assignment.recounts
end
def create
@booth_assignment = ::Poll::BoothAssignment.new(poll_id: booth_assignment_params[:poll_id],
booth_id: booth_assignment_params[:booth_id])
@poll = Poll.find(booth_assignment_params[:poll_id])
@booth = Poll::Booth.find(booth_assignment_params[:booth_id])
@booth_assignment = ::Poll::BoothAssignment.new(poll: @poll,
booth: @booth)
if @booth_assignment.save
notice = t("admin.poll_booth_assignments.flash.create")
else
notice = t("admin.poll_booth_assignments.flash.error_create")
end
redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice
respond_to do |format|
format.js { render layout: false }
end
end
def destroy
@poll = Poll.find(booth_assignment_params[:poll_id])
@booth = Poll::Booth.find(booth_assignment_params[:booth_id])
@booth_assignment = ::Poll::BoothAssignment.find(params[:id])
if @booth_assignment.destroy
@@ -40,7 +48,14 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
else
notice = t("admin.poll_booth_assignments.flash.error_destroy")
end
redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice
respond_to do |format|
format.js { render layout: false }
end
end
def manage
@booths = ::Poll::Booth.all
@poll = Poll.find(params[:poll_id])
end
private

View File

@@ -18,14 +18,16 @@ class Admin::Poll::OfficerAssignmentsController < Admin::Poll::BaseController
@officer = ::Poll::Officer.includes(:user).find(officer_assignment_params[:officer_id])
@officer_assignments = ::Poll::OfficerAssignment.
joins(:booth_assignment).
includes(:total_results, booth_assignment: :booth).
includes(:recounts, booth_assignment: :booth).
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", @officer.id, @poll.id).
order(:date)
end
def search_officers
load_search
@officers = User.joins(:poll_officer).search(@search).order(username: :asc)
poll_officers = User.where(id: @poll.officers.pluck(:user_id))
@officers = poll_officers.search(@search).order(username: :asc)
respond_to do |format|
format.js

View File

@@ -1,7 +1,7 @@
class Admin::Poll::PollsController < Admin::Poll::BaseController
load_and_authorize_resource
before_action :load_search, only: [:search_booths, :search_questions, :search_officers]
before_action :load_search, only: [:search_booths, :search_officers]
before_action :load_geozones, only: [:new, :create, :edit, :update]
def index
@@ -47,23 +47,8 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController
redirect_to admin_poll_path(@poll), notice: notice
end
def remove_question
question = ::Poll::Question.find(params[:question_id])
if @poll.questions.include? question
@poll.questions.delete(question)
notice = t("admin.polls.flash.question_removed")
else
notice = t("admin.polls.flash.error_on_question_removed")
end
redirect_to admin_poll_path(@poll), notice: notice
end
def search_questions
@questions = ::Poll::Question.where("poll_id IS ? OR poll_id != ?", nil, @poll.id).search(search: @search).order(title: :asc)
respond_to do |format|
format.js
end
def booth_assignments
@polls = Poll.current_or_incoming
end
private
@@ -73,7 +58,10 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController
end
def poll_params
params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted, geozone_ids: [])
params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted,
:summary, :description, :results_enabled, :stats_enabled,
geozone_ids: [],
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
end
def search_params

View File

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

View File

@@ -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
notice = if @video.destroy
t("flash.actions.destroy.poll_question_answer_video")
else
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

@@ -0,0 +1,57 @@
class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController
before_action :load_answer, only: [:show, :edit, :update, :documents]
load_and_authorize_resource :question, class: "::Poll::Question"
def new
@answer = ::Poll::Question::Answer.new
end
def create
@answer = ::Poll::Question::Answer.new(answer_params)
if @answer.save
redirect_to admin_question_path(@answer.question),
notice: t("flash.actions.create.poll_question_answer")
else
render :new
end
end
def show
end
def edit
end
def update
if @answer.update(answer_params)
redirect_to admin_question_path(@answer.question),
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
def order_answers
::Poll::Question::Answer.order_answers(params[:ordered_list])
render nothing: true
end
private
def answer_params
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
end

View File

@@ -15,14 +15,12 @@ class Admin::Poll::QuestionsController < Admin::Poll::BaseController
def new
@polls = Poll.all
@question.valid_answers = I18n.t('poll_questions.default_valid_answers')
proposal = Proposal.find(params[:proposal_id]) if params[:proposal_id].present?
@question.copy_attributes_from_proposal(proposal)
end
def create
@question.author = @question.proposal.try(:author) || current_user
recover_documents_from_cache(@question)
if @question.save
redirect_to admin_question_path(@question)
@@ -32,7 +30,6 @@ class Admin::Poll::QuestionsController < Admin::Poll::BaseController
end
def show
@document = Document.new(documentable: @question)
end
def edit
@@ -58,8 +55,7 @@ class Admin::Poll::QuestionsController < Admin::Poll::BaseController
private
def question_params
params.require(:poll_question).permit(:poll_id, :title, :question, :description, :proposal_id, :valid_answers, :video_url,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
params.require(:poll_question).permit(:poll_id, :title, :question, :proposal_id, :video_url)
end
def search_params

View File

@@ -3,7 +3,7 @@ class Admin::Poll::RecountsController < Admin::Poll::BaseController
def index
@booth_assignments = @poll.booth_assignments.
includes(:booth, :total_results, :voters).
includes(:booth, :recounts, :voters).
order("poll_booths.name").
page(params[:page]).per(50)
end

View File

@@ -1,12 +1,13 @@
class Admin::Poll::ShiftsController < Admin::Poll::BaseController
before_action :load_booth
before_action :load_polls
before_action :load_officer
def new
load_shifts
@shift = ::Poll::Shift.new
@voting_polls = @booth.polls.current_or_incoming
@recount_polls = @booth.polls.current_or_recounting_or_incoming
end
def create
@@ -14,10 +15,10 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
@officer = @shift.officer
if @shift.save
notice = t("admin.poll_shifts.flash.create")
redirect_to new_admin_booth_shift_path(@shift.booth), notice: notice
redirect_to new_admin_booth_shift_path(@shift.booth), notice: t("admin.poll_shifts.flash.create")
else
load_shifts
flash[:error] = t("admin.poll_shifts.flash.date_missing")
render :new
end
end
@@ -30,7 +31,7 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
end
def search_officers
@officers = User.search(params[:search]).order(username: :asc)
@officers = User.search(params[:search]).order(username: :asc).select { |o| o.poll_officer? == true }
end
private
@@ -39,10 +40,6 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
@booth = ::Poll::Booth.find(params[:booth_id])
end
def load_polls
@polls = ::Poll.current_or_incoming
end
def load_shifts
@shifts = @booth.shifts
end
@@ -54,7 +51,7 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
end
def shift_params
params.require(:shift).permit(:booth_id, :officer_id, :date)
shift_params = params.require(:shift).permit(:booth_id, :officer_id, :task, date: [:vote_collection_date, :recount_scrutiny_date])
shift_params.merge(date: shift_params[:date]["#{shift_params[:task]}_date".to_sym])
end
end

View File

@@ -1,7 +1,7 @@
class Admin::SettingsController < Admin::BaseController
def index
all_settings = (Setting.all).group_by { |s| s.type }
all_settings = Setting.all.group_by { |s| s.type }
@settings = all_settings['common']
@feature_flags = all_settings['feature']
@banner_styles = all_settings['banner-style']
@@ -14,6 +14,13 @@ class Admin::SettingsController < Admin::BaseController
redirect_to admin_settings_path, notice: t("admin.settings.flash.updated")
end
def update_map
Setting["map_latitude"] = params[:latitude].to_f
Setting["map_longitude"] = params[:longitude].to_f
Setting["map_zoom"] = params[:zoom].to_i
redirect_to admin_settings_path, notice: t("admin.settings.index.map.flash.update")
end
private
def settings_params

View File

@@ -6,16 +6,10 @@ class Admin::ValuatorsController < Admin::BaseController
end
def search
@user = User.find_by(email: params[:email])
respond_to do |format|
if @user
@valuator = Valuator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
@users = User.search(params[:name_or_email])
.includes(:valuator)
.page(params[:page])
.for_render
end
def create
@@ -25,6 +19,11 @@ class Admin::ValuatorsController < Admin::BaseController
redirect_to admin_valuators_path
end
def destroy
@valuator.destroy
redirect_to admin_valuators_path
end
def summary
@valuators = Valuator.order(spending_proposals_count: :desc)
end
@@ -36,4 +35,4 @@ class Admin::ValuatorsController < Admin::BaseController
params.require(:valuator).permit(:user_id, :description)
end
end
end

View File

@@ -44,12 +44,10 @@ module Budgets
set_comment_flags(@comment_tree.comments)
load_investment_votes(@investment)
@investment_ids = [@investment.id]
@document = Document.new(documentable: @investment)
end
def create
@investment.author = current_user
recover_documents_from_cache(@investment)
if @investment.save
Mailer.budget_investment_created(@investment).deliver_later
@@ -105,9 +103,12 @@ module Budgets
end
def investment_params
params.require(:budget_investment).permit(:title, :description, :external_url, :heading_id, :tag_list,
:organization_name, :location, :terms_of_service,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
params.require(:budget_investment)
.permit(:title, :description, :external_url, :heading_id, :tag_list,
:organization_name, :location, :terms_of_service,
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
map_location_attributes: [:latitude, :longitude, :zoom])
end
def load_ballot

View File

@@ -4,17 +4,22 @@ module CommentableActions
include Search
def index
@resources = @search_terms.present? ? resource_model.search(@search_terms) : resource_model.all
@resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources
@resources = resource_model.all
@resources = @current_order == "recommendations" && current_user.present? ? @resources.recommendations(current_user) : @resources.for_render
@resources = @resources.search(@search_terms) if @search_terms.present?
@resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources
@resources = @resources.tagged_with(@tag_filter) if @tag_filter
@resources = @resources.page(params[:page]).for_render.send("sort_by_#{@current_order}")
@resources = @resources.page(params[:page]).send("sort_by_#{@current_order}")
index_customization if index_customization.present?
@tag_cloud = tag_cloud
@banners = Banner.with_active
set_resource_votes(@resources)
set_resources_instance
end
@@ -57,10 +62,7 @@ module CommentableActions
end
def update
resource.assign_attributes(strong_params)
recover_documents_from_cache(resource)
if resource.save
if resource.update(strong_params)
redirect_to resource, notice: t("flash.actions.update.#{resource_name.underscore}")
else
load_categories
@@ -112,11 +114,4 @@ module CommentableActions
nil
end
def recover_documents_from_cache(resource)
return false unless resource.try(:documents)
resource.documents = resource.documents.each do |document|
document.set_attachment_from_cached_attachment if document.cached_attachment.present?
end
end
end

View File

@@ -10,7 +10,7 @@ class DebatesController < ApplicationController
invisible_captcha only: [:create, :update], honeypot: :subtitle
has_orders %w{hot_score confidence_score created_at relevance}, only: :index
has_orders ->(c) { Debate.debates_orders(c.current_user) }, only: :index
has_orders %w{most_voted newest oldest}, only: :show
load_and_authorize_resource

View File

@@ -0,0 +1,48 @@
class DirectUploadsController < ApplicationController
include DirectUploadsHelper
include ActionView::Helpers::UrlHelper
before_action :authenticate_user!
load_and_authorize_resource except: :create
skip_authorization_check only: :create
helper_method :render_destroy_upload_link
def create
@direct_upload = DirectUpload.new(direct_upload_params.merge(user: current_user, attachment: params[:attachment]))
if @direct_upload.valid?
@direct_upload.save_attachment
@direct_upload.relation.set_cached_attachment_from_attachment
render json: { cached_attachment: @direct_upload.relation.cached_attachment,
filename: @direct_upload.relation.attachment.original_filename,
destroy_link: render_destroy_upload_link(@direct_upload).html_safe,
attachment_url: @direct_upload.relation.attachment.url}
else
@direct_upload.destroy_attachment
render json: { errors: @direct_upload.errors[:attachment].join(", ") },
status: 422
end
end
def destroy
@direct_upload = DirectUpload.new(direct_upload_params.merge(user: current_user))
@direct_upload.relation.set_attachment_from_cached_attachment
if @direct_upload.destroy_attachment
render json: :ok
else
render json: :error
end
end
private
def direct_upload_params
params.require(:direct_upload)
.permit(:resource, :resource_type, :resource_id, :resource_relation,
:attachment, :cached_attachment, attachment_attributes: [])
end
end

View File

@@ -1,29 +1,7 @@
class DocumentsController < ApplicationController
before_action :authenticate_user!
before_action :find_documentable, except: :destroy
before_action :prepare_new_document, only: [:new, :new_nested]
before_action :prepare_document_for_creation, only: :create
load_and_authorize_resource except: :upload
skip_authorization_check only: :upload
def new
end
def new_nested
end
def create
recover_attachments_from_cache
if @document.save
flash[:notice] = t "documents.actions.create.notice"
redirect_to params[:from]
else
flash[:alert] = t "documents.actions.create.alert"
render :new
end
end
load_and_authorize_resource
def destroy
respond_to do |format|
@@ -45,57 +23,4 @@ class DocumentsController < ApplicationController
end
end
def destroy_upload
@document = Document.new(cached_attachment: params[:path])
@document.set_attachment_from_cached_attachment
@document.cached_attachment = nil
@document.documentable = @documentable
if @document.attachment.destroy
flash.now[:notice] = t "documents.actions.destroy.notice"
else
flash.now[:alert] = t "documents.actions.destroy.alert"
end
render :destroy
end
def upload
@document = Document.new(document_params.merge(user: current_user))
@document.documentable = @documentable
if @document.valid?
@document.attachment.save
@document.set_cached_attachment_from_attachment(URI(request.url))
else
@document.attachment.destroy
end
end
private
def document_params
params.require(:document).permit(:title, :documentable_type, :documentable_id,
:attachment, :cached_attachment, :user_id)
end
def find_documentable
@documentable = params[:documentable_type].constantize.find_or_initialize_by(id: params[:documentable_id])
end
def prepare_new_document
@document = Document.new(documentable: @documentable, user_id: current_user.id)
end
def prepare_document_for_creation
@document = Document.new(document_params)
@document.documentable = @documentable
@document.user = current_user
end
def recover_attachments_from_cache
if @document.attachment.blank? && @document.cached_attachment.present?
@document.set_attachment_from_cached_attachment
end
end
end

View File

@@ -0,0 +1,26 @@
class ImagesController < ApplicationController
before_action :authenticate_user!
load_and_authorize_resource
def destroy
respond_to do |format|
format.html do
if @image.destroy
flash[:notice] = t "images.actions.destroy.notice"
else
flash[:alert] = t "images.actions.destroy.alert"
end
redirect_to params[:from]
end
format.js do
if @image.destroy
flash.now[:notice] = t "images.actions.destroy.notice"
else
flash.now[:alert] = t "images.actions.destroy.alert"
end
end
end
end
end

View File

@@ -30,7 +30,7 @@ class Legislation::AnnotationsController < ApplicationController
def create
if !@process.allegations_phase.open? || @draft_version.final_version?
render(json: {}, status: :not_found) && (return)
render(json: {}, status: :not_found) && return
end
existing_annotation = @draft_version.annotations.where(

View File

@@ -30,7 +30,7 @@ class Legislation::AnswersController < Legislation::BaseController
def answer_params
params.require(:legislation_answer).permit(
:legislation_question_option_id,
:legislation_question_option_id
)
end

View File

@@ -2,4 +2,8 @@ class Legislation::BaseController < ApplicationController
include FeatureFlags
feature_flag :legislation
def legislation_proposal_votes(proposals)
@legislation_proposal_votes = current_user ? current_user.legislation_proposal_votes(proposals) : {}
end
end

View File

@@ -14,6 +14,8 @@ class Legislation::ProcessesController < Legislation::BaseController
redirect_to legislation_process_draft_version_path(@process, draft_version)
elsif @process.debate_phase.enabled?
redirect_to debate_legislation_process_path(@process)
elsif @process.proposals_phase.enabled?
redirect_to proposals_legislation_process_path(@process)
else
redirect_to allegations_legislation_process_path(@process)
end
@@ -81,6 +83,18 @@ class Legislation::ProcessesController < Legislation::BaseController
end
end
def proposals
set_process
@phase = :proposals_phase
if @process.proposals_phase.started?
legislation_proposal_votes(@process.proposals)
render :proposals
else
render :phase_not_open
end
end
private
def member_method?

View File

@@ -0,0 +1,72 @@
class Legislation::ProposalsController < Legislation::BaseController
include CommentableActions
include FlagActions
load_and_authorize_resource :process, class: "Legislation::Process"
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
before_action :parse_tag_filter, only: :index
before_action :load_categories, only: [:index, :new, :create, :edit, :map, :summary]
before_action :load_geozones, only: [:edit, :map, :summary]
before_action :authenticate_user!, except: [:index, :show, :map, :summary]
invisible_captcha only: [:create, :update], honeypot: :subtitle
has_orders %w{confidence_score created_at}, only: :index
has_orders %w{most_voted newest oldest}, only: :show
helper_method :resource_model, :resource_name
respond_to :html, :js
def show
super
legislation_proposal_votes(@process.proposals)
@document = Document.new(documentable: @proposal)
if request.path != legislation_process_proposal_path(params[:process_id], @proposal)
redirect_to legislation_process_proposal_path(params[:process_id], @proposal),
status: :moved_permanently
end
end
def create
@proposal = Legislation::Proposal.new(proposal_params.merge(author: current_user))
if @proposal.save
redirect_to legislation_process_proposal_path(params[:process_id], @proposal), notice: I18n.t('flash.actions.create.proposal')
else
render :new
end
end
def index_customization
load_successful_proposals
load_featured unless @proposal_successful_exists
end
def vote
@proposal.register_vote(current_user, params[:value])
legislation_proposal_votes(@proposal)
end
private
def proposal_params
params.require(:legislation_proposal).permit(:legislation_process_id, :title,
:question, :summary, :description, :video_url, :tag_list,
:terms_of_service, :geozone_id,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
end
def resource_model
Legislation::Proposal
end
def resource_name
'proposal'
end
def load_successful_proposals
@proposal_successful_exists = Legislation::Proposal.successful.exists?
end
end

View File

@@ -4,7 +4,7 @@ class Management::DocumentVerificationsController < Management::BaseController
before_action :set_document, only: :check
def index
@document_verification = Verification::Management::Document.new()
@document_verification = Verification::Management::Document.new
end
def check

View File

@@ -11,7 +11,7 @@ class NotificationsController < ApplicationController
def show
@notification = current_user.notifications.find(params[:id])
redirect_to url_for(@notification.linkable_resource)
redirect_to linkable_resource_path(@notification)
end
def mark_all_as_read
@@ -25,4 +25,15 @@ class NotificationsController < ApplicationController
@notification.mark_as_read
end
def linkable_resource_path(notification)
case notification.linkable_resource.class.name
when "Budget::Investment"
budget_investment_path @notification.linkable_resource.budget, @notification.linkable_resource
when "Topic"
community_topic_path @notification.linkable_resource.community, @notification.linkable_resource
else
url_for @notification.linkable_resource
end
end
end

View File

@@ -7,6 +7,6 @@ class Officing::BaseController < ApplicationController
skip_authorization_check
def verify_officer
raise CanCan::AccessDenied unless current_user.try(:poll_officer?) || current_user.try(:administrator?)
raise CanCan::AccessDenied unless current_user.try(:poll_officer?)
end
end

View File

@@ -7,7 +7,9 @@ class Officing::PollsController < Officing::BaseController
def final
@polls = if current_user.poll_officer?
current_user.poll_officer.final_days_assigned_polls.select {|poll| poll.ends_at > 2.week.ago && poll.expired?}
current_user.poll_officer.final_days_assigned_polls.select do |poll|
poll.ends_at > 2.weeks.ago && poll.expired? || poll.ends_at.today?
end
else
[]
end

View File

@@ -5,7 +5,7 @@ class Officing::ResultsController < Officing::BaseController
before_action :load_partial_results, only: :new
before_action :load_officer_assignment, only: :create
before_action :check_booth_and_date, only: :create
before_action :check_officer_assignment, only: :create
before_action :build_results, only: :create
def new
@@ -26,21 +26,15 @@ class Officing::ResultsController < Officing::BaseController
@partial_results = ::Poll::PartialResult.includes(:question).
where(booth_assignment_id: index_params[:booth_assignment_id]).
where(date: index_params[:date])
@whites = ::Poll::WhiteResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
@nulls = ::Poll::NullResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
@total = ::Poll::TotalResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
@recounts = ::Poll::Recount.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date])
end
end
private
def check_booth_and_date
def check_officer_assignment
if @officer_assignment.blank?
go_back_to_new(t("officing.results.flash.error_wrong_booth"))
elsif results_params[:date].blank? ||
Date.parse(results_params[:date]) < @poll.starts_at.to_date ||
Date.parse(results_params[:date]) > @poll.ends_at.to_date
go_back_to_new(t("officing.results.flash.error_wrong_date"))
end
end
@@ -52,66 +46,41 @@ class Officing::ResultsController < Officing::BaseController
go_back_to_new if question.blank?
results.each_pair do |answer_index, count|
if count.present?
answer = question.valid_answers[answer_index.to_i]
go_back_to_new if question.blank?
next if count.blank?
answer = question.question_answers.where(given_order: answer_index.to_i + 1).first.title
go_back_to_new if question.blank?
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
date: results_params[:date],
question_id: question_id,
answer: answer)
partial_result.officer_assignment_id = @officer_assignment.id
partial_result.amount = count.to_i
partial_result.author = current_user
partial_result.origin = 'booth'
@results << partial_result
end
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
date: Date.current,
question_id: question_id,
answer: answer)
partial_result.officer_assignment_id = @officer_assignment.id
partial_result.amount = count.to_i
partial_result.author = current_user
partial_result.origin = 'booth'
@results << partial_result
end
end
build_white_results
build_null_results
build_total_results
build_recounts
end
def build_white_results
if results_params[:whites].present?
white_result = ::Poll::WhiteResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
date: results_params[:date])
white_result.officer_assignment_id = @officer_assignment.id
white_result.amount = results_params[:whites].to_i
white_result.author = current_user
white_result.origin = 'booth'
@results << white_result
end
end
def build_null_results
if results_params[:nulls].present?
null_result = ::Poll::NullResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
date: results_params[:date])
null_result.officer_assignment_id = @officer_assignment.id
null_result.amount = results_params[:nulls].to_i
null_result.author = current_user
null_result.origin = 'booth'
@results << null_result
end
end
def build_total_results
if results_params[:total].present?
total_result = ::Poll::TotalResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
date: results_params[:date])
total_result.officer_assignment_id = @officer_assignment.id
total_result.amount = results_params[:total].to_i
total_result.author = current_user
total_result.origin = 'booth'
@results << total_result
def build_recounts
recount = ::Poll::Recount.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
date: Date.current)
recount.officer_assignment_id = @officer_assignment.id
recount.author = current_user
recount.origin = 'booth'
[:whites, :nulls, :total].each do |recount_type|
if results_params[recount_type].present?
recount["#{recount_type.to_s.singularize}_amount"] = results_params[recount_type].to_i
end
end
@results << recount
end
def go_back_to_new(alert = nil)
params[:d] = results_params[:date]
params[:d] = Date.current
params[:oa] = results_params[:officer_assignment_id]
flash.now[:alert] = (alert || t("officing.results.flash.error_create"))
load_officer_assignments
@@ -120,7 +89,7 @@ class Officing::ResultsController < Officing::BaseController
end
def load_poll
@poll = ::Poll.expired.includes(:questions).find(params[:poll_id])
@poll = ::Poll.includes(:questions).find(params[:poll_id])
end
def load_officer_assignment
@@ -135,7 +104,7 @@ class Officing::ResultsController < Officing::BaseController
final.
where(id: current_user.poll_officer.officer_assignment_ids).
where("poll_booth_assignments.poll_id = ?", @poll.id).
order(date: :asc)
where(date: Date.current)
end
def load_partial_results
@@ -146,7 +115,7 @@ class Officing::ResultsController < Officing::BaseController
end
def results_params
params.permit(:officer_assignment_id, :date, :questions, :whites, :nulls, :total)
params.permit(:officer_assignment_id, :questions, :whites, :nulls, :total)
end
def index_params

View File

@@ -3,7 +3,8 @@ class Officing::VotersController < Officing::BaseController
def new
@user = User.find(params[:id])
@polls = Poll.answerable_by(@user)
booths = current_user.poll_officer.shifts.current.vote_collection.pluck(:booth_id).uniq
@polls = Poll.answerable_by(@user).where(id: Poll::BoothAssignment.where(booth: booths).pluck(:poll_id).uniq)
end
def create
@@ -12,7 +13,9 @@ class Officing::VotersController < Officing::BaseController
@voter = Poll::Voter.new(document_type: @user.document_type,
document_number: @user.document_number,
user: @user,
poll: @poll)
poll: @poll,
origin: "booth",
officer: current_user.poll_officer)
@voter.save!
end

View File

@@ -5,25 +5,19 @@ class Polls::QuestionsController < ApplicationController
has_orders %w{most_voted newest oldest}, only: :show
def show
@commentable = @question.proposal.present? ? @question.proposal : @question
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
set_comment_flags(@comment_tree.comments)
@document = Document.new(documentable: @question)
question_answer = @question.answers.where(author_id: current_user.try(:id)).first
@answers_by_question_id = {@question.id => question_answer.try(:answer)}
end
def answer
answer = @question.answers.find_or_initialize_by(author: current_user)
token = params[:token]
answer.answer = params[:answer]
answer.touch if answer.persisted?
answer.save!
answer.record_voter_participation
answer.record_voter_participation(token)
@question.question_answers.where(question_id: @question).each do |question_answer|
question_answer.set_most_voted
end
@answers_by_question_id = {@question.id => params[:answer]}
@answers_by_question_id = { @question.id => params[:answer] }
end
end

View File

@@ -1,8 +1,10 @@
class PollsController < ApplicationController
include PollsHelper
load_and_authorize_resource
has_filters %w{current expired incoming}
has_orders %w{most_voted newest oldest}, only: :show
::Poll::Answer # trigger autoload
@@ -12,12 +14,24 @@ class PollsController < ApplicationController
def show
@questions = @poll.questions.for_render.sort_for_list
@token = poll_voter_token(@poll, current_user)
@poll_questions_answers = Poll::Question::Answer.where(question: @poll.questions).where.not(description: "").order(:given_order)
@answers_by_question_id = {}
poll_answers = ::Poll::Answer.by_question(@poll.question_ids).by_author(current_user.try(:id))
poll_answers.each do |answer|
@answers_by_question_id[answer.question_id] = answer.answer
end
@commentable = @poll
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
end
def stats
@stats = Poll::Stats.new(@poll).generate
end
def results
end
end

View File

@@ -9,7 +9,7 @@ class ProposalsController < ApplicationController
invisible_captcha only: [:create, :update], honeypot: :subtitle
has_orders %w{hot_score confidence_score created_at relevance archival_date}, only: :index
has_orders ->(c) { Proposal.proposals_orders(c.current_user) }, only: :index
has_orders %w{most_voted newest oldest}, only: :show
load_and_authorize_resource
@@ -19,13 +19,11 @@ class ProposalsController < ApplicationController
def show
super
@notifications = @proposal.notifications
@document = Document.new(documentable: @proposal)
redirect_to proposal_path(@proposal), status: :moved_permanently if request.path != proposal_path(@proposal)
end
def create
@proposal = Proposal.new(proposal_params.merge(author: current_user))
recover_documents_from_cache(@proposal)
if @proposal.save
redirect_to share_proposal_path(@proposal), notice: I18n.t('flash.actions.create.proposal')
@@ -78,7 +76,9 @@ class ProposalsController < ApplicationController
def proposal_params
params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url,
:responsible_name, :tag_list, :terms_of_service, :geozone_id,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
map_location_attributes: [:latitude, :longitude, :zoom])
end
def retired_params
@@ -113,7 +113,7 @@ class ProposalsController < ApplicationController
end
def load_featured
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank?
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations"
@featured_proposals = Proposal.not_archived.sort_by_confidence_score.limit(3)
if @featured_proposals.present?
set_featured_proposal_votes(@featured_proposals)

View File

@@ -0,0 +1,11 @@
class TagsController < ApplicationController
load_and_authorize_resource class: ActsAsTaggableOn::Tag
respond_to :json
def suggest
@tags = ActsAsTaggableOn::Tag.search(params[:search]).map(&:name)
respond_with @tags
end
end

View File

@@ -1,12 +1,10 @@
class WelcomeController < ApplicationController
skip_authorization_check
before_action :set_user_recommendations, only: :index, if: :current_user
layout "devise", only: [:welcome, :verification]
def index
if current_user
redirect_to :proposals
end
end
def welcome
@@ -16,4 +14,11 @@ class WelcomeController < ApplicationController
redirect_to verification_path if signed_in?
end
private
def set_user_recommendations
@recommended_debates = Debate.recommendations(current_user).sort_by_recommendations.limit(3)
@recommended_proposals = Proposal.recommendations(current_user).sort_by_recommendations.limit(3)
end
end

View File

@@ -13,33 +13,33 @@ module AdminHelper
end
def menu_tags?
["tags"].include? controller_name
["tags"].include?(controller_name)
end
def menu_moderated_content?
["proposals", "debates", "comments", "hidden_users"].include? controller_name
["proposals", "debates", "comments", "hidden_users"].include?(controller_name) && controller.class.parent != Admin::Legislation
end
def menu_budget?
["spending_proposals"].include? controller_name
["spending_proposals"].include?(controller_name)
end
def menu_polls?
["polls", "questions", "officers", "booths", "officer_assignments", "booth_assignments", "recounts", "results", "shifts"].include? controller_name
%w[polls questions officers booths officer_assignments booth_assignments recounts results shifts questions answers].include?(controller_name)
end
def menu_profiles?
["administrators", "organizations", "officials", "moderators", "valuators", "managers", "users"].include? controller_name
%w[administrators organizations officials moderators valuators managers users activity].include?(controller_name)
end
def menu_banners?
["banners"].include? controller_name
["banners"].include?(controller_name)
end
def menu_customization?
["pages", "images", "content_blocks"].include? controller_name
["pages", "images", "content_blocks"].include?(controller_name)
end
def official_level_options
options = [["", 0]]
(1..5).each do |i|

View File

@@ -60,4 +60,8 @@ module ApplicationHelper
def format_price(number)
number_to_currency(number, precision: 0, locale: I18n.default_locale)
end
def kaminari_path(url)
"#{root_url.chomp("\/")}#{url}"
end
end

View File

@@ -4,4 +4,12 @@ module DebatesHelper
Debate.all.featured.count > 0
end
end
def empty_recommended_debates_message_text(user)
if user.interests.any?
t('debates.index.recommendations.without_results')
else
t('debates.index.recommendations.without_interests')
end
end
end

View File

@@ -0,0 +1,16 @@
module DirectUploadsHelper
def render_destroy_upload_link(direct_upload)
label = direct_upload.resource_relation == "image" ? "images" : "documents"
link_to t("#{label}.form.delete_button"),
direct_upload_destroy_url("direct_upload[resource_type]": direct_upload.resource_type,
"direct_upload[resource_id]": direct_upload.resource_id,
"direct_upload[resource_relation]": direct_upload.resource_relation,
"direct_upload[cached_attachment]": direct_upload.relation.cached_attachment,
format: :json),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
end
end

View File

@@ -8,12 +8,12 @@ module DocumentablesHelper
documentable.class.max_documents_allowed
end
def max_file_size(documentable)
bytes_to_mega(documentable.class.max_file_size)
def max_file_size(documentable_class)
bytes_to_mega(documentable_class.max_file_size)
end
def accepted_content_types(documentable)
documentable.class.accepted_content_types
def accepted_content_types(documentable_class)
documentable_class.accepted_content_types
end
def accepted_content_types_extensions(documentable_class)
@@ -22,20 +22,19 @@ module DocumentablesHelper
.join(",")
end
def humanized_accepted_content_types(documentable)
documentable.class.accepted_content_types
.collect{ |content_type| content_type.split("/").last }
.join(", ")
def documentable_humanized_accepted_content_types(documentable_class)
documentable_class.accepted_content_types
.collect{ |content_type| content_type.split("/").last }
.join(", ")
end
def documentables_note(documentable)
t "documents.form.note", max_documents_allowed: max_documents_allowed(documentable),
accepted_content_types: humanized_accepted_content_types(documentable),
max_file_size: max_file_size(documentable)
accepted_content_types: documentable_humanized_accepted_content_types(documentable.class),
max_file_size: max_file_size(documentable.class)
end
def max_documents_allowed?(documentable)
documentable.documents.count >= documentable.class.max_documents_allowed
end
end

View File

@@ -4,7 +4,7 @@ module DocumentsHelper
document.attachment_file_name
end
def errors_on_attachment(document)
def document_errors_on_attachment(document)
document.errors[:attachment].join(', ') if document.errors.key?(:attachment)
end
@@ -12,78 +12,53 @@ module DocumentsHelper
bytes / Numeric::MEGABYTE
end
def document_nested_field_name(document, index, field)
parent = document.documentable_type.parameterize.underscore
"#{parent.parameterize}[documents_attributes][#{index}][#{field}]"
end
def document_nested_field_id(document, index, field)
parent = document.documentable_type.parameterize.underscore
"#{parent.parameterize}_documents_attributes_#{index}_#{field}"
end
def document_nested_field_wrapper_id(index)
"document_#{index}"
end
def render_destroy_document_link(document, index)
if document.persisted?
def render_destroy_document_link(builder, document)
if !document.persisted? && document.cached_attachment.present?
link_to t('documents.form.delete_button'),
document_path(document, index: index, nested_document: true),
method: :delete,
remote: true,
data: { confirm: t('documents.actions.destroy.confirm') },
class: "delete float-right"
elsif !document.persisted? && document.cached_attachment.present?
link_to t('documents.form.delete_button'),
destroy_upload_documents_path(path: document.cached_attachment,
nested_document: true,
index: index,
documentable_type: document.documentable_type,
documentable_id: document.documentable_id),
method: :delete,
remote: true,
class: "delete float-right"
direct_upload_destroy_url("direct_upload[resource_type]": document.documentable_type,
"direct_upload[resource_id]": document.documentable_id,
"direct_upload[resource_relation]": "documents",
"direct_upload[cached_attachment]": document.cached_attachment),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
else
link_to t('documents.form.delete_button'),
"#",
class: "delete float-right remove-document"
link_to_remove_association t('documents.form.delete_button'), builder, class: "delete remove-document"
end
end
def render_attachment(document, index)
html = file_field_tag :attachment,
accept: accepted_content_types_extensions(document.documentable_type.constantize),
class: 'js-document-attachment',
data: {
url: document_direct_upload_url(document),
cached_attachment_input_field: document_nested_field_id(document, index, :cached_attachment),
multiple: false,
index: index,
nested_document: true
},
name: document_nested_field_name(document, index, :attachment),
id: document_nested_field_id(document, index, :attachment)
if document.attachment.blank? && document.cached_attachment.blank?
klass = document.errors[:attachment].any? ? "error" : ""
html += label_tag document_nested_field_id(document, index, :attachment),
t("documents.form.attachment_label"),
class: "button hollow #{klass}"
if document.errors[:attachment].any?
html += content_tag :small, class: "error" do
errors_on_attachment(document)
end
end
end
def render_attachment(builder, document)
klass = document.errors[:attachment].any? ? "error" : ""
klass = document.persisted? || document.cached_attachment.present? ? " hide" : ""
html = builder.label :attachment,
t("documents.form.attachment_label"),
class: "button hollow #{klass}"
html += builder.file_field :attachment,
label: false,
accept: accepted_content_types_extensions(document.documentable_type.constantize),
class: 'js-document-attachment',
data: {
url: document_direct_upload_url(document),
nested_document: true
}
html
end
def document_direct_upload_url(document)
upload_documents_url(
documentable_type: document.documentable_type,
documentable_id: document.documentable_id,
format: :js
)
direct_uploads_url("direct_upload[resource_type]": document.documentable_type,
"direct_upload[resource_id]": document.documentable_id,
"direct_upload[resource_relation]": "documents")
end
def document_item_link(document)
link_to "#{document.title} <small>(#{document.humanized_content_type} | \
#{number_to_human_size(document.attachment_file_size)}</small>)".html_safe,
document.attachment.url,
target: "_blank",
title: t("shared.target_blank_html")
end
end

View File

@@ -12,7 +12,7 @@ module FlagsHelper
def flagged?(flaggable)
if flaggable.is_a? Comment
@comment_flags[flaggable.id]
@comment_flags[flaggable.id] unless flaggable.commentable_type == "Poll"
else
Flag.flagged?(current_user, flaggable)
end

View File

@@ -0,0 +1,40 @@
module ImageablesHelper
def can_destroy_image?(imageable)
imageable.image.present? && can?(:destroy, imageable.image)
end
def imageable_class(imageable)
imageable.class.name.parameterize('_')
end
def imageable_max_file_size
bytes_to_megabytes(Image::MAX_IMAGE_SIZE)
end
def bytes_to_megabytes(bytes)
bytes / Numeric::MEGABYTE
end
def imageable_accepted_content_types
Image::ACCEPTED_CONTENT_TYPE
end
def imageable_accepted_content_types_extensions
Image::ACCEPTED_CONTENT_TYPE
.collect{ |content_type| ".#{content_type.split('/').last}" }
.join(",")
end
def imageable_humanized_accepted_content_types
Image::ACCEPTED_CONTENT_TYPE
.collect{ |content_type| content_type.split("/").last }
.join(", ")
end
def imageables_note(_imageable)
t "images.form.note", accepted_content_types: imageable_humanized_accepted_content_types,
max_file_size: imageable_max_file_size
end
end

View File

@@ -0,0 +1,79 @@
module ImagesHelper
def image_absolute_url(image, version)
return "" unless image
if Paperclip::Attachment.default_options[:storage] == :filesystem
URI(request.url) + image.attachment.url(version)
else
investment.image_url(version)
end
end
def image_first_recommendation(image)
t "images.#{image.imageable.class.name.parameterize.underscore}.recommendation_one_html",
title: image.imageable.title
end
def image_attachment_file_name(image)
image.attachment_file_name
end
def image_errors_on_attachment(image)
image.errors[:attachment].join(', ') if image.errors.key?(:attachment)
end
def image_bytes_to_megabytes(bytes)
bytes / Numeric::MEGABYTE
end
def image_class(image)
image.persisted? ? "persisted-image" : "cached-image"
end
def render_destroy_image_link(builder, image)
if !image.persisted? && image.cached_attachment.present?
link_to t('images.form.delete_button'),
direct_upload_destroy_url("direct_upload[resource_type]": image.imageable_type,
"direct_upload[resource_id]": image.imageable_id,
"direct_upload[resource_relation]": "image",
"direct_upload[cached_attachment]": image.cached_attachment),
method: :delete,
remote: true,
class: "delete remove-cached-attachment"
else
link_to_remove_association t('images.form.delete_button'), builder, class: "delete remove-image"
end
end
def render_image_attachment(builder, imageable, image)
klass = image.errors[:attachment].any? ? "error" : ""
klass = image.persisted? || image.cached_attachment.present? ? " hide" : ""
html = builder.label :attachment,
t("images.form.attachment_label"),
class: "button hollow #{klass}"
html += builder.file_field :attachment,
label: false,
accept: imageable_accepted_content_types_extensions,
class: 'js-image-attachment',
data: {
url: image_direct_upload_url(imageable),
nested_image: true
}
html
end
def render_image(image, version, show_caption = true)
version = image.persisted? ? version : :original
render partial: "images/image", locals: { image: image,
version: version,
show_caption: show_caption }
end
def image_direct_upload_url(imageable)
direct_uploads_url("direct_upload[resource_type]": imageable.class.name,
"direct_upload[resource_id]": imageable.id,
"direct_upload[resource_relation]": "image")
end
end

View File

@@ -1,6 +1,6 @@
module LegislationHelper
def format_date(date)
l(date, format: "%d %b %Y") if date
l(date, format: "%d %h %Y") if date
end
def format_date_for_calendar_form(date)

View File

@@ -0,0 +1,67 @@
module MapLocationsHelper
def map_location_available?(map_location)
map_location.present? && map_location.available?
end
def map_location_latitude(map_location)
map_location.present? && map_location.latitude.present? ? map_location.latitude : Setting["map_latitude"]
end
def map_location_longitude(map_location)
map_location.present? && map_location.longitude.present? ? map_location.longitude : Setting["map_longitude"]
end
def map_location_zoom(map_location)
map_location.present? && map_location.zoom.present? ? map_location.zoom : Setting["map_zoom"]
end
def map_location_input_id(prefix, attribute)
"#{prefix}_map_location_attributes_#{attribute}"
end
def map_location_remove_marker_link_id(map_location)
"remove-marker-link-#{dom_id(map_location)}"
end
def render_map(map_location, parent_class, editable, remove_marker_label)
map = content_tag_for :div,
map_location,
class: "map",
data: prepare_map_settings(map_location, editable, parent_class)
map += map_location_remove_marker(map_location, remove_marker_label) if editable
map
end
def map_location_remove_marker(map_location, text)
content_tag :div, class: "text-right" do
content_tag :a,
id: map_location_remove_marker_link_id(map_location),
href: "#",
class: "location-map-remove-marker-button delete" do
text
end
end
end
private
def prepare_map_settings(map_location, editable, parent_class)
options = {
map: "",
map_center_latitude: map_location_latitude(map_location),
map_center_longitude: map_location_longitude(map_location),
map_zoom: map_location_zoom(map_location),
map_tiles_provider: Rails.application.secrets.map_tiles_provider,
map_tiles_provider_attribution: Rails.application.secrets.map_tiles_provider_attribution,
marker_editable: editable,
marker_latitude: map_location.latitude,
marker_longitude: map_location.longitude,
marker_remove_selector: "##{map_location_remove_marker_link_id(map_location)}",
latitude_input_selector: "##{map_location_input_id(parent_class, 'latitude')}",
longitude_input_selector: "##{map_location_input_id(parent_class, 'longitude')}",
zoom_input_selector: "##{map_location_input_id(parent_class, 'zoom')}"
}
end
end

View File

@@ -1,7 +1,7 @@
module PollRecountsHelper
def total_recounts_by_booth(booth_assignment)
booth_assignment.total_results.any? ? booth_assignment.total_results.to_a.sum(&:amount) : nil
booth_assignment.recounts.any? ? booth_assignment.recounts.to_a.sum(&:total_amount) : nil
end
end

View File

@@ -41,4 +41,12 @@ module PollsHelper
booth.name + location
end
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

View File

@@ -12,8 +12,8 @@ module ProposalsHelper
percentage = (proposal.total_votes.to_f * 100 / Proposal.votes_needed_for_success)
case percentage
when 0 then "0%"
when 0..(0.1) then "0.1%"
when (0.1)..100 then number_to_percentage(percentage, strip_insignificant_zeros: true, precision: 1)
when 0..0.1 then "0.1%"
when 0.1..100 then number_to_percentage(percentage, strip_insignificant_zeros: true, precision: 1)
else "100%"
end
end
@@ -32,8 +32,12 @@ module ProposalsHelper
Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] }
end
def can_create_document?(document, proposal)
can?(:create, document) && proposal.documents.size < Proposal.max_documents_allowed
def empty_recommended_proposals_message_text(user)
if user.interests.any?
t('proposals.index.recommendations.without_results')
else
t('proposals.index.recommendations.without_interests')
end
end
def author_of_proposal?(proposal)
@@ -44,4 +48,4 @@ module ProposalsHelper
current_user && proposal.editable_by?(current_user)
end
end
end

View File

@@ -1,15 +1,30 @@
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)]
def shift_vote_collection_dates(booth, polls)
return [] if polls.blank?
date_options((start_date(polls)..end_date(polls)), Poll::Shift.tasks[:vote_collection], booth)
end
def shift_recount_scrutiny_dates(booth, polls)
return [] if polls.blank?
dates = polls.map(&:ends_at).map(&:to_date).sort.inject([]) do |total, date|
initial_date = date < Date.current ? Date.current : date
total << (initial_date..date + Poll::RECOUNT_DURATION).to_a
end
options_for_select(options, params[:date])
date_options(dates.flatten.uniq, Poll::Shift.tasks[:recount_scrutiny], booth)
end
def date_options(dates, task_id, booth)
valid_dates(dates, task_id, booth).map { |date| [l(date, format: :long), l(date)] }
end
def valid_dates(dates, task_id, booth)
dates.reject { |date| officer_shifts(task_id, booth).include?(date) }
end
def start_date(polls)
polls.map(&:starts_at).min.to_date
start_date = polls.map(&:starts_at).min.to_date
start_date < Date.current ? Date.current : start_date
end
def end_date(polls)
@@ -20,4 +35,9 @@ module ShiftsHelper
officers.collect { |officer| [officer.name, officer.id] }
end
private
def officer_shifts(task_id, booth)
@officer.shifts.where(task: task_id, booth: booth).map(&:date)
end
end

View File

@@ -8,6 +8,8 @@ module TagsHelper
proposals_path(search: tag_name)
when 'budget/investment'
budget_investments_path(@budget, search: tag_name)
when 'legislation/proposal'
legislation_process_proposals_path(@process, search: tag_name)
else
'#'
end
@@ -22,6 +24,8 @@ module TagsHelper
proposal_path(taggable)
when 'budget/investment'
budget_investment_path(taggable.budget_id, taggable)
when 'legislation/proposal'
legislation_process_proposal_path(@process, taggable)
else
'#'
end

View File

@@ -52,12 +52,8 @@ module UsersHelper
current_user && current_user.manager?
end
def current_poll_officer?
current_user && current_user.poll_officer?
end
def show_admin_menu?
current_administrator? || current_moderator? || current_valuator? || current_manager? || current_poll_officer?
current_administrator? || current_moderator? || current_valuator? || current_manager?
end
def interests_title_text(user)

View File

@@ -0,0 +1,58 @@
module WelcomeHelper
def active_class(index)
"is-active is-in" if index.zero?
end
def slide_display(index)
"display: none;" if index.positive?
end
def recommended_path(recommended)
case recommended.class.name
when "Debate"
debate_path(recommended)
when "Proposal"
proposal_path(recommended)
else
'#'
end
end
def render_recommendation_image(recommended, image_default)
image_path = calculate_image_path(recommended, image_default)
image_tag(image_path) if image_path.present?
end
def calculate_image_path(recommended, image_default)
if recommended.try(:image) && recommended.image.present? && recommended.image.attachment.exists?
recommended.image.attachment.send("url", :medium)
elsif image_default.present?
image_default
end
end
def calculate_carousel_size(debates, proposals, apply_offset)
offset = calculate_offset(debates, proposals, apply_offset)
centered = calculate_centered(debates, proposals)
"#{offset if offset} #{centered if centered}"
end
def calculate_centered(debates, proposals)
if (debates.blank? && proposals.any?) ||
(debates.any? && proposals.blank?)
centered = "medium-centered large-centered"
end
end
def calculate_offset(debates, proposals, apply_offset)
if debates.any? && proposals.any?
offset = if apply_offset
"medium-offset-2 large-offset-2"
else
"end"
end
end
end
end

View File

@@ -14,6 +14,9 @@ module Abilities
can :restore, Proposal
cannot :restore, Proposal, hidden_at: nil
can :restore, Legislation::Proposal
cannot :restore, Legislation::Proposal, hidden_at: nil
can :restore, User
cannot :restore, User, hidden_at: nil
@@ -26,6 +29,9 @@ module Abilities
can :confirm_hide, Proposal
cannot :confirm_hide, Proposal, hidden_at: nil
can :confirm_hide, Legislation::Proposal
cannot :confirm_hide, Legislation::Proposal, hidden_at: nil
can :confirm_hide, User
cannot :confirm_hide, User, hidden_at: nil
@@ -33,11 +39,11 @@ module Abilities
can :unmark_featured, Debate
can :comment_as_administrator, [Debate, Comment, Proposal, Poll::Question, Budget::Investment,
Legislation::Question, Legislation::Annotation, Topic]
Legislation::Question, Legislation::Proposal, Legislation::Annotation, Topic]
can [:search, :create, :index, :destroy], ::Administrator
can [:search, :create, :index, :destroy], ::Moderator
can [:search, :create, :index, :summary], ::Valuator
can [:search, :create, :index, :destroy, :summary], ::Valuator
can [:search, :create, :index, :destroy], ::Manager
can [:search, :index], ::User
@@ -45,7 +51,7 @@ module Abilities
can [:read, :update, :valuate, :destroy, :summary], SpendingProposal
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners], Budget
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners, :read_results], Budget
can [:read, :create, :update, :destroy], Budget::Group
can [:read, :create, :update, :destroy], Budget::Heading
can [:hide, :update, :toggle_selection], Budget::Investment
@@ -56,10 +62,10 @@ module Abilities
can [:index, :create, :edit, :update, :destroy], Geozone
can [:read, :create, :update, :destroy, :add_question, :remove_question, :search_booths, :search_questions, :search_officers], Poll
can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers, :booth_assignments, :results, :stats], Poll
can [:read, :create, :update, :destroy, :available], Poll::Booth
can [:search, :create, :index, :destroy], ::Poll::Officer
can [:create, :destroy], ::Poll::BoothAssignment
can [:create, :destroy, :manage], ::Poll::BoothAssignment
can [:create, :destroy], ::Poll::OfficerAssignment
can [:read, :create, :update], Poll::Question
can :destroy, Poll::Question # , comments_count: 0, votes_up: 0
@@ -71,9 +77,12 @@ module Abilities
can [:manage], ::Legislation::Process
can [:manage], ::Legislation::DraftVersion
can [:manage], ::Legislation::Question
cannot :comment_as_moderator, [::Legislation::Question, Legislation::Annotation]
can [:manage], ::Legislation::Proposal
cannot :comment_as_moderator, [::Legislation::Question, Legislation::Annotation, ::Legislation::Proposal]
can [:create, :destroy], Document
can [:destroy], Image
can [:create, :destroy], DirectUpload
end
end
end

View File

@@ -18,12 +18,21 @@ module Abilities
end
can [:retire_form, :retire], Proposal, author_id: user.id
can :read, Legislation::Proposal
cannot [:edit, :update], Legislation::Proposal do |proposal|
proposal.editable_by?(user)
end
can [:retire_form, :retire], Legislation::Proposal, author_id: user.id
can :create, Comment
can :create, Debate
can :create, Proposal
can :create, Legislation::Proposal
can :suggest, Debate
can :suggest, Proposal
can :suggest, Legislation::Proposal
can :suggest, ActsAsTaggableOn::Tag
can [:flag, :unflag], Comment
cannot [:flag, :unflag], Comment, user_id: user.id
@@ -34,10 +43,16 @@ module Abilities
can [:flag, :unflag], Proposal
cannot [:flag, :unflag], Proposal, author_id: user.id
can [:flag, :unflag], Legislation::Proposal
cannot [:flag, :unflag], Legislation::Proposal, author_id: user.id
can [:create, :destroy], Follow
can [:create, :destroy, :new], Document, documentable: { author_id: user.id }
can [:new_nested, :upload, :destroy_upload], Document
can [:destroy], Document, documentable: { author_id: user.id }
can [:destroy], Image, imageable: { author_id: user.id }
can [:create, :destroy], DirectUpload
unless user.organization?
can :vote, Debate
@@ -50,10 +65,15 @@ module Abilities
can :vote, SpendingProposal
can :create, SpendingProposal
can :vote, Legislation::Proposal
can :vote_featured, Legislation::Proposal
can :create, Legislation::Answer
can :create, Budget::Investment, budget: { phase: "accepting" }
can :suggest, Budget::Investment, budget: { phase: "accepting" }
can :destroy, Budget::Investment, budget: { phase: ["accepting", "reviewing"] }, author_id: user.id
can :vote, Budget::Investment, budget: { phase: "selecting" }
can [:show, :create], Budget::Ballot, budget: { phase: "balloting" }
can [:create, :destroy], Budget::Ballot::Line, budget: { phase: "balloting" }

View File

@@ -7,6 +7,12 @@ module Abilities
can [:read, :map, :summary, :share], Proposal
can :read, Comment
can :read, Poll
can :results, Poll do |poll|
poll.expired? && poll.results_enabled?
end
can :stats, Poll do |poll|
poll.expired? && poll.stats_enabled?
end
can :read, Poll::Question
can [:read, :welcome], Budget
can :read, SpendingProposal
@@ -18,10 +24,10 @@ module Abilities
can [:read, :print], Budget::Investment
can :read_results, Budget, phase: "finished"
can :new, DirectMessage
can [:read, :debate, :draft_publication, :allegations, :result_publication], Legislation::Process, published: true
can [:read, :debate, :draft_publication, :allegations, :result_publication, :proposals], Legislation::Process, published: true
can [:read, :changes, :go_to_version], Legislation::DraftVersion
can [:read], Legislation::Question
can [:create], Legislation::Answer
can [:read, :map, :share], Legislation::Proposal
can [:search, :comments, :read, :create, :new_comment], Legislation::Annotation
end
end

View File

@@ -38,6 +38,15 @@ module Abilities
can :moderate, Proposal
cannot :moderate, Proposal, author_id: user.id
can :hide, Legislation::Proposal, hidden_at: nil
cannot :hide, Legislation::Proposal, author_id: user.id
can :ignore_flag, Legislation::Proposal, ignored_flag_at: nil, hidden_at: nil
cannot :ignore_flag, Legislation::Proposal, author_id: user.id
can :moderate, Legislation::Proposal
cannot :moderate, Legislation::Proposal, author_id: user.id
can :hide, User
cannot :hide, User, id: user.id

Some files were not shown because too many files have changed in this diff Show More