voluntary 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +1 -1
  4. data/app/assets/javascripts/voluntary/lib/jquery-competitive_list.js +3 -7
  5. data/app/assets/javascripts/voluntary/lib/sugar.js +8264 -0
  6. data/app/assets/stylesheets/voluntary/bootstrap_and_overrides.css.sass +1 -1
  7. data/app/controllers/voluntary/api/v1/argument_topics_controller.rb +18 -0
  8. data/app/controllers/voluntary/api/v1/arguments_controller.rb +76 -0
  9. data/app/controllers/voluntary/api/v1/things/arguments_controller.rb +48 -0
  10. data/app/controllers/voluntary/api/v1/users_controller.rb +9 -0
  11. data/app/models/argument.rb +58 -0
  12. data/app/models/argument_topic.rb +17 -0
  13. data/app/models/user.rb +1 -0
  14. data/app/serializers/application_serializer.rb +2 -0
  15. data/app/serializers/argument_serializer.rb +19 -0
  16. data/app/serializers/basic_user_serializer.rb +3 -0
  17. data/app/serializers/current_user_serializer.rb +3 -0
  18. data/app/serializers/user_serializer.rb +2 -0
  19. data/app/views/layouts/application.html.erb +1 -1
  20. data/app/views/shared/layouts/twitter_bootstrap/_control_group.html.erb +1 -1
  21. data/app/views/shared/layouts/twitter_bootstrap/_modal.html.erb +13 -9
  22. data/config/initializers/active_model_serializer.rb +4 -0
  23. data/config/locales/general/en.yml +15 -1
  24. data/config/locales/resources/argument/en.yml +28 -0
  25. data/config/locales/resources/argument_topic/en.yml +9 -0
  26. data/config/locales/resources/like/en.yml +6 -0
  27. data/config/routes/api.rb +12 -0
  28. data/db/migrate/20121006162913_add_public_attribute_to_roles.rb +3 -0
  29. data/db/migrate/20150818151512_create_or_alter_arguments.rb +49 -0
  30. data/db/migrate/20150821102558_add_vote_column_to_arguments.rb +6 -0
  31. data/db/migrate/20150823174056_add_likes_count_to_arguments.rb +6 -0
  32. data/lib/generators/voluntary/product_dummy/templates/features/step_definitions/session_steps.rb +1 -0
  33. data/lib/generators/voluntary/product_dummy/templates/features/step_definitions/web_steps.rb +4 -0
  34. data/lib/generators/voluntary/product_dummy/templates/features/support/env.rb +4 -0
  35. data/lib/voluntary/engine.rb +1 -0
  36. data/lib/voluntary/test/rspec_helpers/factories.rb +4 -0
  37. data/lib/voluntary/version.rb +1 -1
  38. data/lib/voluntary.rb +1 -1
  39. metadata +35 -4
  40. data/lib/generators/voluntary/product_dummy/templates/features/step_definitions/state_machines/vacancy_steps.rb +0 -7
@@ -14,4 +14,4 @@
14
14
  overflow-y: auto
15
15
 
16
16
  #bootstrap_modal
