voluntary_classified_advertisement 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/MIT-LICENSE +1 -1
  4. data/app/controllers/classified_advertisement/tasks_controller.rb +40 -0
  5. data/app/helpers/voluntary_classified_advertisement/tasks_helper.rb +17 -0
  6. data/app/models/product/classified_advertisement/candidature.rb +3 -16
  7. data/app/models/product/classified_advertisement/story.rb +13 -14
  8. data/app/models/product/classified_advertisement/task.rb +56 -91
  9. data/app/models/product/classified_advertisement/vacancy.rb +17 -60
  10. data/app/views/classified_advertisement/tasks/_navigation.html.erb +8 -0
  11. data/app/views/classified_advertisement/tasks/calendar.html.erb +23 -0
  12. data/app/views/classified_advertisement/tasks/sign_out.js.erb +5 -0
  13. data/app/views/classified_advertisement/tasks/sign_up.js.erb +5 -0
  14. data/app/views/classified_advertisement/tasks/sign_up_form.html.erb +23 -0
  15. data/app/views/products/types/classified_advertisement/stories/_task_fields.html.erb +7 -10
  16. data/app/views/products/types/classified_advertisement/tasks/_collection.html.erb +76 -0
  17. data/app/views/products/types/classified_advertisement/tasks/_form.html.erb +134 -0
  18. data/app/views/products/types/classified_advertisement/tasks/_state_switch.html.erb +17 -0
  19. data/app/views/products/types/classified_advertisement/tasks/show.html.erb +42 -0
  20. data/app/views/products/types/classified_advertisement/wizard.html.erb +45 -0
  21. data/app/views/products/types/classified_advertisement/workflow/tasks/_vacancy_fields.html.erb +1 -1
  22. data/app/views/products/types/classified_advertisement/workflow/tasks/_work_form.html.erb +13 -15
  23. data/config/locales/resources/candidature/en.yml +5 -0
  24. data/config/locales/resources/task/en.yml +13 -0
  25. data/config/routes.rb +17 -0
  26. data/db/migrate/20130806131503_add_classified_advertisement_product.rb +2 -2
  27. data/db/migrate/20151021161627_add_amount_to_candidatures.rb +5 -0
  28. data/lib/voluntary_classified_advertisement/version.rb +1 -1
  29. metadata +33 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4e0af2c11128cde4f2e14162a635847dd6d9670d
4
- data.tar.gz: f178c2fb85b1c6ccd85dfba6a75ff54118c536c8
3
+ metadata.gz: aec7ac6a224d0308649e238c69b9e9fef327aa57
4
+ data.tar.gz: 970a05e0b18a896868f1f0311458c6177f1975e4
5
5
  SHA512:
