tawork 0.0.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 (239) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +16 -0
  4. data/Gemfile +91 -0
  5. data/Gemfile.lock +295 -0
  6. data/MIT-LICENSE +20 -0
  7. data/Procfile +2 -0
  8. data/README.md +1 -0
  9. data/Rakefile +6 -0
  10. data/app/assets/images/.keep +0 -0
  11. data/app/assets/javascripts/application.js +31 -0
  12. data/app/assets/javascripts/backbone/models/.gitkeep +0 -0
  13. data/app/assets/javascripts/backbone/routers/.gitkeep +0 -0
  14. data/app/assets/javascripts/backbone/tawork.js.coffee +11 -0
  15. data/app/assets/javascripts/backbone/templates/.gitkeep +0 -0
  16. data/app/assets/javascripts/backbone/views/.gitkeep +0 -0
  17. data/app/assets/javascripts/backbone/views/page.js.coffee +75 -0
  18. data/app/assets/javascripts/backbone/views/ticket.js.coffee +110 -0
  19. data/app/assets/javascripts/backbone/views/tree_node_page.js.coffee +16 -0
  20. data/app/assets/javascripts/backbone/views/tree_node_ticket.js.coffee +14 -0
  21. data/app/assets/javascripts/wiki/pages.js.coffee +3 -0
  22. data/app/assets/stylesheets/application.css +22 -0
  23. data/app/assets/stylesheets/bootstrap_and_overrides.sass +208 -0
  24. data/app/assets/stylesheets/diff.css +14 -0
  25. data/app/assets/stylesheets/wiki/pages.css.scss +3 -0
  26. data/app/controllers/application_controller.rb +15 -0
  27. data/app/controllers/assignments_controller.rb +30 -0
  28. data/app/controllers/attachments_controller.rb +10 -0
  29. data/app/controllers/comments_controller.rb +24 -0
  30. data/app/controllers/concerns/.keep +0 -0
  31. data/app/controllers/home_controller.rb +7 -0
  32. data/app/controllers/projects_controller.rb +31 -0
  33. data/app/controllers/search_controller.rb +49 -0
  34. data/app/controllers/sink_controller.rb +10 -0
  35. data/app/controllers/tickets_controller.rb +147 -0
  36. data/app/controllers/users/omniauth_callbacks_controller.rb +23 -0
  37. data/app/controllers/wiki/pages_controller.rb +115 -0
  38. data/app/controllers/wiki/spaces_controller.rb +37 -0
  39. data/app/helpers/application_helper.rb +20 -0
  40. data/app/helpers/wiki/pages_helper.rb +2 -0
  41. data/app/inputs/fake_input.rb +6 -0
  42. data/app/mailers/.keep +0 -0
  43. data/app/models/.keep +0 -0
  44. data/app/models/assignment.rb +5 -0
  45. data/app/models/attachment.rb +54 -0
  46. data/app/models/bug.rb +2 -0
  47. data/app/models/comment.rb +6 -0
  48. data/app/models/concerns/.keep +0 -0
  49. data/app/models/page.rb +68 -0
  50. data/app/models/project.rb +2 -0
  51. data/app/models/space.rb +2 -0
  52. data/app/models/story.rb +29 -0
  53. data/app/models/story_detail.rb +3 -0
  54. data/app/models/task.rb +2 -0
  55. data/app/models/ticket.rb +127 -0
  56. data/app/models/user.rb +36 -0
  57. data/app/models/user_verifier.rb +2 -0
  58. data/app/views/comments/_comment.html.haml +6 -0
  59. data/app/views/comments/_form.html.haml +4 -0
  60. data/app/views/comments/create.js.coffee +7 -0
  61. data/app/views/devise/confirmations/new.html.erb +12 -0
  62. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  63. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  64. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  65. data/app/views/devise/passwords/edit.html.erb +16 -0
  66. data/app/views/devise/passwords/new.html.erb +12 -0
  67. data/app/views/devise/registrations/edit.html.erb +29 -0
  68. data/app/views/devise/registrations/new.html.erb +18 -0
  69. data/app/views/devise/sessions/new.html.erb +17 -0
  70. data/app/views/devise/shared/_links.erb +25 -0
  71. data/app/views/devise/unlocks/new.html.erb +12 -0
  72. data/app/views/home/index.html.haml +4 -0
  73. data/app/views/layouts/_activity_wrapper.html.haml +17 -0
  74. data/app/views/layouts/_nav_header.html.haml +26 -0
  75. data/app/views/layouts/_spaces.html.haml +34 -0
  76. data/app/views/layouts/application.html.haml +39 -0
  77. data/app/views/layouts/minimal.html.haml +22 -0
  78. data/app/views/projects/index.html.haml +16 -0
  79. data/app/views/projects/new.html.haml +6 -0
  80. data/app/views/public_activity/ticket/_assignment.html.haml +14 -0
  81. data/app/views/public_activity/ticket/_create_comment.html.haml +10 -0
  82. data/app/views/public_activity/ticket/_created.html.haml +3 -0
  83. data/app/views/public_activity/ticket/_reorder.html.haml +2 -0
  84. data/app/views/public_activity/ticket/_state_change.html.haml +2 -0
  85. data/app/views/public_activity/ticket/_update_details.html.haml +13 -0
  86. data/app/views/tickets/_activity.html.haml +3 -0
  87. data/app/views/tickets/_breadcrumb.html.haml +7 -0
  88. data/app/views/tickets/_bug_form.html.haml +1 -0
  89. data/app/views/tickets/_events_dropdown.html.haml +4 -0
  90. data/app/views/tickets/_form.html.haml +28 -0
  91. data/app/views/tickets/_project_form.html.haml +1 -0
  92. data/app/views/tickets/_story_form.html.haml +15 -0
  93. data/app/views/tickets/_task_form.html.haml +8 -0
  94. data/app/views/tickets/_tickets_listing.html.haml +5 -0
  95. data/app/views/tickets/_title_and_description.html.haml +8 -0
  96. data/app/views/tickets/_tree_node.html.haml +28 -0
  97. data/app/views/tickets/assignment.js.coffee +3 -0
  98. data/app/views/tickets/create.js.coffee +7 -0
  99. data/app/views/tickets/new.html.haml +1 -0
  100. data/app/views/tickets/show.html.haml +64 -0
  101. data/app/views/tickets/trigger_event.js.coffee +12 -0
  102. data/app/views/tickets/update.js.coffee +12 -0
  103. data/app/views/wiki/pages/_attachment.html.haml +5 -0
  104. data/app/views/wiki/pages/_attachments.html.haml +22 -0
  105. data/app/views/wiki/pages/_breadcrumb.html.haml +9 -0
  106. data/app/views/wiki/pages/_child_menu.html.haml +9 -0
  107. data/app/views/wiki/pages/_display.html.haml +138 -0
  108. data/app/views/wiki/pages/_page_header.html.haml +13 -0
  109. data/app/views/wiki/pages/_subpages_dropdown.html.haml +6 -0
  110. data/app/views/wiki/pages/_subtree.html.haml +7 -0
  111. data/app/views/wiki/pages/_tree_node.html.haml +21 -0
  112. data/app/views/wiki/pages/attach.js.coffee +2 -0
  113. data/app/views/wiki/pages/combined.html.haml +8 -0
  114. data/app/views/wiki/pages/create.js.coffee +5 -0
  115. data/app/views/wiki/pages/edit.html.haml +2 -0
  116. data/app/views/wiki/pages/history.html.haml +13 -0
  117. data/app/views/wiki/pages/index.html.haml +2 -0
  118. data/app/views/wiki/pages/new.html.haml +13 -0
  119. data/app/views/wiki/pages/show.html.haml +14 -0
  120. data/app/views/wiki/pages/update.html.haml +2 -0
  121. data/app/views/wiki/spaces/_page_list_item.html.haml +11 -0
  122. data/app/views/wiki/spaces/_space_list.html.haml +4 -0
  123. data/app/views/wiki/spaces/new.html.haml +5 -0
  124. data/app/views/wiki/spaces/space_list.html.haml +1 -0
  125. data/bin/bundle +3 -0
  126. data/bin/rails +4 -0
  127. data/bin/rake +4 -0
  128. data/config/application.rb +30 -0
  129. data/config/boot.rb +4 -0
  130. data/config/database.yml +39 -0
  131. data/config/environment.rb +5 -0
  132. data/config/environments/development.rb +35 -0
  133. data/config/environments/production.rb +80 -0
  134. data/config/environments/test.rb +36 -0
  135. data/config/initializers/backtrace_silencers.rb +7 -0
  136. data/config/initializers/config.rb +4 -0
  137. data/config/initializers/devise.rb +257 -0
  138. data/config/initializers/elasticsearch.rb +9 -0
  139. data/config/initializers/filter_parameter_logging.rb +4 -0
  140. data/config/initializers/gollum.rb +31 -0
  141. data/config/initializers/haml_gfm.rb +66 -0
  142. data/config/initializers/inflections.rb +16 -0
  143. data/config/initializers/mime_types.rb +5 -0
  144. data/config/initializers/secret_token.rb +12 -0
  145. data/config/initializers/session_store.rb +3 -0
  146. data/config/initializers/simple_form.rb +145 -0
  147. data/config/initializers/simple_form_bootstrap.rb +73 -0
  148. data/config/initializers/wrap_parameters.rb +14 -0
  149. data/config/locales/devise.en.yml +59 -0
  150. data/config/locales/en.yml +23 -0
  151. data/config/locales/simple_form.en.yml +26 -0
  152. data/config/routes.rb +101 -0
  153. data/config/tinymce.yml +10 -0
  154. data/config.ru +4 -0
  155. data/db/migrate/20131209041251_create_tickets.rb +13 -0
  156. data/db/migrate/20131210041050_devise_create_users.rb +42 -0
  157. data/db/migrate/20131210043014_add_username_to_users.rb +5 -0
  158. data/db/migrate/20131210045348_add_creator_to_ticket.rb +5 -0
  159. data/db/migrate/20131211034104_create_comments.rb +11 -0
  160. data/db/migrate/20131212073014_create_assignments.rb +12 -0
  161. data/db/migrate/20131215220825_add_position_to_ticket.rb +5 -0
  162. data/db/migrate/20131216044331_create_story_details.rb +12 -0
  163. data/db/migrate/20131218060557_create_activities.rb +23 -0
  164. data/db/migrate/20140109235844_create_pages.rb +14 -0
  165. data/db/migrate/20140112004346_create_attachments.rb +13 -0
  166. data/db/migrate/20140120030547_add_name_to_users.rb +5 -0
  167. data/db/schema.rb +125 -0
  168. data/db/seeds.rb +7 -0
  169. data/init.rb +1 -0
  170. data/lib/assets/.keep +0 -0
  171. data/lib/tasks/.keep +0 -0
  172. data/lib/tawork/engine.rb +13 -0
  173. data/lib/tawork/version.rb +3 -0
  174. data/lib/tawork.rb +4 -0
  175. data/lib/templates/haml/scaffold/_form.html.haml +10 -0
  176. data/lib/ticket_assignment.rb +25 -0
  177. data/log/.keep +0 -0
  178. data/public/401.html +57 -0
  179. data/public/404.html +58 -0
  180. data/public/422.html +58 -0
  181. data/public/500.html +57 -0
  182. data/public/favicon.ico +0 -0
  183. data/public/robots.txt +5 -0
  184. data/tags +279 -0
  185. data/tawork.gemspec +24 -0
  186. data/vendor/.DS_Store +0 -0
  187. data/vendor/assets/.DS_Store +0 -0
  188. data/vendor/assets/javascripts/.keep +0 -0
  189. data/vendor/assets/javascripts/bootstrap-tagsinput.js +503 -0
  190. data/vendor/assets/javascripts/bootstrap-tree.js +15 -0
  191. data/vendor/assets/javascripts/bootstrap-typeahead.js +335 -0
  192. data/vendor/assets/javascripts/hallo.js +2949 -0
  193. data/vendor/assets/javascripts/highlight.pack.js +1 -0
  194. data/vendor/assets/javascripts/jquery.autosize.js +250 -0
  195. data/vendor/assets/javascripts/jquery.mjs.nestedSortable.js +613 -0
  196. data/vendor/assets/javascripts/rangy-core.js +94 -0
  197. data/vendor/assets/javascripts/tinymce/mention/plugin.js +358 -0
  198. data/vendor/assets/stylesheets/.keep +0 -0
  199. data/vendor/assets/stylesheets/bootflat-extensions.css +356 -0
  200. data/vendor/assets/stylesheets/bootflat-square.css +69 -0
  201. data/vendor/assets/stylesheets/bootflat.css +1556 -0
  202. data/vendor/assets/stylesheets/bootstrap-tagsinput.css +45 -0
  203. data/vendor/assets/stylesheets/bootstrap-tree.sass +82 -0
  204. data/vendor/assets/stylesheets/highlight/arta.css +160 -0
  205. data/vendor/assets/stylesheets/highlight/ascetic.css +50 -0
  206. data/vendor/assets/stylesheets/highlight/brown_paper.css +105 -0
  207. data/vendor/assets/stylesheets/highlight/brown_papersq.png +0 -0
  208. data/vendor/assets/stylesheets/highlight/dark.css +105 -0
  209. data/vendor/assets/stylesheets/highlight/default.css +153 -0
  210. data/vendor/assets/stylesheets/highlight/docco.css +132 -0
  211. data/vendor/assets/stylesheets/highlight/far.css +113 -0
  212. data/vendor/assets/stylesheets/highlight/foundation.css +133 -0
  213. data/vendor/assets/stylesheets/highlight/github.css +130 -0
  214. data/vendor/assets/stylesheets/highlight/googlecode.css +146 -0
  215. data/vendor/assets/stylesheets/highlight/idea.css +122 -0
  216. data/vendor/assets/stylesheets/highlight/ir_black.css +105 -0
  217. data/vendor/assets/stylesheets/highlight/magula.css +123 -0
  218. data/vendor/assets/stylesheets/highlight/mono-blue.css +62 -0
  219. data/vendor/assets/stylesheets/highlight/monokai.css +127 -0
  220. data/vendor/assets/stylesheets/highlight/monokai_sublime.css +102 -0
  221. data/vendor/assets/stylesheets/highlight/obsidian.css +154 -0
  222. data/vendor/assets/stylesheets/highlight/pojoaque.css +105 -0
  223. data/vendor/assets/stylesheets/highlight/pojoaque.jpg +0 -0
  224. data/vendor/assets/stylesheets/highlight/railscasts.css +182 -0
  225. data/vendor/assets/stylesheets/highlight/rainbow.css +115 -0
  226. data/vendor/assets/stylesheets/highlight/school_book.css +113 -0
  227. data/vendor/assets/stylesheets/highlight/school_book.png +0 -0
  228. data/vendor/assets/stylesheets/highlight/solarized_dark.css +92 -0
  229. data/vendor/assets/stylesheets/highlight/solarized_light.css +92 -0
  230. data/vendor/assets/stylesheets/highlight/sunburst.css +160 -0
  231. data/vendor/assets/stylesheets/highlight/tomorrow-night-blue.css +52 -0
  232. data/vendor/assets/stylesheets/highlight/tomorrow-night-bright.css +51 -0
  233. data/vendor/assets/stylesheets/highlight/tomorrow-night-eighties.css +51 -0
  234. data/vendor/assets/stylesheets/highlight/tomorrow-night.css +52 -0
  235. data/vendor/assets/stylesheets/highlight/tomorrow.css +49 -0
  236. data/vendor/assets/stylesheets/highlight/vs.css +89 -0
  237. data/vendor/assets/stylesheets/highlight/xcode.css +157 -0
  238. data/vendor/assets/stylesheets/highlight/zenburn.css +117 -0
  239. metadata +299 -0