17
- width: 800px !important
17
+ width: 900px !important
@@ -0,0 +1,18 @@
1
+ module Voluntary
2
+ module Api
3
+ module V1
4
+ class ArgumentTopicsController < ActionController::Base
5
+ include Voluntary::V1::BaseController
6
+
7
+ respond_to :json
8
+
9
+ def autocomplete
10
+ render json: (
11
+ ArgumentTopic.order(:name).where("name LIKE ?", "%#{params[:term]}%").
12
+ map{|t| { id: t.id, value: t.name.truncate(50) }}
13
+ ), root: false
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,76 @@
1
+ module Voluntary
2
+ module Api
3
+ module V1
4
+ class ArgumentsController < ActionController::Base
5
+ include Voluntary::V1::BaseController
6
+
7
+ respond_to :json
8
+
9
+ def index
10
+ options = {}
11
+
12
+ arguments = Argument
13
+ arguments = Argument.where(
14
+ argumentable_type: params[:argumentable_type], argumentable_id: params[:argumentable_id]
15
+ ) if params[:argumentable_id].present?
16
+ options[:json] = arguments.paginate(page: params[:page], per_page: 10)
17
+
18
+ options[:meta] = {
19
+ pagination: {
20
+ total_pages: options[:json].total_pages, current_page: options[:json].current_page,
21
+ previous_page: options[:json].previous_page, next_page: options[:json].next_page
22
+ }
23
+ }
24
+
25
+ respond_with do |format|
26
+ format.json { render options }
27
+ end
28
+ end
29
+
30
+ def create
31
+ raise CanCan::AccessDenied if current_user.blank?
32
+
33
+ respond_to do |format|
34
+ format.json { render json: Argument.create_with_topic(current_user.id, params[:argument]) }
35
+ end
36
+ end
37
+
38
+ def update
39
+ resource = current_user.arguments.where('arguments.id = ?', params[:id]).first
40
+ errors = {}
41
+
42
+ if resource.nil?
43
+ errors[:base] = I18n.t('activerecord.errors.models.general.attributes.base.user_resource_not_found')
44
+ else
45
+ topic = ArgumentTopic.find_or_create_by_name params[:argument][:topic_name]
46
+ params[:argument][:topic_id] = topic.id
47
+ resource.update_attributes params[:argument]
48
+ resource.valid?
49
+ errors = resource.errors.to_hash
50
+ end
51
+
52
+ respond_to do |format|
53
+ format.json do
54
+ render json: errors.empty? ? resource : { errors: errors }
55
+ end
56
+ end
57
+ end
58
+
59
+ def destroy
60
+ resource = current_user.arguments.find params[:id]
61
+ resource.destroy
62
+
63
+ respond_to do |format|
64
+ format.json do
65
+ render json: if resource.persisted?
66
+ { error: I18n.t('activerecord.errors.models.argument.attributes.base.deletion_failed') }
67
+ else
68
+ {}
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,48 @@
1
+ module Voluntary
2
+ module Api
3
+ module V1
4
+ module Things
5
+ class ArgumentsController < ActionController::Base
6
+ include Voluntary::V1::BaseController
7
+
8
+ respond_to :json
9
+
10
+ def comparison
11
+ options = {}
12
+
13
+ arguments = Argument.compare_two_argumentables(params[:argumentable_type], params[:side], params[:left_thing_name], params[:right_thing_name]).
14
+ paginate(page: params[:page], per_page: 10)
15
+
16
+ options[:json] = arguments.map do |argument_comparison|
17
+ hash = {
18
+ left: { id: argument_comparison.id, value: argument_comparison.value },
19
+ right: { id: argument_comparison.right_id, value: argument_comparison.right_value },
20
+ topic: { id: argument_comparison.topic_id, name: argument_comparison.topic_name }
21
+ }
22
+
23
+ if params[:side] == 'right'
24
+ left = hash[:left].clone
25
+ right = hash[:right].clone
26
+ hash[:left] = right
27
+ hash[:right] = left
28
+ end
29
+
30
+ hash
31
+ end
32
+
33
+ options[:meta] = {
34
+ pagination: {
35
+ total_pages: arguments.total_pages, current_page: arguments.current_page,
36
+ previous_page: arguments.previous_page, next_page: arguments.next_page
37
+ }
38
+ }
39
+
40
+ respond_with do |format|
41
+ format.json { render options }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ class Voluntary::Api::V1::UsersController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def show
7
+ respond_with User.friendly.find(params[:id])
8
+ end
9
+ end
@@ -0,0 +1,58 @@
1
+ class Argument < ActiveRecord::Base
2
+ include Likeable
3
+
4
+ belongs_to :user
5
+ belongs_to :topic, class_name: 'ArgumentTopic'
6
+ belongs_to :argumentable, polymorphic: true
7
+
8
+ scope :compare_two_argumentables, ->(argumentable_type, side, left_argumentable_name, right_argumentable_name) do
9
+ left_argumentable_name, right_argumentable_name = right_argumentable_name, left_argumentable_name if side == 'right'
10
+
11
+ left_argumentable = argumentable_type.constantize.where('LOWER(name) = ?', left_argumentable_name.downcase).first
12
+ right_argumentable = argumentable_type.constantize.where('LOWER(name) = ?', right_argumentable_name.downcase).first
13
+
14
+ scope = joins(:topic).select('arguments.id, arguments.value, arguments.topic_id, argument_topics.name AS topic_name, arguments2.id AS right_id, arguments2.value AS right_value').
15
+ joins(
16
+ "#{side == 'both' ? 'INNER' : 'LEFT'} JOIN arguments arguments2 ON " +
17
+ "arguments2.argumentable_type = #{sanitize(argumentable_type)} AND " +
18
+ "arguments2.argumentable_id = #{sanitize(right_argumentable.id)} AND arguments2.topic_id = arguments.topic_id"
19
+ )
20
+ scope = scope.where('arguments2.id IS NULL') unless side == 'both'
21
+ scope.where('arguments.argumentable_type = ? AND arguments.argumentable_id = ?', argumentable_type, left_argumentable.id)
22
+ end
23
+
24
+ validates :topic_id, presence: true
25
+ validates :argumentable_type, presence: true
26
+ validates :argumentable_id, presence: true, uniqueness: { scope: [:topic_id, :argumentable_type] }
27
+
28
+ attr_accessible :topic_id, :argumentable_type, :argumentable_id, :vote, :value
29
+
30
+ attr_accessor :positive
31
+
32
+ def self.create_with_topic(user_id, attributes)
33
+ topic = ArgumentTopic.find_or_create_by_name attributes[:topic_name]
34
+
35
+ if topic.valid?
36
+ argumentable_id = if attributes[:argumentable_name].present?
37
+ attributes[:argumentable_type].constantize.where('LOWER(name) = ?', attributes[:argumentable_name].downcase).first.id
38
+ else
39
+ attributes[:argumentable_type].constantize.where(id: attributes[:argumentable_id]).first.try(:id)
40
+ end
41
+
42
+ argument = Argument.new(
43
+ topic_id: topic.id, argumentable_type: attributes[:argumentable_type], argumentable_id: argumentable_id,
44
+ value: attributes[:value], vote: attributes[:vote]
45
+ )
46
+ argument.user_id = user_id
47
+ argument.save
48
+
49
+ if argument.valid?
50
+ argument
51
+ else
52
+ { errors: argument.errors.to_hash }
53
+ end
54
+ else
55
+ { errors: { topic: topic.errors.to_hash } }
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ class ArgumentTopic < ActiveRecord::Base
2
+ has_many :arguments
3
+
4
+ validates :name, presence: true, uniqueness: { case_sensitive: false }
5
+
6
+ attr_accessible :name, :text
7
+
8
+ def self.find_or_create_by_name(name)
9
+ resource = where('LOWER(name) = ?', name.to_s.strip.downcase).first
10
+
11
+ if resource
12
+ resource
13
+ else
14
+ resource = create(name: name.to_s.strip)
15
+ end
16
+ end
17
+ end
data/app/models/user.rb CHANGED
@@ -10,6 +10,7 @@ class User < ActiveRecord::Base
10
10
  has_and_belongs_to_many :areas
