tawork 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +16 -0
- data/Gemfile +91 -0
- data/Gemfile.lock +295 -0
- data/MIT-LICENSE +20 -0
- data/Procfile +2 -0
- data/README.md +1 -0
- data/Rakefile +6 -0
- data/app/assets/images/.keep +0 -0
- data/app/assets/javascripts/application.js +31 -0
- data/app/assets/javascripts/backbone/models/.gitkeep +0 -0
- data/app/assets/javascripts/backbone/routers/.gitkeep +0 -0
- data/app/assets/javascripts/backbone/tawork.js.coffee +11 -0
- data/app/assets/javascripts/backbone/templates/.gitkeep +0 -0
- data/app/assets/javascripts/backbone/views/.gitkeep +0 -0
- data/app/assets/javascripts/backbone/views/page.js.coffee +75 -0
- data/app/assets/javascripts/backbone/views/ticket.js.coffee +110 -0
- data/app/assets/javascripts/backbone/views/tree_node_page.js.coffee +16 -0
- data/app/assets/javascripts/backbone/views/tree_node_ticket.js.coffee +14 -0
- data/app/assets/javascripts/wiki/pages.js.coffee +3 -0
- data/app/assets/stylesheets/application.css +22 -0
- data/app/assets/stylesheets/bootstrap_and_overrides.sass +208 -0
- data/app/assets/stylesheets/diff.css +14 -0
- data/app/assets/stylesheets/wiki/pages.css.scss +3 -0
- data/app/controllers/application_controller.rb +15 -0
- data/app/controllers/assignments_controller.rb +30 -0
- data/app/controllers/attachments_controller.rb +10 -0
- data/app/controllers/comments_controller.rb +24 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/home_controller.rb +7 -0
- data/app/controllers/projects_controller.rb +31 -0
- data/app/controllers/search_controller.rb +49 -0
- data/app/controllers/sink_controller.rb +10 -0
- data/app/controllers/tickets_controller.rb +147 -0
- data/app/controllers/users/omniauth_callbacks_controller.rb +23 -0
- data/app/controllers/wiki/pages_controller.rb +115 -0
- data/app/controllers/wiki/spaces_controller.rb +37 -0
- data/app/helpers/application_helper.rb +20 -0
- data/app/helpers/wiki/pages_helper.rb +2 -0
- data/app/inputs/fake_input.rb +6 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/models/assignment.rb +5 -0
- data/app/models/attachment.rb +54 -0
- data/app/models/bug.rb +2 -0
- data/app/models/comment.rb +6 -0
- data/app/models/concerns/.keep +0 -0
- data/app/models/page.rb +68 -0
- data/app/models/project.rb +2 -0
- data/app/models/space.rb +2 -0
- data/app/models/story.rb +29 -0
- data/app/models/story_detail.rb +3 -0
- data/app/models/task.rb +2 -0
- data/app/models/ticket.rb +127 -0
- data/app/models/user.rb +36 -0
- data/app/models/user_verifier.rb +2 -0
- data/app/views/comments/_comment.html.haml +6 -0
- data/app/views/comments/_form.html.haml +4 -0
- data/app/views/comments/create.js.coffee +7 -0
- data/app/views/devise/confirmations/new.html.erb +12 -0
- data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/devise/passwords/edit.html.erb +16 -0
- data/app/views/devise/passwords/new.html.erb +12 -0
- data/app/views/devise/registrations/edit.html.erb +29 -0
- data/app/views/devise/registrations/new.html.erb +18 -0
- data/app/views/devise/sessions/new.html.erb +17 -0
- data/app/views/devise/shared/_links.erb +25 -0
- data/app/views/devise/unlocks/new.html.erb +12 -0
- data/app/views/home/index.html.haml +4 -0
- data/app/views/layouts/_activity_wrapper.html.haml +17 -0
- data/app/views/layouts/_nav_header.html.haml +26 -0
- data/app/views/layouts/_spaces.html.haml +34 -0
- data/app/views/layouts/application.html.haml +39 -0
- data/app/views/layouts/minimal.html.haml +22 -0
- data/app/views/projects/index.html.haml +16 -0
- data/app/views/projects/new.html.haml +6 -0
- data/app/views/public_activity/ticket/_assignment.html.haml +14 -0
- data/app/views/public_activity/ticket/_create_comment.html.haml +10 -0
- data/app/views/public_activity/ticket/_created.html.haml +3 -0
- data/app/views/public_activity/ticket/_reorder.html.haml +2 -0
- data/app/views/public_activity/ticket/_state_change.html.haml +2 -0
- data/app/views/public_activity/ticket/_update_details.html.haml +13 -0
- data/app/views/tickets/_activity.html.haml +3 -0
- data/app/views/tickets/_breadcrumb.html.haml +7 -0
- data/app/views/tickets/_bug_form.html.haml +1 -0
- data/app/views/tickets/_events_dropdown.html.haml +4 -0
- data/app/views/tickets/_form.html.haml +28 -0
- data/app/views/tickets/_project_form.html.haml +1 -0
- data/app/views/tickets/_story_form.html.haml +15 -0
- data/app/views/tickets/_task_form.html.haml +8 -0
- data/app/views/tickets/_tickets_listing.html.haml +5 -0
- data/app/views/tickets/_title_and_description.html.haml +8 -0
- data/app/views/tickets/_tree_node.html.haml +28 -0
- data/app/views/tickets/assignment.js.coffee +3 -0
- data/app/views/tickets/create.js.coffee +7 -0
- data/app/views/tickets/new.html.haml +1 -0
- data/app/views/tickets/show.html.haml +64 -0
- data/app/views/tickets/trigger_event.js.coffee +12 -0
- data/app/views/tickets/update.js.coffee +12 -0
- data/app/views/wiki/pages/_attachment.html.haml +5 -0
- data/app/views/wiki/pages/_attachments.html.haml +22 -0
- data/app/views/wiki/pages/_breadcrumb.html.haml +9 -0
- data/app/views/wiki/pages/_child_menu.html.haml +9 -0
- data/app/views/wiki/pages/_display.html.haml +138 -0
- data/app/views/wiki/pages/_page_header.html.haml +13 -0
- data/app/views/wiki/pages/_subpages_dropdown.html.haml +6 -0
- data/app/views/wiki/pages/_subtree.html.haml +7 -0
- data/app/views/wiki/pages/_tree_node.html.haml +21 -0
- data/app/views/wiki/pages/attach.js.coffee +2 -0
- data/app/views/wiki/pages/combined.html.haml +8 -0
- data/app/views/wiki/pages/create.js.coffee +5 -0
- data/app/views/wiki/pages/edit.html.haml +2 -0
- data/app/views/wiki/pages/history.html.haml +13 -0
- data/app/views/wiki/pages/index.html.haml +2 -0
- data/app/views/wiki/pages/new.html.haml +13 -0
- data/app/views/wiki/pages/show.html.haml +14 -0
- data/app/views/wiki/pages/update.html.haml +2 -0
- data/app/views/wiki/spaces/_page_list_item.html.haml +11 -0
- data/app/views/wiki/spaces/_space_list.html.haml +4 -0
- data/app/views/wiki/spaces/new.html.haml +5 -0
- data/app/views/wiki/spaces/space_list.html.haml +1 -0
- data/bin/bundle +3 -0
- data/bin/rails +4 -0
- data/bin/rake +4 -0
- data/config/application.rb +30 -0
- data/config/boot.rb +4 -0
- data/config/database.yml +39 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +35 -0
- data/config/environments/production.rb +80 -0
- data/config/environments/test.rb +36 -0
- data/config/initializers/backtrace_silencers.rb +7 -0
- data/config/initializers/config.rb +4 -0
- data/config/initializers/devise.rb +257 -0
- data/config/initializers/elasticsearch.rb +9 -0
- data/config/initializers/filter_parameter_logging.rb +4 -0
- data/config/initializers/gollum.rb +31 -0
- data/config/initializers/haml_gfm.rb +66 -0
- data/config/initializers/inflections.rb +16 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/secret_token.rb +12 -0
- data/config/initializers/session_store.rb +3 -0
- data/config/initializers/simple_form.rb +145 -0
- data/config/initializers/simple_form_bootstrap.rb +73 -0
- data/config/initializers/wrap_parameters.rb +14 -0
- data/config/locales/devise.en.yml +59 -0
- data/config/locales/en.yml +23 -0
- data/config/locales/simple_form.en.yml +26 -0
- data/config/routes.rb +101 -0
- data/config/tinymce.yml +10 -0
- data/config.ru +4 -0
- data/db/migrate/20131209041251_create_tickets.rb +13 -0
- data/db/migrate/20131210041050_devise_create_users.rb +42 -0
- data/db/migrate/20131210043014_add_username_to_users.rb +5 -0
- data/db/migrate/20131210045348_add_creator_to_ticket.rb +5 -0
- data/db/migrate/20131211034104_create_comments.rb +11 -0
- data/db/migrate/20131212073014_create_assignments.rb +12 -0
- data/db/migrate/20131215220825_add_position_to_ticket.rb +5 -0
- data/db/migrate/20131216044331_create_story_details.rb +12 -0
- data/db/migrate/20131218060557_create_activities.rb +23 -0
- data/db/migrate/20140109235844_create_pages.rb +14 -0
- data/db/migrate/20140112004346_create_attachments.rb +13 -0
- data/db/migrate/20140120030547_add_name_to_users.rb +5 -0
- data/db/schema.rb +125 -0
- data/db/seeds.rb +7 -0
- data/init.rb +1 -0
- data/lib/assets/.keep +0 -0
- data/lib/tasks/.keep +0 -0
- data/lib/tawork/engine.rb +13 -0
- data/lib/tawork/version.rb +3 -0
- data/lib/tawork.rb +4 -0
- data/lib/templates/haml/scaffold/_form.html.haml +10 -0
- data/lib/ticket_assignment.rb +25 -0
- data/log/.keep +0 -0
- data/public/401.html +57 -0
- data/public/404.html +58 -0
- data/public/422.html +58 -0
- data/public/500.html +57 -0
- data/public/favicon.ico +0 -0
- data/public/robots.txt +5 -0
- data/tags +279 -0
- data/tawork.gemspec +24 -0
- data/vendor/.DS_Store +0 -0
- data/vendor/assets/.DS_Store +0 -0
- data/vendor/assets/javascripts/.keep +0 -0
- data/vendor/assets/javascripts/bootstrap-tagsinput.js +503 -0
- data/vendor/assets/javascripts/bootstrap-tree.js +15 -0
- data/vendor/assets/javascripts/bootstrap-typeahead.js +335 -0
- data/vendor/assets/javascripts/hallo.js +2949 -0
- data/vendor/assets/javascripts/highlight.pack.js +1 -0
- data/vendor/assets/javascripts/jquery.autosize.js +250 -0
- data/vendor/assets/javascripts/jquery.mjs.nestedSortable.js +613 -0
- data/vendor/assets/javascripts/rangy-core.js +94 -0
- data/vendor/assets/javascripts/tinymce/mention/plugin.js +358 -0
- data/vendor/assets/stylesheets/.keep +0 -0
- data/vendor/assets/stylesheets/bootflat-extensions.css +356 -0
- data/vendor/assets/stylesheets/bootflat-square.css +69 -0
- data/vendor/assets/stylesheets/bootflat.css +1556 -0
- data/vendor/assets/stylesheets/bootstrap-tagsinput.css +45 -0
- data/vendor/assets/stylesheets/bootstrap-tree.sass +82 -0
- data/vendor/assets/stylesheets/highlight/arta.css +160 -0
- data/vendor/assets/stylesheets/highlight/ascetic.css +50 -0
- data/vendor/assets/stylesheets/highlight/brown_paper.css +105 -0
- data/vendor/assets/stylesheets/highlight/brown_papersq.png +0 -0
- data/vendor/assets/stylesheets/highlight/dark.css +105 -0
- data/vendor/assets/stylesheets/highlight/default.css +153 -0
- data/vendor/assets/stylesheets/highlight/docco.css +132 -0
- data/vendor/assets/stylesheets/highlight/far.css +113 -0
- data/vendor/assets/stylesheets/highlight/foundation.css +133 -0
- data/vendor/assets/stylesheets/highlight/github.css +130 -0
- data/vendor/assets/stylesheets/highlight/googlecode.css +146 -0
- data/vendor/assets/stylesheets/highlight/idea.css +122 -0
- data/vendor/assets/stylesheets/highlight/ir_black.css +105 -0
- data/vendor/assets/stylesheets/highlight/magula.css +123 -0
- data/vendor/assets/stylesheets/highlight/mono-blue.css +62 -0
- data/vendor/assets/stylesheets/highlight/monokai.css +127 -0
- data/vendor/assets/stylesheets/highlight/monokai_sublime.css +102 -0
- data/vendor/assets/stylesheets/highlight/obsidian.css +154 -0
- data/vendor/assets/stylesheets/highlight/pojoaque.css +105 -0
- data/vendor/assets/stylesheets/highlight/pojoaque.jpg +0 -0
- data/vendor/assets/stylesheets/highlight/railscasts.css +182 -0
- data/vendor/assets/stylesheets/highlight/rainbow.css +115 -0
- data/vendor/assets/stylesheets/highlight/school_book.css +113 -0
- data/vendor/assets/stylesheets/highlight/school_book.png +0 -0
- data/vendor/assets/stylesheets/highlight/solarized_dark.css +92 -0
- data/vendor/assets/stylesheets/highlight/solarized_light.css +92 -0
- data/vendor/assets/stylesheets/highlight/sunburst.css +160 -0
- data/vendor/assets/stylesheets/highlight/tomorrow-night-blue.css +52 -0
- data/vendor/assets/stylesheets/highlight/tomorrow-night-bright.css +51 -0
- data/vendor/assets/stylesheets/highlight/tomorrow-night-eighties.css +51 -0
- data/vendor/assets/stylesheets/highlight/tomorrow-night.css +52 -0
- data/vendor/assets/stylesheets/highlight/tomorrow.css +49 -0
- data/vendor/assets/stylesheets/highlight/vs.css +89 -0
- data/vendor/assets/stylesheets/highlight/xcode.css +157 -0
- data/vendor/assets/stylesheets/highlight/zenburn.css +117 -0
- 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
|
data/app/mailers/.keep
ADDED
File without changes
|
data/app/models/.keep
ADDED
File without changes
|
@@ -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
File without changes
|
data/app/models/page.rb
ADDED
@@ -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
|
data/app/models/space.rb
ADDED
data/app/models/story.rb
ADDED
@@ -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
|
data/app/models/task.rb
ADDED
@@ -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
|
data/app/models/user.rb
ADDED
@@ -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,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,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 %>
|