voluntary 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04ce673bd23bdfc0a764e2e6e94a05721b54518d
4
- data.tar.gz: e7a3f174f5cdd4a83f37434bb639373079af5ae3
3
+ metadata.gz: 9e0d6d9bf2a37688124de536d7859f1830abf3c6
4
+ data.tar.gz: 94f456e0b313a7d306724a1612e0bedea268d0f6
5
5
  SHA512:
6
- metadata.gz: ecfb127f78f437007cf0d312bfe883698ac532fec3d6d04b38fd8315d587353996798504e731fcb92050429ac7282fa28bd293c6552223b88f7faba6550e2cb1
7
- data.tar.gz: 7401b9fd9770e8a18c3d001465545ec7aac84d1bc60a5316dc7d01f7e9e04128eed017e1ada63859070e653d07b21aa678c55095cf75af3763d9d81e7e806388
6
+ metadata.gz: 7e2b60e9b3b05d5f3c0bd8733b96908fd3cc687db7c03999dcd36c69834030e595c7ec77cfa961ebc93ff739830e53d228e67f74931e19732a3cd53d195eff74
7
+ data.tar.gz: d5affd0cc24ceb1af706ce02afaedaf1e9441509f033b6f884ee1b3516b93fe91f6409f4692b4241726e2d1f9180e4458eebe2ea3f7dac545ced13e0a6033b74
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## unreleased ##
2
2
 