11
11
  has_and_belongs_to_many :projects
12
12
 
13
+ has_many :arguments, dependent: :nullify
13
14
  has_many :organizations, dependent: :destroy
14
15
  def stories; Story.where(offeror_id: id); end
15
16
 
@@ -0,0 +1,2 @@
1
+ class ApplicationSerializer < ActiveModel::Serializer
2
+ end
@@ -0,0 +1,19 @@
1
+ class ArgumentSerializer < ActiveModel::Serializer
2
+ attributes :id, :vote, :topic_id, :topic_name, :argumentable_type, :argumentable_id, :argumentable_name, :value, :user_id, :user_name, :user_slug, :positive, :likes_count, :dislikes_count
3
+
4
+ def argumentable_name
5
+ object.argumentable.try(:name)
6
+ end
7
+
8
+ def topic_name
9
+ object.topic.try(:name)
10
+ end
11
+
12
+ def user_name
13
+ object.user.try(:name)
14
+ end
15
+
16
+ def user_slug
17
+ object.user.try(:slug)
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ class BasicUserSerializer < ApplicationSerializer
2
+ attributes :id, :slug, :name, :email
3
+ end
@@ -0,0 +1,3 @@
1
+ class CurrentUserSerializer < BasicUserSerializer
2
+ #attributes :admin?
3
+ end
@@ -0,0 +1,2 @@
1
+ class UserSerializer < BasicUserSerializer
2
+ end
@@ -9,7 +9,7 @@
9
9
  <link href="//netdna.bootstrapcdn.com/font-awesome/3.1.1/css/font-awesome.css" rel="stylesheet"/>