@@ -0,0 +1,115 @@
1
+ class Wiki::PagesController < ApplicationController
2
+ before_filter :authenticate_user!
3
+ before_filter :load_page
4
+
5
+ def index
6
+ end
7
+
8
+ def create
9
+ create_params = page_params
10
+ if params[:markdown_body].present?
11
+ create_params[:body] = redcarpet(params[:markdown_body])
12
+ end
13
+ @page = Page.new create_params.merge(
14
+ creator: current_user,
15
+ parent_id: params[:parent_id]
16
+ )
17
+ if @page.save
18
+ @page.update_to_gollum(current_user)
19
+ @page.create_activity key: "page.created", owner: current_user
20
+ end
21
+ end
22
+
23
+ def show
24
+ @subtree = @page.subtree.group_by(&:parent_id)
25
+ end
26
+
27
+ def history
28
+ end
29
+
30
+ def combined
31
+ @subtree = @page.subtree.group_by(&:parent_id)
32
+ @hide_extras = true
33
+ render layout: "minimal"
34
+ end
35
+
36
+ def update
37
+ update_params = params.require(params[:type]).permit(
38
+ :title, :body,
39
+ )
40
+ if params[:markdown_body].present?
41
+ update_params[:body] = redcarpet(params[:markdown_body])
42
+ end
43
+ if @page.update_attributes(update_params)
44
+ @page.update_to_gollum(current_user)
45
+ @page.create_activity key: "page.update_details", owner: current_user
46
+ end
47
+ end
48
+
49
+ def new
50
+ @page = Page.new creator: current_user
51
+ end
52
+
53
+ def reorder
54
+ old_parent_id = @page.parent_id
55
+ old_position = @page.position
56
+ if @page.reorder!(
57
+ parent_id: params[:parent_id],
58
+ position: params[:position]
59
+ )
60
+ @activity = @page.create_activity key: "page.reorder",
61
+ owner: current_user,
62
+ parameters: {
63
+ from_parent_id: old_parent_id,
64
+ old_position: old_position,
65
+ parent_id: params[:parent_id],
66
+ position: params[:position]
67
+ }
68
+ end
69
+
70
+ render json: {}
71
+ end
72
+
73
+ def attach
74
+ @attachment = Attachment.create_from_uploaded_file(params[:file], current_user, attachable: @page)
75
+
76
+ if @attachment.errors.none?
77
+ @activity = @ticket.page key: "ticket.attachment",
78
+ owner: current_user, recipient: @attachment
79
+ end
80
+ end
81
+
82
+ def subpages_dropdown
83
+ render partial: 'subpages_dropdown'
84
+ end
85
+
86
+ protected
87
+ def load_page
88
+ @page = Page.find(params[:id]) if params[:id]
89
+ end
90
+
91
+ private
92
+ def page_params
93
+ params.require(params[:type]).permit(:title, :body)
94
+ end
95
+
96
+ def redcarpet(text)
97
+ markdown = Redcarpet::Markdown.new(
98
+ Redcarpet::Render::HTML,
99
+ no_intra_emphasis: true,
100
+ tables: true,
101
+ fenced_code_blocks: true,
102
+ autolink: true,
103
+ # disable_indented_code_blocks: true,
104
+ strikethrough: true,
105
+ lax_spacing: true,
106
+ space_after_headers: true,
107
+ superscript: true,
108
+ # underline: true,
109
+ highlight: true,
110
+ quote: true,
111
+ footnotes: true,
112
+ )
113
+ markdown.render text
114
+ end
115
+ end
@@ -0,0 +1,37 @@
1
+ class Wiki::SpacesController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ def new
5
+ @space = Space.new creator: current_user
6
+ end
7
+
8
+ def create
9
+ @space = Space.new space_params.merge(creator: current_user)
10
+
11
+ if @space.save
12
+ redirect_to wiki_page_path(@space)
13
+ else
14
+ render :new
15
+ end
16
+ end
17
+
18
+ def space_list
19
+ @page = Page.find params[:id]
20
+ @load_list = []
21
+ if params[:page_id].present?
22
+ @until_page = Page.find params[:page_id]
23
+ @load_list = @until_page.ancestor_ids
24
+ end
25
+ render layout: false
26
+ end
27
+
28
+ def load_till_space
29
+ @page = Page.find params[:page_id]
30
+ end
31
+
32
+ private
33
+ def space_params
34
+ params.require(:space).permit(:title)
35
+ end
36
+ end
37
+
@@ -0,0 +1,20 @@
1
+ module ApplicationHelper
2
+ [:project, :story, :bug, :task].each do |method|
3
+ define_method("#{method}_path") do |*args|
4
+ ticket_path(*args)
5
+ end
6
+
7
+ define_method("#{method.to_s.pluralize}_path") do |*args|
8
+ tickets_path(*args)
9
+ end
10
+ end
11
+
12
+ def ticket_types
13
+ Ticket::ALLOWED_TYPES.each_with_object({}) do |type, hash|
14
+ hash[type] = Ticket.filtered_type_class(type).new(
15
+ creator: current_user,
16
+ parent_id: params[:parent_id]
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,2 @@
1
+ module Wiki::PagesHelper
2
+ end
@@ -0,0 +1,6 @@
1
+ class FakeInput < SimpleForm::Inputs::StringInput
2
+ # This method only create a basic input without reading any value from object
3
+ def input
4
+ template.text_field_tag(attribute_name, nil, input_html_options)
5
+ end
6
+ end
data/app/mailers/.keep ADDED
File without changes
data/app/models/.keep ADDED
File without changes
@@ -0,0 +1,5 @@
1
+ class Assignment < ActiveRecord::Base
2
+ belongs_to :user
3
+ belongs_to :ticket
4
+ belongs_to :assigner, class_name: "User"
5
+ end
@@ -0,0 +1,54 @@
1
+ class Attachment < ActiveRecord::Base
2
+ include Tire::Model::Search
3
+ include Tire::Model::Callbacks
4
+
5
+ # after_save :save_to_git
6
+ belongs_to :attachable, :polymorphic => true
7
+ validates_presence_of :attachable
8
+
9
+ def self.create_from_uploaded_file(file, user, options = {})
10
+ filename = file.original_filename
11
+ attachment = Attachment.create( options.merge(
12
+ filename: filename,
13
+ content_type: file.content_type,
14
+ size: file.size,
15
+ ))
16
+
17
+ if attachment.errors.none?
18
+ attachment.save_to_gollum(
19
+ file, user,
20
+ "uploading file: #{filename}"
21
+ )
22
+ end
23
+
24
+ attachment
25
+ end
26
+
27
+ def file_data
28
+ format = File.extname(filename).gsub(".", "")
29
+ $wiki.file(wiki_dir + "/" + wiki_attachment_data + "." + format).raw_data
30
+ end
31
+
32
+ def save_to_gollum(file, user, message)
33
+ commit = {
34
+ message: message,
35
+ name: user.name,
36
+ email: user.email
37
+ }
38
+
39
+ file_name = file.try(:original_filename) || File.basename(file.path)
40
+ extension = File.extname(file_name).gsub(".", "")
41
+ data_file = file.try(:tempfile) || file
42
+ $wiki.write_page(wiki_attachment_data, extension, data_file, commit, wiki_dir)
43
+ end
44
+
45
+ protected
46
+
47
+ def wiki_attachment_data
48
+ "#{id}-data"
49
+ end
50
+
51
+ def wiki_dir
52
+ "attachments/#{id}"
53
+ end
54
+ end
data/app/models/bug.rb ADDED
@@ -0,0 +1,2 @@
1
+ class Bug < Ticket
2
+ end
@@ -0,0 +1,6 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :user
3
+ belongs_to :ticket
4
+
5
+ validates :body, presence: true
6
+ end
File without changes
@@ -0,0 +1,68 @@
1
+ class Page < ActiveRecord::Base
2
+ include PublicActivity::Common
3
+
4
+ include Tire::Model::Search
5
+ include Tire::Model::Callbacks
6
+
7
+ has_ancestry #touch: true
8
+ acts_as_list scope: [:ancestry]
9
+
10
+ attr_accessor :old_ancestor_ids
11
+
12
+ belongs_to :creator_id
13
+ has_many :attachments, as: :attachable, dependent: :destroy
14
+
15
+ validates_presence_of :creator
16
+ validates_presence_of :title
17
+
18
+ belongs_to :creator, class_name: 'User'
19
+ after_save :touch_ancestry
20
+
21
+ def to_param
22
+ [id, title.parameterize].join("-")
23
+ end
24
+
25
+ def wiki_dir
26
+ "wiki/#{id}"
27
+ end
28
+
29
+ def update_to_gollum(user)
30
+ commit = {
31
+ message: 'no message',
32
+ name: user.name,
33
+ email: user.email
34
+ }
35
+
36
+ body_page = "#{id}-body"
37
+ title_page = "#{id}-title"
38
+
39
+ $wiki.write_page(wiki_dir + "/" + body_page, :textile, body, commit)
40
+ $wiki.write_page(wiki_dir + "/" + title_page, :textile, title, commit)
41
+ end
42
+
43
+ def type
44
+ @type || "Page"
45
+ end
46
+
47
+ def versions
48
+ $wiki.page("#{id}-body", nil, wiki_dir).try(:versions) || []
49
+ end
50
+
51
+ def reorder!(options)
52
+ if options[:parent_id]
53
+ self.old_ancestor_ids = self.ancestor_ids
54
+ self.parent_id = options[:parent_id]
55
+ self.save
56
+ end
57
+ self.insert_at options[:position].to_i
58
+ self.save
59
+ end
60
+
61
+ def touch_ancestry
62
+ self.old_ancestor_ids ||= []
63
+ Page.where(id: (ancestor_ids + old_ancestor_ids).uniq).update_all(updated_at: Time.now)
64
+ end
65
+
66
+ private
67
+
68
+ end
@@ -0,0 +1,2 @@
1
+ class Project < Ticket
2
+ end
@@ -0,0 +1,2 @@
1
+ class Space < Page
2
+ end
@@ -0,0 +1,29 @@
1
+ class Story < Ticket
2
+ has_one :story_detail, foreign_key: "ticket_id", dependent: :destroy
3
+
4
+ validates :who, :what, presence: true
5
+
6
+ after_save do
7
+ story_detail.save if story_detail.changed?
8
+ end
9
+
10
+ [:who, :what, :why].each do |method|
11
+ define_method(method) do |*args|
12
+ return nil unless story_detail
13
+ story_detail.send(method, *args)
14
+ end
15
+
16
+ define_method("#{method}=") do |*args|
17
+ build_story_detail unless story_detail
18
+ story_detail.send("#{method}=", *args)
19
+ end
20
+ end
21
+
22
+ def title
23
+ return super unless who.present? && what.present?
24
+ title = "#{who} wants to #{what}"
25
+ title += ", so: #{why}" if why.present?
26
+
27
+ title
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ class StoryDetail < ActiveRecord::Base
2
+ belongs_to :story, foreign_key: "ticket_id"
3
+ end
@@ -0,0 +1,2 @@
1
+ class Task < Ticket
2
+ end
@@ -0,0 +1,127 @@
1
+ class Ticket < ActiveRecord::Base
2
+ include AASM
3
+ include PublicActivity::Common
4
+
5
+ include Tire::Model::Search
6
+ include Tire::Model::Callbacks
7
+
8
+
9
+
10
+ has_ancestry #touch: true
11
+ acts_as_list scope: [:ancestry]
12
+
13
+ attr_accessor :old_ancestor_ids
14
+
15
+ class InvalidTypeError < StandardError; end
16
+ class UnknownEventError < StandardError; end
17
+
18
+ ALLOWED_TYPES = %w(story task bug)
19
+
20
+ belongs_to :creator, class_name: 'User'
21
+ validates_presence_of :creator
22
+ validates_presence_of :title
23
+
24
+ has_many :comments
25
+ has_many :assignments
26
+ has_many :attachments, as: :attachable, dependent: :destroy
27
+
28
+
29
+ after_save :touch_ancestry
30
+
31
+ ACTIVE_STATES = [:open, :current, :current, :completed]
32
+ scope :active, -> {where(state: ACTIVE_STATES)}
33
+
34
+ ARCHIVED_STATES = [:rejected, :verified]
35
+ scope :archived, -> {where(state: ARCHIVED_STATES)}
36
+
37
+ scope :with_state, ->(state) {where(state: state.to_s)}
38
+
39
+ aasm column: :state do
40
+ state :open, initial: true
41
+ state :current
42
+ state :completed
43
+
44
+ state :rejected
45
+ state :verified
46
+
47
+ event :reopen do
48
+ transitions to: :open, from: [:current, :completed, :rejected, :verified]
49
+ end
50
+
51
+ event :start do
52
+ transitions to: :current, from: :open
53
+ end
54
+
55
+ event :restart do
56
+ transitions to: :current, from: [:verified, :completed]
57
+ end
58
+
59
+ event :complete do
60
+ transitions to: :completed, from: [:open, :current]
61
+ end
62
+
63
+ event :reject do
64
+ transitions to: :rejected, from: [:open, :current]
65
+ end
66
+
67
+ event :verify do
68
+ transitions to: :verified, from: [:current, :completed]
69
+ end
70
+ end
71
+
72
+ def self.filtered_type_class(type)
73
+ raise InvalidTypeError unless ALLOWED_TYPES.include?(type)
74
+ type.classify.constantize
75
+ end
76
+
77
+ def self.ordered
78
+ order("position ASC")
79
+ end
80
+
81
+ def short_title(num_words = 2)
82
+ words = title.split
83
+ short = words[0..num_words].join(" ")
84
+ short += "..." if words.count > num_words
85
+
86
+ short
87
+ end
88
+
89
+
90
+ def assignment_users_hash
91
+ assignments.each_with_object([]) do |assignment, array|
92
+ array << {
93
+ id: assignment.user.id,
94
+ name: assignment.user.display_name,
95
+ }
96
+ end
97
+
98
+ end
99
+
100
+ def assignment_users
101
+ assignments.map{|assignment| [assignment.user.display_name, assignment.user.id]}
102
+ end
103
+
104
+ def tags
105
+ ""
106
+ end
107
+
108
+ def trigger_event!(event)
109
+ raise UnknownEventError unless self.aasm.events.include?(event.to_sym)
110
+ self.send("#{event}!")
111
+ end
112
+
113
+ def reorder!(options)
114
+ if options[:parent_id]
115
+ self.old_ancestor_ids = self.ancestor_ids
116
+ self.parent_id = options[:parent_id]
117
+ self.save
118
+ end
119
+ self.insert_at options[:position].to_i
120
+ self.save
121
+ end
122
+
123
+ def touch_ancestry
124
+ self.old_ancestor_ids ||= []
125
+ Ticket.where(id: (ancestor_ids + old_ancestor_ids).uniq).update_all(updated_at: Time.now)
126
+ end
127
+ end
@@ -0,0 +1,36 @@
1
+ class User < ActiveRecord::Base
2
+ include Tire::Model::Search
3
+ include Tire::Model::Callbacks
4
+
5
+ # Include default devise modules. Others available are:
6
+ # :confirmable, :lockable, :timeoutable and :omniauthable
7
+ devise :database_authenticatable, :registerable,
8
+ :recoverable, :rememberable, :trackable, :validatable
9
+ devise :omniauthable, omniauth_providers: [:google_apps]
10
+
11
+ has_many :tickets, foreign_key: 'creator_id'
12
+ has_many :projects, foreign_key: 'creator_id', class_name: "Project"
13
+
14
+ def self.find_for_open_id(access_token, signed_in_resource = nil)
15
+ data = access_token.info
16
+ name = data["name"]
17
+
18
+ if name.blank?
19
+ name = data["first_name"] + " " + data["last_name"]
20
+ end
21
+
22
+ if user = User.where(email: data["email"]).first
23
+ user
24
+ else
25
+ User.create!(
26
+ name: name,
27
+ email: data["email"],
28
+ password: Devise.friendly_token[0,20]
29
+ )
30
+ end
31
+ end
32
+
33
+ def display_name
34
+ name || username || email
35
+ end
36
+ end
@@ -0,0 +1,2 @@
1
+ class UserVerifier
2
+ end
@@ -0,0 +1,6 @@
1
+ %li.panel.panel-default.list-group-item
2
+ .panel-body
3
+ :markdown
4
+ #{comment.body}
5
+ %small
6
+ #{comment.user.display_name}
@@ -0,0 +1,4 @@
1
+ = simple_form_for comment, remote: true do |f|
2
+ = f.input :ticket_id, as: :hidden
3
+ = f.input :body, placeholder: "add a comment", label: false
4
+ = f.submit "Add Comment", class: 'btn btn-primary'
@@ -0,0 +1,7 @@
1
+ <% if @comment.errors.any? %>
2
+ $("#new_comment").replaceWith('<%=j render 'form', comment: @comment %>')
3
+ <% else %>
4
+ $("#new_comment").replaceWith('<%=j render 'form', comment: Comment.new(ticket_id: params[:comment][:ticket_id]) %>')
5
+ $(".ticket[data-ticket-id=<%= @ticket.id %>] > #activities")
6
+ .prepend('<%=j render 'tickets/activity', ticket: @ticket, activity: @activity %>')
7
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <h2>Resend confirmation instructions</h2>
2
+
3
+ <%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
4
+ <%= devise_error_messages! %>
5
+
6
+ <div><%= f.label :email %><br />
7
+ <%= f.email_field :email, :autofocus => true %></div>
8
+
9
+ <div><%= f.submit "Resend confirmation instructions" %></div>
10
+ <% end %>
11
+
12
+ <%= render "devise/shared/links" %>
@@ -0,0 +1,5 @@
1
+ <p>Welcome <%= @email %>!</p>
2
+
3
+ <p>You can confirm your account email through the link below:</p>
4
+
5
+ <p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>
@@ -0,0 +1,8 @@
1
+ <p>Hello <%= @resource.email %>!</p>
2
+
3
+ <p>Someone has requested a link to change your password. You can do this through the link below.</p>
4
+
5
+ <p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
6
+
7
+ <p>If you didn't request this, please ignore this email.</p>
8
+ <p>Your password won't change until you access the link above and create a new one.</p>
@@ -0,0 +1,7 @@
1
+ <p>Hello <%= @resource.email %>!</p>
2
+
3
+ <p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
4
+
5
+ <p>Click the link below to unlock your account:</p>
6
+
7
+ <p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @token) %></p>
@@ -0,0 +1,16 @@
1
+ <h2>Change your password</h2>
2
+
3
+ <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
4
+ <%= devise_error_messages! %>
5
+ <%= f.hidden_field :reset_password_token %>
6
+
7
+ <div><%= f.label :password, "New password" %><br />
8
+ <%= f.password_field :password, :autofocus => true %></div>
9
+
10
+ <div><%= f.label :password_confirmation, "Confirm new password" %><br />
11
+ <%= f.password_field :password_confirmation %></div>
12
+
13
+ <div><%= f.submit "Change my password" %></div>
14
+ <% end %>
15
+
16
+ <%= render "devise/shared/links" %>
@@ -0,0 +1,12 @@
1
+ <h2>Forgot your password?</h2>
2
+
3
+ <%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| %>
4
+ <%= devise_error_messages! %>
5
+
6
+ <div><%= f.label :email %><br />
7
+ <%= f.email_field :email, :autofocus => true %></div>
8
+
9
+ <div><%= f.submit "Send me reset password instructions" %></div>
10
+ <% end %>
11
+
12
+ <%= render "devise/shared/links" %>
@@ -0,0 +1,29 @@
1
+ <h2>Edit <%= resource_name.to_s.humanize %></h2>
2
+
3
+ <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
4
+ <%= devise_error_messages! %>
5
+
6
+ <div><%= f.label :email %><br />
7
+ <%= f.email_field :email, :autofocus => true %></div>
8
+
9
+ <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
10
+ <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
11
+ <% end %>
12
+
13
+ <div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
14
+ <%= f.password_field :password, :autocomplete => "off" %></div>
15
+
16
+ <div><%= f.label :password_confirmation %><br />
17
+ <%= f.password_field :password_confirmation %></div>
18
+
19
+ <div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
20
+ <%= f.password_field :current_password %></div>
21
+
22
+ <div><%= f.submit "Update" %></div>
23
+ <% end %>
24
+
25
+ <h3>Cancel my account</h3>
26
+
27
+ <p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %></p>
28
+
29
+ <%= link_to "Back", :back %>