6
- metadata.gz: bcbb2fb9157aaf9aaee2e181496b669dade19a7323ec615c0a82069601fcbc5ebc647f6faa9953de3975c78144d4e38657646da39f6a5f184d35c425f0a601f0
7
- data.tar.gz: 85e1aa022bfd4cfbcae1980bca93bfee9d5906f1576308f7eecf082f68d32ef288beef320c92f52fafd2f99d7ad6647c96eb0b9626ca2f20b9826d17c19f1c12
6
+ metadata.gz: da23cf8bd51cf0f6b648f5966f26582eeff549508a6467ec9ec75489b4bb8f1b8871775592bd1cee8a3f5c31cc2480195cb7c2a8cd5ffddf970936d8fdbbb7fd
7
+ data.tar.gz: 730e52f3bcddc1977b305bd112d9a67312a590ed23eb6a400d421a101ce26561fd1c5e88f2d93203774656e132686bfddf753c0c0df5723df543df59930b157d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.3.0 (October 29, 2015) ##
2
+
3
+ * [#7](https://github.com/volontariat/voluntary_classified_advertisement/issues/7) Custom task page
4
+ * [#6](https://github.com/volontariat/voluntary_classified_advertisement/issues/6) Calendar view of story tasks
5
+ * [#5](https://github.com/volontariat/voluntary_classified_advertisement/issues/5) Task Form and Management "2.0"
6
+ * [#4](https://github.com/volontariat/voluntary_classified_advertisement/issues/4) Story Form and Management "2.0"
7
+
1
8
  ## 0.2.0 (April 10, 2015) ##
2
9
 
3
10
  * #3 Rails 4.2.1 upgrade and Travis setup.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2013 YOURNAME
1
+ Copyright 2013 Mathias Gawlista
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -0,0 +1,40 @@
1
+ module ClassifiedAdvertisement
2
+ class TasksController < ApplicationController
3
+ def calendar
4
+ @story = Story.find params[:story_id]
5
+ end
6
+
7
+ def events
8
+ @story = Story.find params[:story_id]
9
+ tasks = @story.tasks.where(:from.gte => params[:start], :to.lt => params[:end])
10
+
11
+ tasks = tasks.map do |task|
12
+ { title: task.name, url: task_path(task), start: task.from.to_s, end: task.to.to_s }
13
+ end
14
+
15
+ render json: tasks
16
+ end
17
+
18
+ def sign_up_form
19
+ @task = Task.find(params[:id])
20
+ @amount = @task.vacancy.candidatures.where(user_id: current_user.id).first.try(:amount)
21
+
22
+ render layout: false
23
+ end
24
+
25
+ def sign_up
26
+ task = Task.find(params[:id])
27
+ params[:candidature] ||= {}
28
+ @error = task.sign_up(current_user.id, params[:candidature][:amount])
29
+
30
+ render layout: false
31
+ end
32
+
33
+ def sign_out
34
+ task = Task.find(params[:id])
35
+ @error = task.sign_out(current_user.id)
36
+
37
+ render layout: false
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ module VoluntaryClassifiedAdvertisement
2
+ module TasksHelper
3
+ def tasks_with_candidatures(user)
4
+ task_ids, vacancy_to_task_id = [], {}
5
+
6
+ if user_signed_in?
7
+ @tasks.each{|t| vacancy_to_task_id[t.vacancy_id] = t.id }
8
+
9
+ Candidature.where(user_id: current_user.id, vacancy_id: @tasks.map(&:vacancy_id)).each do |candidature|
10
+ task_ids << vacancy_to_task_id[candidature.vacancy_id]
11
+ end
12
+ end
13
+
14
+ task_ids
15
+ end
16
+ end
17
+ end
@@ -1,20 +1,7 @@
1
1
  class Product::ClassifiedAdvertisement::Candidature < ::Candidature
2
- accepts_nested_attributes_for :resource
2
+ protected
3
3
 
4
- attr_accessible :resource_attributes
5
-
6
- def resource_attributes=(attributes)
7
- self.resource = if attributes[:id].present?
8
- Asset.find(attributes[:id])
9
- else
10
- Asset.new
11
- end
12
-
13
- self.resource.attributes = attributes
14
-
15
- self.resource.save
16
-
17
- self.resource_type = 'Asset'
18
- self.resource_id = self.resource.id
4
+ def validate_resource_id?
5
+ resource_type == 'User' || vacancy.resource_type == 'User'
19
6
  end
20
7
  end
@@ -1,19 +1,18 @@
1
1
  class Product::ClassifiedAdvertisement::Story < Story
2
2
  has_many :tasks, dependent: :destroy, class_name: 'Product::ClassifiedAdvertisement::Task', inverse_of: :story
3
3
 
4
- def tasks_attributes=(attributes)
5
- self.tasks ||= []
6
-
7
- attributes.each do |index, task_attributes|
8
- destroy = task_attributes.delete :_destroy
9
-
10
- if task_attributes[:id].present? && destroy.to_i == 1
11
- self.tasks.where(id: task_attributes[:id]).destroy_all
12
- elsif task_attributes[:id].present?
13
- tasks.find(task_attributes[:id]).update_attributes(task_attributes)
14
- else
15
- self.tasks.build(task_attributes)
16
- end
17
- end
4
+ field :address, type: String
5
+ field :lat, type: String
6
+ field :lon, type: String
7
+ field :address_description, type: String
8
+
9
+ attr_accessible :address, :lat, :lon, :address_description
10
+
11
+ def after_creation_path
12
+ Rails.application.routes.url_helpers.story_tasks_path(self)
13
+ end
14
+
15
+ def custom_tasks
16
+ tasks.order('from ASC, to ASC')
18
17
  end
19
18
  end
@@ -1,65 +1,32 @@
1
1
  class Product::ClassifiedAdvertisement::Task < ::Task
2
2
  belongs_to :story, class_name: 'Product::ClassifiedAdvertisement::Story', inverse_of: :task
3
3
 
4
- attr_accessible :vacancies_attributes
5
- attr_writer :vacancies
6
-
7
4
  validates :text, presence: true
8
5
 
9
- validate :at_least_one_vacancy
6
+ attr_accessible :vacancy_attributes
7
+ attr_writer :vacancy
10
8
 
11
- after_save :save_dependencies
12
- after_destroy :destroy_non_mongodb_records
9
+ field :vacancy_id, type: Integer
10
+ field :address, type: String
11
+ field :lat, type: String
12
+ field :lon, type: String
13
+ field :address_description, type: String
14
+ field :from, type: DateTime
15
+ field :to, type: DateTime
16
+ field :resource_type, type: String
13
17
 
14
- state_machine :state, initial: :new do
15
- state :under_supervision do
16
- validate :new_candidature_present?
17
- end
18
- end
18
+ attr_accessible :address, :lat, :lon, :address_description, :from, :to, :resource_type
19
19
 
20
- def vacancies
21
- @vacancies ||= new_record? ? [vacancy_class.new(task: self)] : vacancy_class.where(task_id: id.to_s)
22
- end
20
+ before_validation :validate_vacancy
21
+ after_create :set_vacancy_task_association
22
+ after_destroy :destroy_non_mongodb_records
23
23
 
24
- def vacancies_attributes=(attributes = {})
25
- self.vacancies = [] if self.vacancies.length == 1 && self.vacancies.first.new_record?
26
-
27
- attributes.select{|k,v| (v[:name].present? && v[:text].present?) || v[:id].present? }.each do |index, vacancy_attributes|
28
- destroy = vacancy_attributes.delete :_destroy
29
- vacancy_attributes[:task] = self
30
- vacancy = nil
31
-
32
- if vacancy_attributes[:id].present? && destroy.to_i == 1
33
- begin; vacancy_class.destroy(vacancy_attributes[:id]); rescue ActiveRecord::RecordNotFound; end
34
- @vacancies.select!{|v| v.id != vacancy_attributes[:id]}
35
- elsif vacancy_attributes[:id].present?
36
- begin; vacancy = vacancy_class.find(vacancy_attributes[:id]); rescue ActiveRecord::RecordNotFound; end
37
-
38
- vacancy_id = vacancy_attributes.delete(:id)
39
-
40
- vacancy.update_attributes(vacancy_attributes) if vacancy.present?
41
-
42
- vacancy_attributes[:id] = vacancy_id
43
- else
44
- vacancy = vacancy_class.new(vacancy_attributes)
45
- end
46
-
47
- next unless vacancy.present?
48
-
49
- if vacancy_attributes[:id].present?
50
- self.vacancies.each_with_index do |current_vacancy, vacancies_index|
51
- if current_vacancy.id.to_s == vacancy_attributes[:id]
52
- self.vacancies[vacancies_index] = vacancy
53
- end
54
- end
55
- else
56
- self.vacancies << vacancy
57
- end
58
- end
24
+ def vacancy_attributes=(value)
25
+ vacancy.update value
59
26
  end
60
27
 
61
- def vacancies_attributes
62
- @vacancies_attributes ||= (vacancies.empty? ? [vacancy_class.new(task: self)] : vacancies).map{|v| v.attributes}
28
+ def vacancy
29
+ @vacancy ||= new_record? ? vacancy_class.new(task: self) : vacancy_class.find(vacancy_id)
63
30
  end
64
31
 
65
32
  def vacancy_class
@@ -89,54 +56,52 @@ class Product::ClassifiedAdvertisement::Task < ::Task
89
56
  super(transition)
90
57
  end
91
58
 
92
- private
93
-
94
- def at_least_one_vacancy
95
- unless vacancies.select(&:valid?).any?
96
- errors.add(:base, I18n.t('activerecord.errors.models.task.attributes.base.no_vacancies'))
59
+ def sign_up(current_user_id, amount = nil)
60
+ amount = vacancy.resource_type == 'User' ? 1 : amount
61
+ user_candidature = vacancy.candidatures.where(user_id: current_user_id).first
62
+
63
+ if amount == user_candidature.try(:amount)
64
+ return I18n.t('tasks.sign_up.already_signed_up')
65
+ elsif vacancy.calculate_accepted_candidatures_amount == vacancy.limit && amount > user_candidature.try(:amount)
66
+ return I18n.t('tasks.sign_up.limit_reached')
97
67
  end
68
+
69
+ candidature = user_candidature ? user_candidature : vacancy.candidatures.new
70
+ candidature.user_id = current_user_id
71
+ candidature.resource_type = vacancy.resource_type
72
+ candidature.resource_id = current_user_id if vacancy.resource_type == 'User'
73
+ candidature.amount = amount
74
+ user_candidature ? candidature.save : candidature.accept
75
+
76
+ nil
98
77
  end
99
78
 
100
- def save_dependencies
101
- vacancies.select(&:new_record?).each do |vacancy|
102
- vacancy.task = self
103
- vacancy.do_open
104
- end
79
+ def sign_out(current_user_id)
80
+ user_candidature = vacancy.candidatures.where(user_id: current_user_id).first
81
+
82
+ return I18n.t('tasks.sign_out.not_signed_up') unless user_candidature
83
+
84
+ user_candidature.destroy
85
+
86
+ nil
105
87
  end
106
88
 
107
- def new_candidature_present?
108
- vacancies.each do |vacancy|
109
- new_candidatures = vacancy.candidatures.select{|c| c.state == 'new'}
110
-
111
- if new_candidatures.none?
112
- errors.add(
113
- :base,
114
- I18n.t(
115
- 'activerecord.errors.models.task.attributes.base.' +
116
- 'only_one_new_candidature'
117
- )
118
- )
119
- elsif new_candidatures.length == 1 && !new_candidatures.first.resource.valid?
120
- errors.add(
121
- :base,
122
- I18n.t(
123
- 'activerecord.errors.models.task.attributes.base.' +
124
- 'candidature_resource_invalid'
125
- )
126
- )
127
- elsif new_candidatures.length != 1
128
- errors.add(
129
- :base,
130
- I18n.t(
131
- 'activerecord.errors.models.task.attributes.base.' +
132
- 'only_one_new_candidature'
133
- )
134
- )
135
- end
89
+ private
90
+
91
+ def validate_vacancy
92
+ unless vacancy.valid?
93
+ errors[:base] << I18n.t('tasks.save.vacancy_invalid')
136
94
  end
137
95
  end
138
96
 
97
+ def set_vacancy_task_association
98
+ vacancy.do_open
99
+ vacancy.task_id = id
100
+ vacancy.save!
101
+ update_attribute :vacancy_id, vacancy.id
102
+ end
103
+
139
104
  def destroy_non_mongodb_records
140
- vacancies.destroy_all
105
+ vacancy.destroy
141
106
  end
142
107
  end
@@ -1,63 +1,14 @@
1
1
  class Product::ClassifiedAdvertisement::Vacancy < ::Vacancy
2
2
  has_many :candidatures, dependent: :destroy, class_name: 'Product::ClassifiedAdvertisement::Candidature', inverse_of: :vacancy
3
3
 
4
+ validates :timezone, presence: true
5
+ validates :from_raw, presence: true
6
+ validates :to_raw, presence: true
7
+
4
8
  attr_accessible :task_id, :task
5
9
 
6
10
  after_initialize :set_defaults
7
-
8
- =begin
9
- has_many :candidatures, -> do
10
- order(%Q{
11
- CASE
12
- WHEN candidatures.state='new' THEN 1
13
- WHEN candidatures.state='accepted' THEN 2
14
- WHEN candidatures.state='denied' THEN 3
15
- ELSE 4
16
- END
17
- })
18
- end
19
- =end
20
-
21
- validates :task, presence: true
22
-
23
- def candidatures_attributes=(attributes)
24
- self.candidatures ||= []
25
-
26
- attributes.each do |index, candidature_attributes|
27
- destroy = candidature_attributes.delete :_destroy
28
-
29
- if candidature_attributes[:id].present? && destroy.to_i == 1
30
- begin; candidature_class.destroy(candidature_attributes[:id]); rescue ActiveRecord::RecordNotFound; end
31
- @candidatures.select!{|v| v.id != candidature_attributes[:id]}
32
- next
33
- end
34
-
35
- candidature_attributes[:vacancy] = self
36
- candidature = nil
37
-
38
- if candidature_attributes[:id].present?
39
- begin; candidature = candidature_class.find(candidature_attributes[:id]); rescue ActiveRecord::RecordNotFound; end
40
-
41
- candidature_attributes.delete(:id)
42
-
43
- candidature.attributes = candidature_attributes if candidature.present?
44
- else
45
- candidature = candidature_class.new(candidature_attributes)
46
- end
47
-
48
- next unless candidature.present?
49
-
50
- if candidature_attributes[:id].present?
51
- self.candidatures.each_with_index do |current_candidature, candidatures_index|
52
- if current_candidature.id.to_s == candidature_attributes[:id]
53
- self.candidatures[candidatures_index] = candidature
54
- end
55
- end
56
- else
57
- self.candidatures << candidature
58
- end
59
- end
60
- end
11
+ after_update :set_cached_task_attributes
61
12
 
62
13
  def task
63
14
  @task ||= task_class.where(id: task_id).first
@@ -88,13 +39,13 @@ class Product::ClassifiedAdvertisement::Vacancy < ::Vacancy
88
39
  @product ||= project.product if project
89
40
  end
90
41
 
91
- #def new_or_accepted_candidature
92
- # candidatures.where(state: ['new', 'accepted']).first
93
- #end
42
+ def calculate_accepted_candidatures_amount
43
+ candidatures.accepted.sum('amount')
44
+ end
94
45
 
95
- #def denied_candidatures
96
- # candidatures.where(state: 'denied')
97
- #end
46
+ def create_project_user?
47
+ false
48
+ end
98
49
 
99
50
  protected
100
51
 
@@ -103,4 +54,10 @@ class Product::ClassifiedAdvertisement::Vacancy < ::Vacancy
103
54
 
104
55
  super
105
56
  end
57
+
58
+ private
59
+
60
+ def set_cached_task_attributes
61
+ task.update_attributes(from: from, to: to, resource_type: resource_type)
62
+ end
106
63
  end
@@ -0,0 +1,8 @@
1
+ <ul class="nav nav-pills">
2
+ <li role="presentation" class="<%= current_page?(story_tasks_path(@story)) ? 'active' : '' %>">
3
+ <%= link_to t('general.list'), story_tasks_path(@story) %>
4
+ </li>
5
+ <li role="presentation" class="<%= current_page?(calendar_story_tasks_path(@story)) ? 'active' : '' %>">
6
+ <%= link_to t('general.calendar'), calendar_story_tasks_path(@story) %>
7
+ </li>
8
+ </ul>
@@ -0,0 +1,23 @@
1
+ <% content_for :stylesheet_includes do %>
2
+ <%= stylesheet_link_tag 'fullcalendar' %>
3
+ <% end %>
4
+
5
+ <%= render partial: 'classified_advertisement/tasks/navigation' %>
6
+
7
+ <div id="calendar"></div>
8
+
9
+ <p style="margin-top:15px;">
10
+ <%= link_to new_story_task_path(@story), class: 'btn btn-default' do %>
11
+ <span class="glyphicon glyphicon-plus"></span> <%= t("tasks.new.title") %>
12
+ <% end %>
13
+ </p>
14
+
15
+ <% content_for :document_ready do %>
16
+ $('#calendar').fullCalendar({
17
+ events: '<%= events_story_tasks_path(@story, format: 'json') %>'
18
+ });
19
+ <% end %>
20
+
21
+ <% content_for :javascript_includes do %>
22
+ <%= javascript_include_tag 'fullcalendar' %>
23
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if @error.present? %>
2
+ alert("<%= @error %>");
3
+ <% else %>
4
+ window.location.reload();
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if @error.present? %>
2
+ alert("<%= @error %>");
3
+ <% else %>
4
+ window.location.reload();
5
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <div class="modal-dialog">
2
+ <div class="modal-content">
3
+ <%= form_tag sign_up_task_path(@task.id), method: :put, remote: true, class: 'form-horizontal' do %>
4
+ <div class="modal-header">
5
+ <h3><%= t('general.sign_up') %></h3>
6
+ </div>
7
+ <div class="modal-body">
8
+ <div class="form-group string required candidature_amount">
9
+ <label class="string required control-label col-sm-3 control-label" for="candidature_amount">
10
+ <abbr title="required">*</abbr> <%= t('activerecord.attributes.candidature.amount') %>
11
+ </label>
12
+ <div class="col-sm-9">
13
+ <input class="string required form-control" type="text" name="candidature[amount]" id="candidature_amount" value="<%= @amount %>">
14
+ </div>
15
+ </div>
16
+ </div>
17
+ <div class="modal-footer">
18
+ <button type="button" class="btn btn-default" data-dismiss="modal"><%= t('general.close') %></button>
19
+ <%= submit_tag t('general.submit'), class: 'btn btn-default' %>
20
+ </div>
21
+ <% end %>
22
+ </div>
23
+ </div>
@@ -4,17 +4,14 @@
4
4
 
5
5
  <%= f.check_box :_destroy %>
6
6
  <%= f.label :_destroy, t('general.destroy') %>
7
- <div class="form-actions">
8
- <div class="control-group string required" style="display: block">
9
- <div class="controls">
10
- &nbsp;&nbsp;&nbsp;&nbsp;
11
- <%= link_to_add_fields(
12
- t('stories.steps.setup_tasks.add_vacancy'), f, :vacancies, target: 'setup_vacancies_input'
13
- ) %>
14
- </div>
15
- </div>
16
- </div>
17
7
 
8
+ <div class="form-group">
9
+ &nbsp;&nbsp;&nbsp;&nbsp;
10
+ <%= link_to_add_fields(
11
+ t('stories.steps.setup_tasks.add_vacancy'), f, :vacancies, target: 'setup_vacancies_input'
12
+ ) %>
13
+ </div>
14
+
18
15
  <fieldset>
19
16
  <legend><%= t('vacancies.index.title')%></legend>
20
17
  <div id="setup_vacancies_input" class="form-inputs">
@@ -0,0 +1,76 @@
1
+ <%= render partial: 'classified_advertisement/tasks/navigation' %>
2
+
3
+ <% if @tasks.none? || @tasks.select{|e| e.id.present? }.none? %>
4
+ <p><%= I18n.t("tasks.index.empty_collection")%></p>
5
+ <% else %>
6
+ <table class="table table-striped">
7
+ <thead>
8
+ <tr class="<%= cycle('odd', 'even') %>">
9
+ <th><%= t('attributes.name') %></th>
10
+ <th><%= t('attributes.resource_type') %>
11
+ <th><%= t('attributes.from') %>
12
+ <th><%= t('attributes.to') %>
13
+ <th><%= t('activerecord.attributes.vacancy.limit') %></th>
14
+ <% if user_signed_in? %><th></th><% end %>
15
+ <th></th>
16
+ </tr>
17
+ </thead>
18
+ <tbody>
19
+ <% tasks_with_candidatures_of_current_user = tasks_with_candidatures(current_user) %>
20
+ <% @tasks.select{|e| e.id.present? }.each do |task| %>
21
+ <% accepted_candidatures_amount = task.vacancy.calculate_accepted_candidatures_amount %>
22
+ <tr class="<%= cycle('odd', 'even') %>">
23
+ <td><%= link_to task.name, task_path(task) %></td>
24
+ <td><%= task.resource_type %></td>
25
+ <td><%= task.from ? l(task.from, format: :default) : '-' %></td>
26
+ <td><%= task.to ? l(task.to, format: :default) : '-' %></td>
27
+ <td>
28
+ <%= accepted_candidatures_amount %> / <%= task.vacancy.limit || '∞' %>
29
+ </td>
30
+ <% if user_signed_in? %>
31
+ <td>
32
+ <%= render partial: 'products/types/classified_advertisement/tasks/state_switch', locals: { task: task, accepted_candidatures_amount: accepted_candidatures_amount, signed_up: tasks_with_candidatures_of_current_user.include?(task.id) } %>
33
+ </td>
34
+ <% end %>
35
+ <td>
36
+ <% if !task.is_a?(Column) && (
37
+ can?(:destroy, task) || can?(:edit, task) || (
38
+ task.respond_to?(:state_events) && task.state_events.select{|event| can? event, task }.any?
39
+ )
40
+ ) %>
41
+ <div class="dropdown">
42
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#"><%= t('general.actions') %></a>
43
+ <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
44
+ <% if can? :destroy, task %>
45
+ <li>
46
+ <%= link_to(
47
+ t('general.destroy'), task_path(task.id), id: "task_#{task.id}", method: :delete,
48
+ data: { confirm: t('general.questions.are_you_sure') },
49
+ onclick: "delete_link('task_#{task.id}'); return false;"
50
+ )
51
+ %>
52
+ </li>
53
+ <% end %>
54
+ <% if can? :edit, task %>
55
+ <li><%= link_to t('general.edit'), eval("edit_task_path(task)") %></li>
56
+ <% end %>
57
+ <% links = event_links_for_resource(task, 'tasks') %>
58
+ <% if links.any? %>
59
+ <li class="divider"></li>
60
+ <%= render 'shared/resource/event_elements', links: links %>
61
+ <% end %>
62
+ </ul>
63
+ </div>
64
+ <% end %>
65
+ </td>
66
+ </tr>
67
+ <% end %>
68
+ </tbody>
69
+ </table>
70
+ <% end %>
71
+
72
+ <p style="margin-top:15px;">
73
+ <%= link_to new_story_task_path(@story), class: 'btn btn-default' do %>
74
+ <span class="glyphicon glyphicon-plus"></span> <%= t("tasks.new.title") %>
75
+ <% end %>
76
+ </p>
@@ -0,0 +1,134 @@
1
+ <%= simple_form_for(@task, url: @task.new_record? ? tasks_path : task_path(@task), as: :task, html: {class: 'form-vertical', style: 'margin-bottom:15px;'}) do |f| %>
2
+ <%= hidden_field_tag :story_id, @task.story_id %>
3
+ <%= f.input :name %>
4
+ <%= f.input :text, as: :text %>
5
+
6
+ <fieldset class="fieldset" style="border: 1px solid black; padding:15px; margin-top:15px;">
7
+ <legend style="margin-bottom: 0px;"><%= t('activerecord.models.vacancy') %></legend>
8
+
9
+ <div class="form-group string optional vacancy_resource_type <%= params[:task].present? && @task.vacancy.resource_type.blank? ? ' has-error' : '' %>">
10
+ <label class="string optional control-label control-label" for="vacancy_resource_type">
11
+ <abbr title="required">*</abbr> <%= t('attributes.resource_type') %>
12
+ </label>
13
+ <%= select_tag :resource_type, options_for_select(['User', 'Thing'], @task.vacancy.resource_type), id: 'vacancy_resource_type', name: 'task[vacancy_attributes][resource_type]', class: 'string required form-control' %>
14
+ <% if params[:task].present? && @task.vacancy.resource_type.blank? %>
15
+ <span class="help-block"><%= t('errors.messages.blank') %></span>
16
+ <% end %>
17
+ </div>
18
+
19
+ <div class="form-group string required vacancy_name <%= params[:task].present? && @task.vacancy.name.blank? ? ' has-error' : '' %>">
20
+ <label class="string required control-label control-label" for="vacancy_name">
21
+ <abbr title="required">*</abbr> <%= t('attributes.name') %>
22
+ </label>
23
+ <%= text_field_tag :name, @task.vacancy.name, id: 'vacancy_name', name: 'task[vacancy_attributes][name]', class: 'string required form-control' %>
24
+ <% if params[:task].present? && @task.vacancy.name.blank? %>
25
+ <span class="help-block"><%= t('errors.messages.blank') %></span>
26
+ <% end %>
27
+ </div>
28
+
29
+ <div class="form-group string optional vacancy_limit">
30
+ <label class="string optional control-label control-label" for="vacancy_limit">
31
+ <%= t('activerecord.attributes.vacancy.limit') %>
32
+ </label>
33
+ <%= text_field_tag :limit, @task.vacancy.limit, id: 'vacancy_limit', name: 'task[vacancy_attributes][limit]', class: 'string optional form-control' %>
34
+ </div>
35
+
36
+ <div class="form-group string optional vacancy_timezone <%= params[:task].present? && @task.vacancy.timezone.blank? ? ' has-error' : '' %>">
37
+ <label class="string optional control-label control-label" for="vacancy_timezone">
38
+ <%= t('attributes.timezone') %>
39
+ </label>
40
+ <%= time_zone_select @task.vacancy, :timezone, nil, {}, id: 'vacancy_timezone', name: 'task[vacancy_attributes][timezone]', class: 'form-control', class: 'string required form-control' %>
41
+ <% if params[:task].present? && @task.vacancy.timezone.blank? %>
42
+ <span class="help-block"><%= t('errors.messages.blank') %></span>
43
+ <% end %>
44
+ </div>
45
+
46
+ <div class="form-group string optional vacancy_from_raw <%= params[:task].present? && @task.vacancy.from_raw.blank? ? ' has-error' : '' %>">
47
+ <label class="string optional control-label control-label" for="vacancy_from_raw">
48
+ <%= t('activerecord.attributes.vacancy.from') %>
49
+ </label>
50
+ <div class="datetime_picker" class="input-append date">
51
+ <%= text_field_tag :from_raw, @task.vacancy.from_raw, id: 'vacancy_from_raw', name: 'task[vacancy_attributes][from_raw]', 'data-format' => 'yyyy-MM-dd hh:mm:ss', style: 'width:165px;', class: 'string required form-control' %>
52
+ <span class="add-on">
53
+ <i data-time-icon="icon-time" data-date-icon="icon-calendar">
54
+ </i>
55
+ </span>
56
+ <% if params[:task].present? && @task.vacancy.from_raw.blank? %>
57
+ <span class="help-block"><%= t('errors.messages.blank') %></span>
58
+ <% end %>
59
+ </div>
60
+ </div>
61
+
62
+ <div class="form-group string optional vacancy_to_raw <%= params[:task].present? && @task.vacancy.to_raw.blank? ? ' has-error' : '' %>">
63
+ <label class="string optional control-label control-label" for="vacancy_to_raw">
64
+ <%= t('activerecord.attributes.vacancy.to') %>
65
+ </label>
66
+ <div class="datetime_picker" class="input-append date">
67
+ <%= text_field_tag :to_raw, @task.vacancy.to_raw, id: 'vacancy_to_raw', name: 'task[vacancy_attributes][to_raw]', 'data-format' => 'yyyy-MM-dd hh:mm:ss', style: 'width:165px;', class: 'string required form-control' %>
68
+ <span class="add-on">
69
+ <i data-time-icon="icon-time" data-date-icon="icon-calendar">
70
+ </i>
71
+ </span>
72
+ <% if params[:task].present? && @task.vacancy.to_raw.blank? %>
73
+ <span class="help-block"><%= t('errors.messages.blank') %></span>
74
+ <% end %>
75
+ </div>
76
+ </div>
77
+ </fieldset>
78
+
79
+ <fieldset class="fieldset" style="border: 1px solid black; padding:15px; margin-top:15px; margin-bottom:15px;">
80
+ <legend style="margin-bottom: 0px;"><%= t('attributes.address') %></legend>
81
+ <div class="form-group string optional task_address">
82
+ <label class="string optional control-label control-label" for="task_address"><%= t('attributes.string') %></label>
83
+ <input name="task[address]" id="task_address" value="<%= @task.address %>" class="string optional form-control"/>
84
+ <div id="task_map" style="width: 500px; height: 400px; margin-top:15px;"></div>
85
+ <input type="hidden" name="task[lat]" id="task_lat" value="<%= @task.lat %>"/>
86
+ <input type="hidden" name="task[lon]" id="task_lon" value="<%= @task.lon %>"/>
87
+ </div>
88
+
89
+ <div class="form-group string optional task_address_description">
90
+ <label class="string optional control-label control-label" for="task_address_description"><%= t('attributes.description') %></label>
91
+ <input name="task[address_description]" id="task_address_description" value="<%= @task.address_description %>" class="string optional form-control"/>
92
+ </div>
93
+ </fieldset>
94
+
95
+ <%= f.button :submit %>
96
+ <% end %>
97
+
98
+ <% content_for :javascript_includes do %>
99
+ <script type="text/javascript" src='http://maps.google.com/maps/api/js?sensor=false&libraries=places'></script>
100
+ <%= javascript_include_tag 'voluntary/optional_lib/jquery.location_picker.js' %>
101
+ <% end %>
102
+
103
+ <% content_for :document_ready do %>
104
+ var lat = "<%= @task.lat %>";
105
+ var lon = "<%= @task.lon %>";
106
+
107
+ function initLocationPicker(position) {
108
+ options = {
109
+ radius: 300,
110
+ inputBinding: {
111
+ latitudeInput: $('#task_lat'),
112
+ longitudeInput: $('#task_lon'),
113
+ locationNameInput: $('#task_address')
114
+ },
115
+ enableAutocomplete: true
116
+ }
117
+
118
+ if(position) {
119
+ options['location'] = { latitude: position.coords.latitude, longitude: position.coords.longitude }
120
+ } else if (lat != "") {
121
+ options['location'] = { latitude: lat, longitude: lon }
122
+ }
123
+
124
+ $('#task_map').locationpicker(options);
125
+ }
126
+
127
+ if(lat == "" && navigator.geolocation) {
128
+ navigator.geolocation.getCurrentPosition(initLocationPicker);
129
+ } else {
130
+ initLocationPicker(null);
131
+ }
132
+
133
+ $('#vacancy_timezone').val('<%= @task.vacancy.timezone %>')
134
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <% if signed_up %>
2
+ <% if task.vacancy.resource_type == 'Thing' %>
3
+ <%= link_to t('tasks.show.change_signing'), change_signing_task_path(task.id), class: 'btn btn-warning btn-xs remote_modal_link' %>
4
+ <% end %>
5
+
6
+ <%= link_to t('general.sign_out'), sign_out_task_path(task.id), method: :delete, remote: true, data: { confirm: t('general.questions.are_you_sure') }, class: 'btn btn-danger btn-xs' %>
7
+ <% else %>
8
+ <% if (task.vacancy.limit.blank? || accepted_candidatures_amount < task.vacancy.limit) && !task.vacancy.ended? %>
9
+ <% if task.vacancy.resource_type == 'User' %>
10
+ <%= link_to t('general.sign_up'), sign_up_task_path(task.id), method: :put, remote: true, class: 'btn btn-success btn-xs' %>
11
+ <% else %>
12
+ <%= link_to t('general.sign_up'), sign_up_task_path(task.id), class: 'btn btn-success btn-xs remote_modal_link' %>
13
+ <% end %>
14
+ <% else %>
15
+ <%= link_to t('general.sign_up'), '#', class: 'btn btn-danger btn-xs disabled' %></a>
16
+ <% end %>
17
+ <% end %>
@@ -0,0 +1,42 @@
1
+ <% accepted_candidatures_amount = resource.vacancy.calculate_accepted_candidatures_amount %>
2
+ <% signed_up = Candidature.where(user_id: current_user.id, vacancy_id: resource.vacancy_id).any? %>
3
+ <h3><%= resource.name %></h3>
4
+
5
+ <% if resource.text.present? %>
6
+ <%= markdown resource.text %>
7
+ <% end %>
8
+
9
+ <dl class="dl-horizontal">
10
+ <%= show_attribute :vacancy_title, title: t('tasks.show.vacancy_title'), value: resource.vacancy.name %>
11
+ <%= show_attribute :from, title: t('attributes.from'), value: resource.from ? l(resource.from, format: :default) : '-' %>
12
+ <%= show_attribute :to, title: t('attributes.to'), value: resource.to ? l(resource.to, format: :default) : '-' %>
13
+ <%= show_attribute :limit, title: t('activerecord.attributes.vacancy.limit'), value: "#{accepted_candidatures_amount} / #{resource.vacancy.limit ? resource.vacancy.limit : '∞'}" %>
14
+ <%= show_attribute :sign_up, title: t('general.sign_up') + ' / ' + t('general.sign_out'), value: render(partial: 'products/types/classified_advertisement/tasks/state_switch', locals: { task: resource, accepted_candidatures_amount: accepted_candidatures_amount, signed_up: signed_up }) %>
15
+ <%= show_actions %>
16
+ </dl>
17
+
18
+ <% if @task.lat.present? %>
19
+ <h4><%= t('attributes.address') %></h4>
20
+
21
+ <p><strong><%= t('attributes.string') %>:</strong> <%= resource.address %></p>
22
+
23
+ <% if resource.address_description.present? %>
24
+ <p><strong><%= t('attributes.description') %></strong> <%= resource.address_description %></p>
25
+ <% end %>
26
+
27
+ <div id="task_map" style="width: 500px; height: 400px; margin-top:15px;"></div>
28
+
29
+ <% content_for :javascript_includes do %>
30
+ <script type="text/javascript" src='http://maps.google.com/maps/api/js?sensor=false&libraries=places'></script>
31
+ <%= javascript_include_tag 'voluntary/optional_lib/jquery.location_picker.js' %>
32
+ <% end %>
33
+
34
+ <% content_for :document_ready do %>
35
+ $('#task_map').locationpicker({
36
+ location: { latitude: "<%= @task.lat %>", longitude: "<%= @task.lon %>" },
37
+ radius: 300
38
+ });
39
+ <% end %>
40
+ <% end %>
41
+
42
+ <p>&nbsp;</p>
@@ -0,0 +1,45 @@
1
+ <% if @story.new_record? %>
2
+ <h1><%= t('stories.new.title') %></h1>
3
+ <% else %>
4
+ <h1><%= t('stories.edit.title') %></h1>
5
+ <% end %>
6
+
7
+ <%= simple_form_for(@story, url: @story.new_record? ? stories_path : story_path(@story), as: :story, html: {class: 'form-vertical'}) do |f| %>
8
+ <%= render partial: 'shared/form/error_messages', locals: { resource: @story } %>
9
+
10
+ <%= @story.project ? f.hidden_field(:project_id) : f.input(:project_id, collection: Project.all) %>
11
+ <%= f.input :name %>
12
+ <%= f.input :text, as: :text %>
13
+
14
+ <div class="form-group string optional story_address">
15
+ <label class="string optional control-label control-label" for="story_address">Address</label>
16
+ <input name="story[address]" id="story_address" value="<%= @story.address %>" class="string required form-control"/>
17
+ <div id="story_map" style="width: 500px; height: 400px; margin-top:15px;"></div>
18
+ <input type="hidden" name="story[lat]" id="story_lat" value="<%= @story.lat %>"/>
19
+ <input type="hidden" name="story[lon]" id="story_lon" value="<%= @story.lon %>"/>
20
+ </div>
21
+
22
+ <div class="form-group string optional story_address_description">
23
+ <label class="string optional control-label control-label" for="story_address_description">Address description</label>
24
+ <input name="story[address_description]" id="story_address_description" value="<%= @story.address_description %>" class="string required form-control"/>
25
+ </div>
26
+ <%= f.button :submit %>
27
+ <% end %>
28
+
29
+ <% content_for :javascript_includes do %>
30
+ <script type="text/javascript" src='http://maps.google.com/maps/api/js?sensor=false&libraries=places'></script>
31
+ <%= javascript_include_tag 'voluntary/optional_lib/jquery.location_picker.js' %>
32
+ <% end %>
33
+
34
+ <% content_for :document_ready do %>
35
+ $('#story_map').locationpicker({
36
+ location: {latitude: <%= @story.lat ? @story.lat : 'null' %>, longitude: <%= @story.lon ? @story.lon : 'null' %>},
37
+ radius: 300,
38
+ inputBinding: {
39
+ latitudeInput: $('#story_lat'),
40
+ longitudeInput: $('#story_lon'),
41
+ locationNameInput: $('#story_address')
42
+ },
43
+ enableAutocomplete: true
44
+ });
45
+ <% end %>
@@ -12,7 +12,7 @@
12
12
  <% f.object.candidatures.build if f.object.candidatures.select{|c| ['new', 'accepted'].include?(c.state)}.none? %>
13
13
 
14
14
  <%
15
- f.object.candidatures.sort! do |x,y|
15
+ f.object.candidatures = f.object.candidatures.to_a.sort do |x,y|
16
16
  Candidature::STATES.index(x.state.to_sym) <=> Candidature::STATES.index(y.state.to_sym)
17
17
  end
18
18
  %>
@@ -1,16 +1,14 @@
1
1
  <%= render 'shared/form/error_messages', resource: resource %>
2
- <div class="form-inputs">
3
- <table class="table table-striped">
4
- <thead>
5
- <th>Name</th>
6
- <th>Text</th>
7
- </thead>
8
- <tbody>
9
- <%= f.simple_fields_for :vacancies do |vacancy_form| %>
10
- <%= render_product_specific_partial_if_available(
11
- vacancy_form.object, 'workflow/tasks/vacancy_fields', f: vacancy_form
12
- ) %>
13
- <% end %>
14
- </tbody>
15
- </table>
16
- </div>
2
+ <table class="table table-striped">
3
+ <thead>
4
+ <th><%= t('attributes.name') %></th>
5
+ <th><%= t('attributes.text') %></th>
6
+ </thead>
7
+ <tbody>
8
+ <%= f.simple_fields_for :vacancies do |vacancy_form| %>
9
+ <%= render_product_specific_partial_if_available(
10
+ vacancy_form.object, 'workflow/tasks/vacancy_fields', f: vacancy_form
11
+ ) %>
12
+ <% end %>
13
+ </tbody>
14
+ </table>
@@ -0,0 +1,5 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ candidature:
5
+ amount: Amount
@@ -1,4 +1,17 @@
1
1
  en:
2
+ tasks:
3
+ save:
4
+ vacancy_invalid: Vacancy form is invalid!
5
+ show:
6
+ vacancy_title: Vacancy title
7
+ change_signing: Change signing
8
+
9
+ sign_up:
10
+ already_signed_up: You've already signed up this much!
11
+ limit_reached: The limit is already reached!
12
+ sign_out:
13
+ not_signed_up: You've not signed up yet!
14
+
2
15
  activerecord:
3
16
  errors:
4
17
  models:
data/config/routes.rb CHANGED
@@ -1,2 +1,19 @@
1
1
  Rails.application.routes.draw do
2
+ resources :tasks do
3
+ member do
4
+ get 'sign_up' => 'classified_advertisement/tasks#sign_up_form'
5
+ put 'sign_up' => 'classified_advertisement/tasks#sign_up'
6
+ get 'change_signing' => 'classified_advertisement/tasks#sign_up_form'
7
+ delete 'sign_out' => 'classified_advertisement/tasks#sign_out'
8
+ end
9
+ end
10
+
11
+ resources :stories, only: [:create, :show, :edit, :update, :destroy] do
12
+ resources :tasks, only: [:index, :new] do
13
+ collection do
14
+ get 'calendar' => 'classified_advertisement/tasks#calendar'
15
+ get 'events' => 'classified_advertisement/tasks#events'
16
+ end
17
+ end
18
+ end
2
19
  end
@@ -1,9 +1,9 @@
1
1
  class AddClassifiedAdvertisementProduct < ActiveRecord::Migration
2
2
  def up
3
- product = Product.create(name: 'Classified Advertisement', text: 'Dummy')
3
+ product = Product::ClassifiedAdvertisement.create(name: 'Classified Advertisement', text: 'Dummy')
4
4
  end
5
5
 
6
6
  def down
7
- Product.where(name: 'Classified Advertisement').first.destroy
7
+ Product::ClassifiedAdvertisement.first.destroy
8
8
  end
9
9
  end
@@ -0,0 +1,5 @@
1
+ class AddAmountToCandidatures < ActiveRecord::Migration
2
+ def change
3
+ add_column :candidatures, :amount, :integer
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module VoluntaryClassifiedAdvertisement
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voluntary_classified_advertisement
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.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-04-10 00:00:00.000000000 Z
11
+ date: 2015-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: voluntary
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.0
19
+ version: '0.7'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.3.0
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: voluntary_recruiting
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: letter_opener
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -262,7 +276,7 @@ dependencies:
262
276
  - - "~>"
263
277
  - !ruby/object:Gem::Version
264
278
  version: 0.7.1
265
- description: 'Plugin for #Crowdsourcing system Voluntary.Software: http://bit.ly/vca-0-2-0'
279
+ description: "#Crowdsourcing plugin: http://bit.ly/vca-0-3-0"
266
280
  email:
267
281
  - gawlista@gmail.com
268
282
  executables: []
@@ -273,19 +287,32 @@ files:
273
287
  - MIT-LICENSE
274
288
  - README.md
275
289
  - Rakefile
290
+ - app/controllers/classified_advertisement/tasks_controller.rb
291
+ - app/helpers/voluntary_classified_advertisement/tasks_helper.rb
276
292
  - app/models/asset.rb
277
293
  - app/models/product/classified_advertisement.rb
278
294
  - app/models/product/classified_advertisement/candidature.rb
279
295
  - app/models/product/classified_advertisement/story.rb
280
296
  - app/models/product/classified_advertisement/task.rb
281
297
  - app/models/product/classified_advertisement/vacancy.rb
298
+ - app/views/classified_advertisement/tasks/_navigation.html.erb
299
+ - app/views/classified_advertisement/tasks/calendar.html.erb
300
+ - app/views/classified_advertisement/tasks/sign_out.js.erb
301
+ - app/views/classified_advertisement/tasks/sign_up.js.erb
302
+ - app/views/classified_advertisement/tasks/sign_up_form.html.erb
282
303
  - app/views/products/types/classified_advertisement/stories/_task_fields.html.erb
283
304
  - app/views/products/types/classified_advertisement/stories/_vacancy_fields.html.erb
305
+ - app/views/products/types/classified_advertisement/tasks/_collection.html.erb
306
+ - app/views/products/types/classified_advertisement/tasks/_form.html.erb
307
+ - app/views/products/types/classified_advertisement/tasks/_state_switch.html.erb
308
+ - app/views/products/types/classified_advertisement/tasks/show.html.erb
309
+ - app/views/products/types/classified_advertisement/wizard.html.erb
284
310
  - app/views/products/types/classified_advertisement/workflow/tasks/_candidature_fields.html.erb
285
311
  - app/views/products/types/classified_advertisement/workflow/tasks/_resource_fields.html.erb
286
312
  - app/views/products/types/classified_advertisement/workflow/tasks/_vacancy_fields.html.erb
287
313
  - app/views/products/types/classified_advertisement/workflow/tasks/_work_form.html.erb
288
314
  - app/views/products/types/classified_advertisement/workflow/tasks/_work_head.html.erb
315
+ - config/locales/resources/candidature/en.yml
289
316
  - config/locales/resources/story/en.yml
290
317
  - config/locales/resources/task/en.yml
291
318
  - config/locales/workflow/en.yml
@@ -293,6 +320,7 @@ files:
293
320
  - db/migrate/20130806131503_add_classified_advertisement_product.rb
294
321
  - db/migrate/20130809134227_add_task_id_to_vacancies.rb
295
322
  - db/migrate/20130830170731_create_assets.rb
323
+ - db/migrate/20151021161627_add_amount_to_candidatures.rb
296
324
  - lib/tasks/voluntary_classified_advertising_tasks.rake
297
325
  - lib/voluntary_classified_advertisement.rb
298
326
  - lib/voluntary_classified_advertisement/engine.rb