10
10
  </head>
11
11
  <body>
12
- <div id="bootstrap_modal" class="modal hide fade"></div>
12
+ <div id="bootstrap_modal" class="modal fade"></div>
13
13
 
14
14
  <section id="dialog">
15
15
  <img alt="Ajax-loader-small" class="hide " id="dialog_body_spinner" src="<%=image_path('voluntary/spinner.gif')%>"/>
@@ -1,4 +1,4 @@
1
- <% id ||= field.match(/id="([^"]*)"/)[1] %>
1
+ <% id ||= field.match(/id="([^"]*)"/)[1] if field.match(/id="([^"]*)"/) %>
2
2
  <% required ||= false %>
3
3
  <% required_class = required ? 'required' : 'optional' %>
4
4
  <div class="form-group string <%= required_class %> <%= id %>">
@@ -1,12 +1,16 @@
1
1
  <% body ||= nil %>
2
2
  <% footer ||= nil %>
3
- <div class="modal-header">
4
- <button type="button" id="close_bootstrap_modal_button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
5
- <h3><%= title %></h3>
3
+ <div class="modal-dialog">
4
+ <div class="modal-content">
5
+ <div class="modal-header">
6
+ <button type="button" id="close_bootstrap_modal_button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
7
+ <h3><%= title %></h3>
8
+ </div>
9
+ <div class="modal-body" style="overflow-y:none;">
10
+ <%= body || yield(:modal_body) %>
11
+ </div>
12
+ <div class="modal-footer">
13
+ <%= footer || yield(:modal_footer) %>
14
+ </div>
15
+ </div>
6
16
  </div>
7
- <div class="modal-body" style="overflow-y:none;">
8
- <%= body || yield(:modal_body) %>
9
- </div>
10
- <div class="modal-footer">
11
- <%= footer || yield(:modal_footer) %>
12
- </div>
@@ -0,0 +1,4 @@
1
+ ActiveModel::Serializer.setup do |config|
2
+ config.embed = :ids
3
+ config.embed_in_root = true
4
+ end
@@ -1,5 +1,17 @@
1
1
  en:
2
2
  general:
3
+ account: Account
4
+ anonymous: Anonymous
5
+ authentication: Authentication
6
+ author: Author
7
+ cancel: Cancel
8
+ contra: contra
9
+ issues: Issues
10
+ neutral: neutral
11
+ pro: pro
12
+ sign_out: Sign out
13
+ vote: Vote
14
+
3
15
  index:
4
16
  title: Home
5
17
  search: Search
@@ -34,7 +46,7 @@ en:
34
46
  activate: Activate
35
47
  exceptions:
36
48
  wrong_recaptcha: The captcha code which you typed in is wrong.
37
- access_denied: Access denied
49
+ access_denied: Access denied!
38
50
  not_found: Resource not found.
39
51
  notifications:
40
52
  event_successful: "%{event} successful."
@@ -82,5 +94,7 @@ en:
82
94
  models:
83
95
  general:
84
96
  attributes:
97
+ base:
98
+ user_resource_not_found: Resource not found for your account!
85
99
  name:
86
100
  reserved_word_included: is a reserved word
@@ -0,0 +1,28 @@
1
+ en:
2
+ arguments:
3
+ index:
4
+ title: Arguments
5
+ new:
6
+ title: New Argument
7
+ save:
8
+ failed: Something went wrong at saving argument
9
+ successful: Successfully saved argument.
10
+ create:
11
+ title: Create Argument
12
+ update:
13
+ title: Update Argument
14
+ destroy:
15
+ failed: Removing argument failed!
16
+ successful: Successfully removed argument.
17
+ model:
18
+ publish_create_to_brainstorming: A new argument has been added
19
+ publish_update_to_brainstorming: An argument has been updated
20
+ publish_destroy_to_brainstorming: An argument has been removed
21
+
22
+ activerecord:
23
+ errors:
24
+ models:
25
+ argument:
26
+ attributes:
27
+ base:
28
+ deletion_failed: Brainstorming idea argument could not be deleted!
@@ -0,0 +1,9 @@
1
+ en:
2
+ activerecord:
3
+ models:
4
+ argument_topic: Argument Topic
5
+ argument_topic_short: Topic
6
+
7
+ attributes:
8
+ argument_topic:
9
+ value: Value
@@ -1,5 +1,11 @@
1
1
  en:
2
2
  likes:
3
+ create:
4
+ like_failed: Liking failed!
5
+ dislike_failed: Disliking failed!
6
+ destroy:
7
+ unlike_failed: Undoing like failed!
8
+ undo_dislike_failed: Undoing dislike failed!
3
9
  actions:
4
10
  like: Like
5
11
  dislike: Dislike
data/config/routes/api.rb CHANGED
@@ -3,5 +3,17 @@ namespace :voluntary, path: 'api', module: 'voluntary/api', defaults: {format: '
3
3
  resources :stories, only: [] do
4
4
  resources :tasks, only: [:index, :create]
5
5
  end
6
+
7
+ resources :argument_topics, only: [] do
8
+ collection do
9
+ get :autocomplete
10
+ end
11
+ end
12
+
13
+ resources :arguments
14
+
15
+ get '/things/:left_thing_name/vs/:right_thing_name/arguments', to: 'things/arguments#comparison'
16
+
17
+ resources :users
6
18
  end
7
19
  end
@@ -1,3 +1,6 @@
1
+ class Role < ActiveRecord::Base
2
+ end
3
+
1
4
  class AddPublicAttributeToRoles < ActiveRecord::Migration
2
5
  def up
3
6
  add_column :roles, :public, :boolean, default: false
@@ -0,0 +1,49 @@
1
+ class CreateOrAlterArguments < ActiveRecord::Migration
2
+ def up
3
+ if (Product::Ranking rescue nil)
4
+ add_column :arguments, :argumentable_type, :string
5
+ add_column :arguments, :argumentable_id, :integer
6
+
7
+ Argument.update_all 'argumentable_type = "Thing", argumentable_id = thing_id'
8
+
9
+ remove_column :arguments, :thing_id
10
+ add_index :arguments, [:topic_id, :argumentable_id, :argumentable_type], name: 'arguments_index_on_argumentable_topic', unique: true
11
+ add_index :arguments, [:argumentable_id, :argumentable_type], name: 'arguments_index_on_argumentable'
12
+ else
13
+ create_table :argument_topics do |t|
14
+ t.string :name
15
+ t.text :text
16
+ t.timestamps
17
+ end
18
+
19
+ add_index :argument_topics, :name, unique: true
20
+
21
+ create_table :arguments do |t|
22
+ t.string :argumentable_type
23
+ t.integer :argumentable_id
24
+ t.integer :topic_id
25
+ t.string :value
26
+ t.timestamps
27
+ end
28
+
29
+ add_index :arguments, [:topic_id, :argumentable_id, :argumentable_type], name: 'arguments_index_on_argumentable_topic', unique: true
30
+ add_index :arguments, [:argumentable_id, :argumentable_type], name: 'arguments_index_on_argumentable'
31
+ end
32
+ end
33
+
34
+ def down
35
+ if (Product::Ranking rescue nil)
36
+ add_column :arguments, :thing_id, :integer
37
+
38
+ Argument.where(argumentable_type: 'Thing').update_all 'thing_id = argumentable_id'
39
+
40
+ remove_column :arguments, :argumentable_type
41
+ remove_column :arguments, :argumentable_id
42
+
43
+ add_index :arguments, [:topic_id, :thing_id], unique: true
44
+ else
45
+ remove_table :argument_topics
46
+ remove_table :arguments
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,6 @@
1
+ class AddVoteColumnToArguments < ActiveRecord::Migration
2
+ def change
3
+ add_column :arguments, :user_id, :integer
4
+ add_column :arguments, :vote, :boolean
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddLikesCountToArguments < ActiveRecord::Migration
2
+ def change
3
+ add_column :arguments, :likes_count, :integer, default: 0
4
+ add_column :arguments, :dislikes_count, :integer, default: 0
5
+ end
6
+ end
@@ -8,6 +8,7 @@ When /^I (?:sign|log) in as "([^"]*)"$/ do |name|
8
8
  @me = User.find_by_name(name)