3
+ ## 0.6.0 (October 1, 2015) ##
4
+
5
+ * [#93](https://github.com/volontariat/voluntary/issues/93) Core customizations for survey product.
6
+
3
7
  ## 0.5.2 (September 2, 2015) ##
4
8
 
5
9
  * Adds moment.js.
data/README.md CHANGED
@@ -89,7 +89,7 @@ Run this in your console:
89
89
  bundle exec rake db:create:all && bundle exec rails g voluntary:product_dummy # confirm all overwrite questions except of Gemfile
90
90
  cd ..
91
91
  # add gitignore file from voluntary: https://github.com/volontariat/voluntary/blob/master/.gitignore
92
- rails g migration add_product_name_product
92
+ bundle exec rails g migration add_product_name_product
93
93
  # fill migration file with template: https://github.com/volontariat/voluntary_scholarship/blob/master/db/migrate/20140306201232_add_scholarship_product.rb
94
94
  cd dummy
95
95
  bundle exec rake railties:install:migrations
@@ -0,0 +1,139 @@
1
+ /*!
2
+ * JavaScript Cookie v2.0.3
3
+ * https://github.com/js-cookie/js-cookie
4
+ *
5
+ * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
6
+ * Released under the MIT license
7
+ */
8
+ (function (factory) {
9
+ if (typeof define === 'function' && define.amd) {
10
+ define(factory);
11
+ } else if (typeof exports === 'object') {
12
+ module.exports = factory();
13
+ } else {
14
+ var _OldCookies = window.Cookies;
15
+ var api = window.Cookies = factory();
16
+ api.noConflict = function () {
17
+ window.Cookies = _OldCookies;
18
+ return api;
19
+ };
20
+ }
21
+ }(function () {
22
+ function extend () {
23
+ var i = 0;
24
+ var result = {};
25
+ for (; i < arguments.length; i++) {
26
+ var attributes = arguments[ i ];
27
+ for (var key in attributes) {
28
+ result[key] = attributes[key];
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+
34
+ function init (converter) {
35
+ function api (key, value, attributes) {
36
+ var result;
37
+
38
+ // Write
39
+
40
+ if (arguments.length > 1) {
41
+ attributes = extend({
42
+ path: '/'
43
+ }, api.defaults, attributes);
44
+
45
+ if (typeof attributes.expires === 'number') {
46
+ var expires = new Date();
47
+ expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
48
+ attributes.expires = expires;
49
+ }
50
+
51
+ try {
52
+ result = JSON.stringify(value);
53
+ if (/^[\{\[]/.test(result)) {
54
+ value = result;
55
+ }
56
+ } catch (e) {}
57
+
58
+ value = encodeURIComponent(String(value));
59
+ value = value.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
60
+
61
+ key = encodeURIComponent(String(key));
62
+ key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
63
+ key = key.replace(/[\(\)]/g, escape);
64
+
65
+ return (document.cookie = [
66
+ key, '=', value,
67
+ attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
68
+ attributes.path && '; path=' + attributes.path,
69
+ attributes.domain && '; domain=' + attributes.domain,
70
+ attributes.secure ? '; secure' : ''
71
+ ].join(''));
72
+ }
73
+
74
+ // Read
75
+
76
+ if (!key) {
77
+ result = {};
78
+ }
79
+
80
+ // To prevent the for loop in the first place assign an empty array
81
+ // in case there are no cookies at all. Also prevents odd result when
82
+ // calling "get()"
83
+ var cookies = document.cookie ? document.cookie.split('; ') : [];
84
+ var rdecode = /(%[0-9A-Z]{2})+/g;
85
+ var i = 0;
86
+
87
+ for (; i < cookies.length; i++) {
88
+ var parts = cookies[i].split('=');
89
+ var name = parts[0].replace(rdecode, decodeURIComponent);
90
+ var cookie = parts.slice(1).join('=');
91
+
92
+ if (cookie.charAt(0) === '"') {
93
+ cookie = cookie.slice(1, -1);
94
+ }
95
+
96
+ try {
97
+ cookie = converter && converter(cookie, name) || cookie.replace(rdecode, decodeURIComponent);
98
+
99
+ if (this.json) {
100
+ try {
101
+ cookie = JSON.parse(cookie);
102
+ } catch (e) {}
103
+ }
104
+
105
+ if (key === name) {
106
+ result = cookie;
107
+ break;
108
+ }
109
+
110
+ if (!key) {
111
+ result[name] = cookie;
112
+ }
113
+ } catch (e) {}
114
+ }
115
+
116
+ return result;
117
+ }
118
+
119
+ api.get = api.set = api;
120
+ api.getJSON = function () {
121
+ return api.apply({
122
+ json: true
123
+ }, [].slice.call(arguments));
124
+ };
125
+ api.defaults = {};
126
+
127
+ api.remove = function (key, attributes) {
128
+ api(key, '', extend(attributes, {
129
+ expires: -1
130
+ }));
131
+ };
132
+
133
+ api.withConverter = init;
134
+
135
+ return api;
136
+ }
137
+
138
+ return init();
139
+ }));
@@ -0,0 +1,27 @@
1
+ @toggleText = ->
2
+ showChar = 255
3
+ ellipsesText = '...'
4
+ moreText = 'Show more >'
5
+ lessText = 'Show less'
6
+
7
+ $('.more').each ->
8
+ content = $(this).html()
9
+
10
+ if content.length > showChar
11
+ c = content.substr(0, showChar)
12
+ h = content.substr(showChar, content.length - showChar)
13
+ html = c + '<span class="more_ellipses">' + ellipsesText + '&nbsp;</span><span style="display:none;">' + h + '</span>&nbsp;&nbsp;<a href="" class="more_link" style="display:block;">' + moreText + '</a>'
14
+ $(this).html html
15
+
16
+ $('.more_link').click ->
17
+ if $(this).hasClass('less')
18
+ $(this).removeClass 'less'
19
+ $(this).html moreText
20
+ else
21
+ $(this).addClass 'less'
22
+ $(this).html lessText
23
+
24
+ $(this).siblings('.more_ellipses').toggle()
25
+ $(this).prev().toggle()
26
+
27
+ false
@@ -26,6 +26,14 @@ module Voluntary
26
26
 
27
27
  protected
28
28
 
29
+ def product_serializer(class_name, record)
30
+ begin
31
+ "#{record.product.class.name.gsub('Product::', '')}#{class_name}Serializer".constantize.new(record)
32
+ rescue NameError
33
+ "#{class_name}Serializer".constantize.new(record)
34
+ end
35
+ end
36
+
29
37
  def application_navigation
30
38
  :main
31
39
  end
@@ -18,6 +18,7 @@ class StoriesController < ApplicationController
18
18
 
19
19
  def show
20
20
  @comments = @story.comments
21
+ @twitter_sidenav_level = 5
21
22
  end
22
23
 
23
24
  def new
@@ -33,10 +34,7 @@ class StoriesController < ApplicationController
33
34
  end
34
35
 
35
36
  def edit
36
- #if @story.tasks.none?
37
- #@story.tasks << @story.tasks.new
38
- #@story.tasks.first.errors.clear
39
- #end
37
+ @twitter_sidenav_level = 5
40
38
 
41
39
  render_wizard
42
40
  end
@@ -90,6 +88,13 @@ class StoriesController < ApplicationController
90
88
  @presenter = Resources::General::Wizards::StoryPresenter.new(
91
89
  self.view_context, resource: resource
92
90
  )
93
- render 'general/wizard'
91
+
92
+ begin
93
+ raise NotImplementedError if @project.product_id.blank?
94
+
95
+ render "products/types/#{@project.product.class.name.split('Product::').last.tableize.singularize}/wizard"
96
+ rescue NotImplementedError, ActionView::MissingTemplate
97
+ render 'general/wizard'
98
+ end
94
99
  end
95
100
  end
@@ -27,6 +27,10 @@ module Voluntary
27
27
  end
28
28
  end
29
29
 
30
+ def matrix
31
+ render json: Argument.matrix(params[:argumentables]), root: false
32
+ end
33
+
30
34
  def create
31
35
  raise CanCan::AccessDenied if current_user.blank?
32
36
 
@@ -0,0 +1,90 @@
1
+ class Voluntary::Api::V1::StoriesController < ActionController::Base
2
+ include Voluntary::V1::BaseController
3
+
4
+ respond_to :json
5
+
6
+ def show
7
+ story = Story.find(params[:id])
8
+
9
+ respond_to do |format|
10
+ format.json do
11
+ render json: product_serializer('Story', story)
12
+ end
13
+ end
14
+ end
15
+
16
+ def create
17
+ project = Project.find(params[:story][:project_id])
18
+ story = project.story_class.new({ project_id: project.id }.merge(params[:story] || {}))
19
+
20
+ authorize! :create, story
21
+
22
+ story.save
23
+
24
+ respond_to do |format|
25
+ format.json do
26
+ render json: story.persisted? ? product_serializer('Story', story) : { errors: story.errors.to_hash }
27
+ end
28
+ end
29
+ end
30
+
31
+ def update
32
+ story = Story.find params[:id]
33
+
34
+ authorize! :update, story
35
+
36
+ story.update_attributes params[:story]
37
+
38
+ respond_to do |format|
39
+ format.json do
40
+ render json: story.valid? ? product_serializer('Story', story) : { errors: story.errors.to_hash }
41
+ end
42
+ end
43
+ end
44
+
45
+ def activate
46
+ story = Story.find params[:id]
47
+
48
+ authorize! :update, story
49
+
50
+ story.activate
51
+
52
+ respond_to do |format|
53
+ format.json do
54
+ render json: story.errors.empty? && story.valid? ? product_serializer('Story', story) : { errors: story.errors.to_hash }
55
+ end
56
+ end
57
+ end
58
+
59
+ def deactivate
60
+ story = Story.find params[:id]
61
+
62
+ authorize! :update, story
63
+
64
+ story.deactivate
65
+
66
+ respond_to do |format|
67
+ format.json do
68
+ render json: story.errors.empty? && story.valid? ? product_serializer('Story', story) : { errors: story.errors.to_hash }
69
+ end
70
+ end
71
+ end
72
+
73
+ def destroy
74
+ story = current_user.stories.friendly.find params[:id]
75
+
76
+ authorize! :destroy, story
77
+
78
+ story.destroy
79
+
80
+ respond_to do |format|
81
+ format.json do
82
+ render json: if story.persisted?
83
+ { error: I18n.t('activerecord.errors.models.story.attributes.base.deletion_failed') }
84
+ else
85
+ {}
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
data/app/models/area.rb CHANGED
@@ -36,4 +36,10 @@ class Area < ActiveRecord::Base
36
36
 
37
37
  def products
38
38
  end
39
+
40
+ private
41
+
42
+ def should_generate_new_friendly_id?
43
+ slug.blank? || name_changed?
44
+ end
39
45
  end
@@ -27,7 +27,7 @@ class Argument < ActiveRecord::Base
27
27
 
28
28
  attr_accessible :topic_id, :argumentable_type, :argumentable_id, :vote, :value
29
29
 
30
- attr_accessor :positive
30
+ attr_accessor :vote, :positive
31
31
 
32
32
  def self.create_with_topic(user_id, attributes)
33
33
  topic = ArgumentTopic.find_or_create_by_name attributes[:topic_name]
@@ -55,4 +55,44 @@ class Argument < ActiveRecord::Base
55
55
  { errors: { topic: topic.errors.to_hash } }
56
56
  end
57
57
  end
58
+
59
+ def self.matrix(argumentables)
60
+ arguments = []
61
+
62
+ argumentables.each do |index, argumentable|
63
+ arguments += Argument.where(
64
+ argumentable_type: argumentable['type'], argumentable_id: argumentable['id']
65
+ ).includes(:topic).to_a
66
+ end
67
+
68
+ arguments_by_name = {}
69
+
70
+ arguments.each do |argument|
71
+ arguments_by_name[argument.topic.name] ||= []
72
+ arguments_by_name[argument.topic.name] << argument
73
+ end
74
+
75
+ json = { argumentables: [], matrix: [] }
76
+
77
+ argumentables.keys.map(&:to_i).sort.each do |argumentable_index|
78
+ argumentable = argumentables[argumentable_index.to_s]
79
+ argumentable = argumentable['type'].constantize.find(argumentable['id'])
80
+
81
+ json[:argumentables] << { id: argumentable.id, slug: argumentable.try(:slug), name: argumentable.name }
82
+ end
83
+
84
+ arguments_by_name.keys.sort.each do |topic_name|
85
+ item = { topic_name: topic_name, values: [] }
86
+ arguments = arguments_by_name[topic_name]
87
+
88
+ argumentables.keys.map(&:to_i).sort.each do |argumentable_index|
89
+ argumentable = argumentables[argumentable_index.to_s]
90
+ item[:values] << arguments.select{|a| a.argumentable_type == argumentable['type'] && a.argumentable_id == argumentable['id'].to_i }.first.try(:value)
91
+ end
92
+
93
+ json[:matrix] << item
94
+ end
95
+
96
+ json
97
+ end
58
98
  end
@@ -4,9 +4,10 @@ module Likeable
4
4
  included do
5
5
  belongs_to :target, polymorphic: true
6
6
 
7
- has_many :likes, -> { where(positive: true) }, dependent: :delete_all, as: :target
7
+ has_many :likes_or_dislikes, class_name: 'Like', dependent: :delete_all, as: :target
8
+ has_many :likes, -> { where(positive: true) }, as: :target
8
9
  has_many :likers, class_name: 'User', through: :likes, source: :user
9
- has_many :dislikes, -> { where(positive: false) }, class_name: 'Like', dependent: :delete_all, as: :target
10
+ has_many :dislikes, -> { where(positive: false) }, class_name: 'Like', as: :target
10
11
  has_many :dislikers, class_name: 'User', through: :dislikes, source: :user
11
12
 
12
13
  scope :liked_by, ->(user_id) do
@@ -17,4 +17,10 @@ class Organization < ActiveRecord::Base
17
17
  friendly_id :name, :use => :slugged
18
18
 
19
19
  PARENT_TYPES = ['user']
20
+
21
+ private
22
+
23
+ def should_generate_new_friendly_id?
24
+ slug.blank? || name_changed?
25
+ end
20
26
  end
@@ -10,4 +10,10 @@ class Profession < ActiveRecord::Base
10
10
  extend FriendlyId
11
11
 
12
12
  friendly_id :name, :use => :slugged
13
+
14
+ private
15
+
16
+ def should_generate_new_friendly_id?
17
+ slug.blank? || name_changed?
18
+ end
13
19
  end
@@ -74,4 +74,8 @@ class Project < ActiveRecord::Base
74
74
  def destroy_non_active_records
75
75
  stories.destroy_all
76
76
  end
77
+
78
+ def should_generate_new_friendly_id?
79
+ slug.blank? || name_changed?
80
+ end
77
81
  end
data/app/models/result.rb CHANGED
@@ -23,7 +23,7 @@ class Result
23
23
 
24
24
  validates :task_id, presence: true
25
25
  validates :story_id, presence: true
26
- validates :offeror_id, presence: true
26
+ validates :offeror_id, presence: true, if: 'task_id.present? && (task rescue nil) && task.story.with_offeror'
27
27
  validates :text, presence: true
28
28
 
29
29
  after_initialize :cache_associations
@@ -48,13 +48,13 @@ class Result
48
48
 
49
49
  def cache_associations
50
50
  self.story_id = task.story_id if task_id.present? && (task rescue nil)
51
- self.offeror_id = task.offeror_id if task_id.present? && (task rescue nil)
51
+ self.offeror_id = task.offeror_id if task_id.present? && (task rescue nil) && task.story.with_offeror
52
52
  end
53
53
 
54
54
  def cache_product_association
55
55
  self.product_id = task.product_id if task_id.present? && (task rescue nil)
56
56
  end
57
57
 
58
- def set_tasks_result_association; task.update_attribute(:result_id, id); end
59
- def unset_tasks_result_association; task.update_attribute(:result_id, nil); end
58
+ def set_tasks_result_association; task.update_attribute(:result_id, id) unless task.respond_to?(:results); end
59
+ def unset_tasks_result_association; task.update_attribute(:result_id, nil) unless task.respond_to?(:results); end
60
60
  end
@@ -26,8 +26,16 @@ module StateMachines::Story
26
26
  validate :presence_of_tasks
27
27
  end
28
28
 
29
+ state :active do
30
+ validate :presence_of_tasks
31
+ end
32
+
29
33
  event :activate do
30
- transition [:tasks_defined, :completed] => :active
34
+ transition [:new, :tasks_defined, :completed] => :active
35
+ end
36
+
37
+ event :deactivate do
38
+ transition :active => :tasks_defined
31
39
  end
32
40
 
33
41
  event :complete do
@@ -51,7 +59,9 @@ module StateMachines::Story
51
59
  end
52
60
 
53
61
  def presence_of_tasks
54
- self.tasks.delete_if{|t| t.name.blank? && t.text.blank? }
62
+ self.tasks.delete_if do |t|
63
+ t.name.blank? && (t.class.name == 'Task' && t.text.blank?)
64
+ end
55
65
 
56
66
  if tasks.select{|t| !t.valid?}.any?
57
67
  errors[:base] << I18n.t(
data/app/models/story.rb CHANGED
@@ -77,6 +77,12 @@ class Story
77
77
  task
78
78
  end
79
79
 
80
+ protected
81
+
82
+ def with_offeror
83
+ true
84
+ end
85
+
80
86
  private
81
87
 
82
88
  def import_tasks_from_file
data/app/models/task.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  class Task
2
2
  include Mongoid::Document
3
3
  include Mongoid::Timestamps
4
- include Mongoid::Slug
5
4
  #include Mongoid::History::Trackable
6
5
  include ActiveModel::MassAssignmentSecurity
7
6
 
@@ -21,8 +20,6 @@ class Task
21
20
  field :text, type: String
22
21
  field :state, type: String
23
22
  field :unassigned_user_ids, type: Array
24
-
25
- slug :name, reserve: ['new', 'edit', 'next']
26
23
 
27
24
  attr_accessible :story, :story_id, :name, :text, :result_attributes
28
25
 
@@ -33,7 +30,7 @@ class Task
33
30
  scope :incomplete, -> { ne(state: 'completed') }
34
31
 
35
32
  validates :story_id, presence: true
36
- validates :offeror_id, presence: true
33
+ validates :offeror_id, presence: true, if: 'story_id.present? && (story rescue nil) && story.with_offeror'
37
34
  validates :text, presence: true, if: ->(t) { t.class.name == 'Task' }
38
35
  validate :name_valid?
39
36
 
@@ -124,11 +121,15 @@ class Task
124
121
  private
125
122
 
126
123
  def destroy_result
127
- result.try(:destroy)
124
+ if respond_to? :results
125
+ results.map(&:destroy)
126
+ else
127
+ result.try(:destroy)
128
+ end
128
129
  end
129
130
 
130
131
  def cache_associations
131
- self.offeror_id = story.offeror_id if story_id.present? && (story rescue nil)
132
+ self.offeror_id = story.offeror_id if story_id.present? && (story rescue nil) && story.with_offeror
132
133
  end
133
134
 
134
135
  def cache_product_association
data/app/models/user.rb CHANGED
@@ -113,4 +113,8 @@ class User < ActiveRecord::Base
113
113
  self.api_key = SecureRandom.uuid.tr('-', '')
114
114
  end while User.where(api_key: api_key).any?
115
115
  end
116
+
117
+ def should_generate_new_friendly_id?
118
+ slug.blank? || name_changed?
119
+ end
116
120
  end
@@ -1,20 +1,24 @@
1
1
  class Wikidata
2
2
  def self.search(term, known_things)
3
- JSON.parse(
4
- HTTParty.get(
5
- "https://www.wikidata.org/w/api.php?action=wbsearchentities&search=" +
6
- "#{URI.encode(term, /\W/)}&format=json&language=en&type=item&continue=0",
7
- verify: false
8
- ).body
9
- )['search'].map do |item|
10
- description = if item['description'].to_s.present? &&
11
- item['description'] != 'Wikimedia disambiguation page'
12
- " (#{item['description']})"
13
- else
14
- ''
15
- end
16
-
17
- "#{item['label']}#{description}"
18
- end.uniq.select{|i| known_things.select{|t| t[:name] == i }.none? }.map{|item| { name: item } }
3
+ begin
4
+ JSON.parse(
5
+ HTTParty.get(
6
+ "https://www.wikidata.org/w/api.php?action=wbsearchentities&search=" +
7
+ "#{URI.encode(term, /\W/)}&format=json&language=en&type=item&continue=0",
8
+ verify: false
9
+ ).body
10
+ )['search'].map do |item|
11
+ description = if item['description'].to_s.present? &&
12
+ item['description'] != 'Wikimedia disambiguation page'
13
+ " (#{item['description']})"
14
+ else
15
+ ''
16
+ end
17
+
18
+ "#{item['label']}#{description}"
19
+ end.uniq.select{|i| known_things.select{|t| t[:name] == i }.none? }.map{|item| { name: item } }
20
+ rescue SocketError => e
21
+ []
22
+ end
19
23
  end
20
24
  end
@@ -0,0 +1,3 @@
1
+ class StorySerializer < ActiveModel::Serializer
2
+ attributes :id, :name, :text, :product_id, :state
3
+ end
@@ -0,0 +1,3 @@
1
+ class TaskSerializer < ActiveModel::Serializer
2
+ attributes :id, :name, :text, :offeror_id, :author_id, :user_id
3
+ end
@@ -19,10 +19,10 @@
19
19
  </ul>
20
20
  <div class="tab-content">
21
21
  <div role="tabpanel" class="tab-pane active" id="stories" style="padding-top:15px;">
22
- Stories
22
+ <%= image_tag 'voluntary/spinner.gif' %>
23
23
  </div>
24
24
  <div role="tabpanel" class="tab-pane" id="assigned_tasks" style="padding-top:15px;">
25
- Tasks
25
+ <%= image_tag 'voluntary/spinner.gif' %>
26
26
  </div>
27
27
  </div>
28
28
  </div>
@@ -0,0 +1 @@
1
+ <%= link_to t('workflow.user.next_task'), next_task_workflow_user_index_path(story) %>
@@ -19,7 +19,11 @@
19
19
  -
20
20
  <% end %>
21
21
  </td>
22
- <td><%= link_to t('workflow.user.next_task'), next_task_workflow_user_index_path(story) %></td>
22
+ <td>
23
+ <%= render_product_specific_partial_if_available(
24
+ story.project, 'workflow/user/stories/next_task', { story: story }
25
+ ) %>
26
+ </td>
23
27
  </tr>
24
28
  <% end %>
25
29
  </tbody>
@@ -2,6 +2,8 @@ en:
2
2
  arguments:
3
3
  index:
4
4
  title: Arguments
5
+ matrix:
6
+ title: Arguments Matrix
5
7
  new:
6
8
  title: New Argument
7
9
  save:
@@ -7,6 +7,13 @@ en:
7
7
 
8
8
  new:
9
9
  title: New Story
10
+
11
+ create:
12
+ title: Create Story
13
+
14
+ save:
15
+ failed: Something went wrong at saving story
16
+ successful: Successfully saved story.
10
17
 
11
18
  show:
12
19
  states:
@@ -15,6 +22,9 @@ en:
15
22
 
16
23
  edit:
17
24
  title: Edit Story
25
+
26
+ update:
27
+ title: Update Story
18
28
 
19
29
  steps:
20
30
  initialization:
@@ -26,6 +36,8 @@ en:
26
36
  update: Update Tasks
27
37
  activate:
28
38
  title: Activate
39
+ deactivate:
40
+ title: Deactivate
29
41
 
30
42
  activerecord:
31
43
  attributes:
@@ -1,4 +1,11 @@
1
1
  en:
2
+ things:
3
+ show:
4
+ limit_of_comparison_list: Limit of 4 items in thing comparison list reached!
5
+ add_to_comparison_list: Add to comparison list
6
+ remove_from_comparison_list: Remove from comparison list
7
+ comparison_list: Comparison List
8
+
2
9
  activerecord:
3
10
  errors:
4
11
  models:
data/config/routes/api.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  namespace :voluntary, path: 'api', module: 'voluntary/api', defaults: {format: 'json'} do
2
2
  namespace :v1 do
3
- resources :stories, only: [] do
3
+ resources :stories, only: [:create, :show, :update, :destroy] do
4
4
  resources :tasks, only: [:index, :create]
5
+
6
+ member do
7
+ put :activate
8
+ put :deactivate
9
+ end
5
10
  end
6
11
 
7
12
  resources :argument_topics, only: [] do
@@ -10,7 +15,11 @@ namespace :voluntary, path: 'api', module: 'voluntary/api', defaults: {format: '
10
15
  end
11
16
  end
12
17
 
13
- resources :arguments
18
+ resources :arguments do
19
+ collection do
20
+ get :matrix
21
+ end
22
+ end
14
23
 
15
24
  get '/things/:left_thing_name/vs/:right_thing_name/arguments', to: 'things/arguments#comparison'
16
25
 
data/lib/voluntary.rb CHANGED
@@ -60,6 +60,7 @@ require 'bitmask_attributes'
60
60
  require 'csv'
61
61
  require 'httparty'
62
62
  require 'active_model/serializer'
63
+ require 'mongoid_orderable'
63
64
 
64
65
  require 'voluntary/navigation'
65
66
 
@@ -210,6 +210,10 @@ module Voluntary
210
210
  comments.item(:edit, I18n.t('general.edit'), edit_comment_path(@comment))
211
211
  end
212
212
  end
213
+
214
+ if options[:stories_after_resource_has_many]
215
+ instance_exec story, {}, &options[:stories_after_resource_has_many]
216
+ end
213
217
  end
214
218
  end
215
219
  end
@@ -1,3 +1,3 @@
1
1
  module Voluntary
2
- VERSION = '0.5.2'
2
+ VERSION = '0.6.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voluntary
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mathias Gawlista
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-02 00:00:00.000000000 Z
11
+ date: 2015-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -444,6 +444,20 @@ dependencies:
444
444
  - - "~>"
445
445
  - !ruby/object:Gem::Version
446
446
  version: 1.0.0
447
+ - !ruby/object:Gem::Dependency
448
+ name: mongoid_orderable
449
+ requirement: !ruby/object:Gem::Requirement
450
+ requirements:
451
+ - - "~>"
452
+ - !ruby/object:Gem::Version
453
+ version: 4.1.1
454
+ type: :runtime
455
+ prerelease: false
456
+ version_requirements: !ruby/object:Gem::Requirement
457
+ requirements:
458
+ - - "~>"
459
+ - !ruby/object:Gem::Version
460
+ version: 4.1.1
447
461
  - !ruby/object:Gem::Dependency
448
462
  name: mongoid_slug
449
463
  requirement: !ruby/object:Gem::Requirement
@@ -1130,7 +1144,7 @@ dependencies:
1130
1144
  - - "~>"
1131
1145
  - !ruby/object:Gem::Version
1132
1146
  version: 2.2.0
1133
- description: "#Crowdsourcing management system for #RubyOnRails: http://bit.ly/voluntary-0-5-2"
1147
+ description: "#Crowdsourcing management system for #RubyOnRails: http://bit.ly/voluntary-0-6-0"
1134
1148
  email:
1135
1149
  - gawlista@gmail.com
1136
1150
  executables: []
@@ -1146,7 +1160,9 @@ files:
1146
1160
  - app/assets/javascripts/voluntary/base.js.coffee
1147
1161
  - app/assets/javascripts/voluntary/functions.js
1148
1162
  - app/assets/javascripts/voluntary/lib/jquery-competitive_list.js
1163
+ - app/assets/javascripts/voluntary/lib/jquery.cookie.js
1149
1164
  - app/assets/javascripts/voluntary/lib/jquery.multisortable.js
1165
+ - app/assets/javascripts/voluntary/lib/jquery.toggle_text.js.coffee
1150
1166
  - app/assets/javascripts/voluntary/lib/moment.js
1151
1167
  - app/assets/javascripts/voluntary/lib/sugar.js
1152
1168
  - app/assets/javascripts/voluntary/likes/list.js.coffee
@@ -1176,6 +1192,7 @@ files:
1176
1192
  - app/controllers/voluntary/api/v1/arguments_controller.rb
1177
1193
  - app/controllers/voluntary/api/v1/base_controller.rb
1178
1194
  - app/controllers/voluntary/api/v1/organizations_controller.rb
1195
+ - app/controllers/voluntary/api/v1/stories_controller.rb
1179
1196
  - app/controllers/voluntary/api/v1/tasks_controller.rb
1180
1197
  - app/controllers/voluntary/api/v1/things/arguments_controller.rb
1181
1198
  - app/controllers/voluntary/api/v1/users_controller.rb
@@ -1248,6 +1265,8 @@ files:
1248
1265
  - app/serializers/argument_serializer.rb
1249
1266
  - app/serializers/basic_user_serializer.rb
1250
1267
  - app/serializers/current_user_serializer.rb
1268
+ - app/serializers/story_serializer.rb
1269
+ - app/serializers/task_serializer.rb
1251
1270
  - app/serializers/user_serializer.rb
1252
1271
  - app/views/areas/_form.html.erb
1253
1272
  - app/views/areas/edit.html.erb
@@ -1339,6 +1358,7 @@ files:
1339
1358
  - app/views/workflow/user/index.html.erb
1340
1359
  - app/views/workflow/user/product/areas/show.html.erb
1341
1360
  - app/views/workflow/user/projects/show.html.erb
1361
+ - app/views/workflow/user/stories/_next_task.html.erb
1342
1362
  - app/views/workflow/user/stories/index.html.erb
1343
1363
  - app/views/workflow/user/tasks/assigned.html.erb
1344
1364
  - config/initializers/1_initialize_app_config.rb