9
9
  @me.password = 'password'
10
10
  automatic_login
11
+ step %(I should see "Signed in successfully.")
11
12
  end
12
13
 
13
14
  When /^I fill out change password section with my password and "([^"]*)" and "([^"]*)"$/ do |new_pass, confirm_pass|
@@ -269,3 +269,7 @@ end
269
269
  Then /^show me the page$/ do
270
270
  save_and_open_page
271
271
  end
272
+
273
+ Then /^wait (\d+) second(?:s)?$/ do |seconds|
274
+ sleep(seconds.to_i)
275
+ end
@@ -22,6 +22,10 @@ require File.join(File.dirname(__FILE__), "integration_sessions_controller")
22
22
  # steps to use the XPath syntax.
23
23
  Capybara.default_selector = :css
24
24
 
25
+ Capybara.register_driver :chrome do |app|
26
+ Capybara::Selenium::Driver.new(app, browser: :chrome)
27
+ end
28
+
25
29
  Capybara.javascript_driver = ENV['JAVASCRIPT_DRIVER'] ? ENV['JAVASCRIPT_DRIVER'].to_sym : :webkit
26
30
 
27
31
  Capybara.add_selector(:row) do
@@ -1,5 +1,6 @@
1
1
  module Voluntary
2
2
  class Engine < ::Rails::Engine
3
+ config.autoload_paths << File.expand_path("../../../app/serializers", __FILE__)
3
4
  config.autoload_paths << File.expand_path("../../../app/models/concerns", __FILE__)
4
5
  config.autoload_paths << File.expand_path("../../../app/controllers/concerns", __FILE__)
5
6
  config.autoload_paths << File.expand_path("../..", __FILE__)
@@ -4,6 +4,10 @@ module Voluntary
4
4
  class Factories
5
5
  def self.code
6
6
  Proc.new do |factory_girl|
7
+ factory_girl.factory :argument_topic do
8
+ sequence(:name) { |n| "topic #{n}#{r_str}" }
9
+ end
10
+
7
11
  factory_girl.factory :user do
8
12
  sequence(:name) { |n| "user#{n}#{r_str}" }
9
13
  sequence(:email) { |n| "user#{n}#{r_str}@volontari.at" }
@@ -1,3 +1,3 @@
1
1
  module Voluntary
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.1'
3
3
  end
data/lib/voluntary.rb CHANGED
@@ -44,7 +44,6 @@ require 'bootstrap-sass-rails'
44
44
  require 'bootstrap-datetimepicker-rails'
45
45
  require 'jquery-ui-bootstrap-rails-asset'
46
46
  require 'auto_html'
47
- #require 'twitter-bootstrap-rails'
48
47
  require 'simple-navigation-bootstrap'
49
48
  require 'faraday'
50
49
  require 'faraday_middleware'
@@ -60,6 +59,7 @@ require 'selectize-rails'
60
59
  require 'bitmask_attributes'
61
60
  require 'csv'
62
61
  require 'httparty'
62
+ require 'active_model/serializer'
63
63
 
64
64
  require 'voluntary/navigation'
65
65