Commit 387bca94f6e617fe5e910eed032900145de4b11b

Authored by Marcin Ciunelis
1 parent 3db48ca3
Exists in master and in 1 other branch production

rename ErrsController to ProblemsController

Showing 44 changed files with 1016 additions and 1017 deletions   Show diff stats
app/controllers/comments_controller.rb
... ... @@ -11,7 +11,7 @@ class CommentsController < ApplicationController
11 11 else
12 12 flash[:error] = "I'm sorry, your comment was blank! Try again?"
13 13 end
14   - redirect_to app_err_path(@app, @problem)
  14 + redirect_to app_problem_path(@app, @problem)
15 15 end
16 16  
17 17 def destroy
... ... @@ -21,7 +21,7 @@ class CommentsController < ApplicationController
21 21 else
22 22 flash[:error] = "Sorry, I couldn't delete your comment for some reason. I hope you don't have any sensitive information in there!"
23 23 end
24   - redirect_to app_err_path(@app, @problem)
  24 + redirect_to app_problem_path(@app, @problem)
25 25 end
26 26  
27 27 protected
... ... @@ -34,7 +34,7 @@ class CommentsController < ApplicationController
34 34 end
35 35  
36 36 def find_problem
37   - @problem = @app.problems.find(params[:err_id])
  37 + @problem = @app.problems.find(params[:problem_id])
38 38 end
39 39 end
40 40  
... ...
app/controllers/errs_controller.rb
... ... @@ -1,157 +0,0 @@
1   -class ErrsController < ApplicationController
2   - include ActionView::Helpers::TextHelper
3   -
4   - before_filter :find_app, :except => [:index, :all, :destroy_several, :resolve_several, :unresolve_several, :merge_several, :unmerge_several]
5   - before_filter :find_problem, :except => [:index, :all, :destroy_several, :resolve_several, :unresolve_several, :merge_several, :unmerge_several]
6   - before_filter :find_selected_problems, :only => [:destroy_several, :resolve_several, :unresolve_several, :merge_several, :unmerge_several]
7   - before_filter :set_sorting_params, :only => [:index, :all]
8   - before_filter :set_tracker_params, :only => [:create_issue]
9   -
10   - def index
11   - app_scope = current_user.admin? ? App.all : current_user.apps
12   -
13   - @problems = Problem.for_apps(app_scope).in_env(params[:environment]).unresolved.ordered_by(@sort, @order)
14   - @selected_problems = params[:problems] || []
15   - respond_to do |format|
16   - format.html do
17   - @problems = @problems.page(params[:page]).per(current_user.per_page)
18   - end
19   - format.atom
20   - end
21   - end
22   -
23   - def all
24   - app_scope = current_user.admin? ? App.all : current_user.apps
25   - @problems = Problem.for_apps(app_scope).ordered_by(@sort, @order).page(params[:page]).per(current_user.per_page)
26   - @selected_problems = params[:problems] || []
27   - end
28   -
29   - def show
30   - @notices = @problem.notices.reverse_ordered.page(params[:notice]).per(1)
31   - @notice = @notices.first
32   - @comment = Comment.new
33   - if request.headers['X-PJAX']
34   - params["_pjax"] = nil
35   - render :layout => false
36   - end
37   - end
38   -
39   - def create_issue
40   - # Create an issue on GitHub using user's github token
41   - if params[:tracker] == 'user_github'
42   - if !@app.github_repo?
43   - flash[:error] = "This app doesn't have a GitHub repo set up."
44   - elsif !current_user.github_account?
45   - flash[:error] = "You haven't linked your Github account."
46   - else
47   - @tracker = GithubIssuesTracker.new(
48   - :app => @app,
49   - :username => current_user.github_login,
50   - :oauth_token => current_user.github_oauth_token
51   - )
52   - end
53   -
54   - # Or, create an issue using the App's issue tracker
55   - elsif @app.issue_tracker_configured?
56   - @tracker = @app.issue_tracker
57   -
58   - # Otherwise, display error about missing tracker configuration.
59   - else
60   - flash[:error] = "This app has no issue tracker setup."
61   - end
62   -
63   - if flash[:error].blank? && @tracker
64   - begin
65   - @tracker.create_issue @problem, current_user
66   - rescue Exception => ex
67   - Rails.logger.error "Error during issue creation: " << ex.message
68   - flash[:error] = "There was an error during issue creation: #{ex.message}"
69   - end
70   - end
71   -
72   - redirect_to app_err_path(@app, @problem)
73   - end
74   -
75   - def unlink_issue
76   - @problem.update_attribute :issue_link, nil
77   - redirect_to app_err_path(@app, @problem)
78   - end
79   -
80   - def resolve
81   - @problem.resolve!
82   - flash[:success] = 'Great news everyone! The err has been resolved.'
83   - redirect_to :back
84   - rescue ActionController::RedirectBackError
85   - redirect_to app_path(@app)
86   - end
87   -
88   - def resolve_several
89   - @selected_problems.each(&:resolve!)
90   - flash[:success] = "Great news everyone! #{pluralize(@selected_problems.count, 'err has', 'errs have')} been resolved."
91   - redirect_to :back
92   - end
93   -
94   - def unresolve_several
95   - @selected_problems.each(&:unresolve!)
96   - flash[:success] = "#{pluralize(@selected_problems.count, 'err has', 'errs have')} been unresolved."
97   - redirect_to :back
98   - end
99   -
100   - def merge_several
101   - if @selected_problems.length < 2
102   - flash[:notice] = "You must select at least two errors to merge"
103   - else
104   - @merged_problem = Problem.merge!(@selected_problems)
105   - flash[:notice] = "#{@selected_problems.count} errors have been merged."
106   - end
107   - redirect_to :back
108   - end
109   -
110   - def unmerge_several
111   - all = @selected_problems.map(&:unmerge!).flatten
112   - flash[:success] = "#{pluralize(all.length, 'err has', 'errs have')} been unmerged."
113   - redirect_to :back
114   - end
115   -
116   - def destroy_several
117   - nb_problem_destroy = ProblemDestroy.execute(@selected_problems)
118   - flash[:notice] = "#{pluralize(nb_problem_destroy, 'err has', 'errs have')} been deleted."
119   - redirect_to :back
120   - end
121   -
122   - protected
123   - def find_app
124   - @app = App.find(params[:app_id])
125   -
126   - # Mongoid Bug: could not chain: current_user.apps.find_by_id!
127   - # apparently finding by 'watchers.email' and 'id' is broken
128   - raise(Mongoid::Errors::DocumentNotFound.new(App,@app.id)) unless current_user.admin? || current_user.watching?(@app)
129   - end
130   -
131   - def find_problem
132   - @problem = @app.problems.find(params[:id])
133   - end
134   -
135   - def set_tracker_params
136   - IssueTracker.default_url_options[:host] = request.host
137   - IssueTracker.default_url_options[:port] = request.port
138   - IssueTracker.default_url_options[:protocol] = request.scheme
139   - end
140   -
141   - def find_selected_problems
142   - err_ids = (params[:problems] || []).compact
143   - if err_ids.empty?
144   - flash[:notice] = "You have not selected any errors"
145   - redirect_to :back
146   - else
147   - @selected_problems = Array(Problem.find(err_ids))
148   - end
149   - end
150   -
151   - def set_sorting_params
152   - @sort = params[:sort]
153   - @sort = "last_notice_at" unless %w{app message last_notice_at last_deploy_at count}.member?(@sort)
154   - @order = params[:order] || "desc"
155   - end
156   -end
157   -
app/controllers/notices_controller.rb
... ... @@ -15,6 +15,6 @@ class NoticesController &lt; ApplicationController
15 15 # Redirects a notice to the problem page. Useful when using User Information at Airbrake gem.
16 16 def locate
17 17 problem = Notice.find(params[:id]).problem
18   - redirect_to app_err_path(problem.app, problem)
  18 + redirect_to app_problem_path(problem.app, problem)
19 19 end
20 20 end
... ...
app/controllers/problems_controller.rb 0 → 100644
... ... @@ -0,0 +1,157 @@
  1 +class ProblemsController < ApplicationController
  2 + include ActionView::Helpers::TextHelper
  3 +
  4 + before_filter :find_app, :except => [:index, :all, :destroy_several, :resolve_several, :unresolve_several, :merge_several, :unmerge_several]
  5 + before_filter :find_problem, :except => [:index, :all, :destroy_several, :resolve_several, :unresolve_several, :merge_several, :unmerge_several]
  6 + before_filter :find_selected_problems, :only => [:destroy_several, :resolve_several, :unresolve_several, :merge_several, :unmerge_several]
  7 + before_filter :set_sorting_params, :only => [:index, :all]
  8 + before_filter :set_tracker_params, :only => [:create_issue]
  9 +
  10 + def index
  11 + app_scope = current_user.admin? ? App.all : current_user.apps
  12 +
  13 + @problems = Problem.for_apps(app_scope).in_env(params[:environment]).unresolved.ordered_by(@sort, @order)
  14 + @selected_problems = params[:problems] || []
  15 + respond_to do |format|
  16 + format.html do
  17 + @problems = @problems.page(params[:page]).per(current_user.per_page)
  18 + end
  19 + format.atom
  20 + end
  21 + end
  22 +
  23 + def all
  24 + app_scope = current_user.admin? ? App.all : current_user.apps
  25 + @problems = Problem.for_apps(app_scope).ordered_by(@sort, @order).page(params[:page]).per(current_user.per_page)
  26 + @selected_problems = params[:problems] || []
  27 + end
  28 +
  29 + def show
  30 + @notices = @problem.notices.reverse_ordered.page(params[:notice]).per(1)
  31 + @notice = @notices.first
  32 + @comment = Comment.new
  33 + if request.headers['X-PJAX']
  34 + params["_pjax"] = nil
  35 + render :layout => false
  36 + end
  37 + end
  38 +
  39 + def create_issue
  40 + # Create an issue on GitHub using user's github token
  41 + if params[:tracker] == 'user_github'
  42 + if !@app.github_repo?
  43 + flash[:error] = "This app doesn't have a GitHub repo set up."
  44 + elsif !current_user.github_account?
  45 + flash[:error] = "You haven't linked your Github account."
  46 + else
  47 + @tracker = GithubIssuesTracker.new(
  48 + :app => @app,
  49 + :username => current_user.github_login,
  50 + :oauth_token => current_user.github_oauth_token
  51 + )
  52 + end
  53 +
  54 + # Or, create an issue using the App's issue tracker
  55 + elsif @app.issue_tracker_configured?
  56 + @tracker = @app.issue_tracker
  57 +
  58 + # Otherwise, display error about missing tracker configuration.
  59 + else
  60 + flash[:error] = "This app has no issue tracker setup."
  61 + end
  62 +
  63 + if flash[:error].blank? && @tracker
  64 + begin
  65 + @tracker.create_issue @problem, current_user
  66 + rescue Exception => ex
  67 + Rails.logger.error "Error during issue creation: " << ex.message
  68 + flash[:error] = "There was an error during issue creation: #{ex.message}"
  69 + end
  70 + end
  71 +
  72 + redirect_to app_problem_path(@app, @problem)
  73 + end
  74 +
  75 + def unlink_issue
  76 + @problem.update_attribute :issue_link, nil
  77 + redirect_to app_problem_path(@app, @problem)
  78 + end
  79 +
  80 + def resolve
  81 + @problem.resolve!
  82 + flash[:success] = 'Great news everyone! The err has been resolved.'
  83 + redirect_to :back
  84 + rescue ActionController::RedirectBackError
  85 + redirect_to app_path(@app)
  86 + end
  87 +
  88 + def resolve_several
  89 + @selected_problems.each(&:resolve!)
  90 + flash[:success] = "Great news everyone! #{pluralize(@selected_problems.count, 'err has', 'errs have')} been resolved."
  91 + redirect_to :back
  92 + end
  93 +
  94 + def unresolve_several
  95 + @selected_problems.each(&:unresolve!)
  96 + flash[:success] = "#{pluralize(@selected_problems.count, 'err has', 'errs have')} been unresolved."
  97 + redirect_to :back
  98 + end
  99 +
  100 + def merge_several
  101 + if @selected_problems.length < 2
  102 + flash[:notice] = "You must select at least two errors to merge"
  103 + else
  104 + @merged_problem = Problem.merge!(@selected_problems)
  105 + flash[:notice] = "#{@selected_problems.count} errors have been merged."
  106 + end
  107 + redirect_to :back
  108 + end
  109 +
  110 + def unmerge_several
  111 + all = @selected_problems.map(&:unmerge!).flatten
  112 + flash[:success] = "#{pluralize(all.length, 'err has', 'errs have')} been unmerged."
  113 + redirect_to :back
  114 + end
  115 +
  116 + def destroy_several
  117 + nb_problem_destroy = ProblemDestroy.execute(@selected_problems)
  118 + flash[:notice] = "#{pluralize(nb_problem_destroy, 'err has', 'errs have')} been deleted."
  119 + redirect_to :back
  120 + end
  121 +
  122 + protected
  123 + def find_app
  124 + @app = App.find(params[:app_id])
  125 +
  126 + # Mongoid Bug: could not chain: current_user.apps.find_by_id!
  127 + # apparently finding by 'watchers.email' and 'id' is broken
  128 + raise(Mongoid::Errors::DocumentNotFound.new(App,@app.id)) unless current_user.admin? || current_user.watching?(@app)
  129 + end
  130 +
  131 + def find_problem
  132 + @problem = @app.problems.find(params[:id])
  133 + end
  134 +
  135 + def set_tracker_params
  136 + IssueTracker.default_url_options[:host] = request.host
  137 + IssueTracker.default_url_options[:port] = request.port
  138 + IssueTracker.default_url_options[:protocol] = request.scheme
  139 + end
  140 +
  141 + def find_selected_problems
  142 + err_ids = (params[:problems] || []).compact
  143 + if err_ids.empty?
  144 + flash[:notice] = "You have not selected any errors"
  145 + redirect_to :back
  146 + else
  147 + @selected_problems = Array(Problem.find(err_ids))
  148 + end
  149 + end
  150 +
  151 + def set_sorting_params
  152 + @sort = params[:sort]
  153 + @sort = "last_notice_at" unless %w{app message last_notice_at last_deploy_at count}.member?(@sort)
  154 + @order = params[:order] || "desc"
  155 + end
  156 +end
  157 +
... ...
app/helpers/application_helper.rb
... ... @@ -13,7 +13,7 @@ module ApplicationHelper
13 13 event.dtend = notice.created_at.utc + 60.minutes
14 14 event.organizer = notice.server_environment && notice.server_environment["hostname"]
15 15 event.location = notice.server_environment && notice.server_environment["project-root"]
16   - event.url = app_err_url(:app_id => notice.problem.app.id, :id => notice.problem)
  16 + event.url = app_problem_url(:app_id => notice.problem.app.id, :id => notice.problem)
17 17 end
18 18 end
19 19 end.to_s
... ... @@ -58,11 +58,11 @@ module ApplicationHelper
58 58 percent = 100.0 / total.to_f
59 59 rows = tallies.map {|value, count| [(count.to_f * percent), value]} \
60 60 .sort {|a, b| a[0] <=> b[0]}
61   - render "errs/tally_table", :rows => rows
  61 + render "problems/tally_table", :rows => rows
62 62 end
63 63  
64 64 def head(collection)
65   - collection.first(head_size)
  65 + collection.first(head_size)
66 66 end
67 67  
68 68 def tail(collection)
... ...
app/helpers/errs_helper.rb
... ... @@ -1,27 +0,0 @@
1   -module ErrsHelper
2   - def err_confirm
3   - Errbit::Config.confirm_resolve_err === false ? nil : 'Seriously?'
4   - end
5   -
6   - def truncated_err_message(problem)
7   - unless (msg = problem.message).blank?
8   - # Truncate & insert invisible chars so that firefox can emulate 'word-wrap: break-word' CSS rule
9   - truncate(msg, :length => 300).scan(/.{1,5}/).map { |s| h(s) }.join("&#8203;").html_safe
10   - end
11   - end
12   -
13   - def gravatar_tag(email, options = {})
14   - image_tag gravatar_url(email, options), :alt => email, :class => 'gravatar'
15   - end
16   -
17   - def gravatar_url(email, options = {})
18   - default_options = {
19   - :d => Errbit::Config.gravatar_default,
20   - }
21   - options.reverse_merge! default_options
22   - params = options.extract!(:s, :d).delete_if { |k, v| v.blank? }
23   - email_hash = Digest::MD5.hexdigest(email)
24   - "http://www.gravatar.com/avatar/#{email_hash}?#{params.to_query}"
25   - end
26   -end
27   -
app/helpers/problems_helper.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +module ProblemsHelper
  2 + def problem_confirm
  3 + Errbit::Config.confirm_resolve_err === false ? nil : 'Seriously?'
  4 + end
  5 +
  6 + def truncated_problem_message(problem)
  7 + unless (msg = problem.message).blank?
  8 + # Truncate & insert invisible chars so that firefox can emulate 'word-wrap: break-word' CSS rule
  9 + truncate(msg, :length => 300).scan(/.{1,5}/).map { |s| h(s) }.join("&#8203;").html_safe
  10 + end
  11 + end
  12 +
  13 + def gravatar_tag(email, options = {})
  14 + image_tag gravatar_url(email, options), :alt => email, :class => 'gravatar'
  15 + end
  16 +
  17 + def gravatar_url(email, options = {})
  18 + default_options = {
  19 + :d => Errbit::Config.gravatar_default,
  20 + }
  21 + options.reverse_merge! default_options
  22 + params = options.extract!(:s, :d).delete_if { |k, v| v.blank? }
  23 + email_hash = Digest::MD5.hexdigest(email)
  24 + "http://www.gravatar.com/avatar/#{email_hash}?#{params.to_query}"
  25 + end
  26 +end
  27 +
... ...
app/views/apps/show.atom.builder
1 1 atom_feed do |feed|
2 2 feed.title("Errbit notices for #{h @app.name} at #{root_url}")
3   - render "errs/list", :feed => feed
  3 + render "problems/list", :feed => feed
4 4 end
... ...
app/views/apps/show.html.haml
... ... @@ -83,7 +83,7 @@
83 83  
84 84 - if @app.problems.any?
85 85 %h3.clear Errors
86   - = render 'errs/table', :errs => @problems
  86 + = render 'problems/table', :problems => @problems
87 87 - else
88 88 %h3.clear No errs have been caught yet, make sure you setup your app
89 89 = render 'configuration_instructions', :app => @app
... ...
app/views/errs/_issue_tracker_links.html.haml
... ... @@ -1,15 +0,0 @@
1   -- if @app.issue_tracker_configured? || current_user.github_account?
2   - - if @problem.issue_link.present?
3   - %span= link_to 'go to issue', @problem.issue_link, :class => "#{@problem.issue_type}_goto goto-issue"
4   - = link_to 'unlink issue', unlink_issue_app_err_path(@app, @problem), :method => :delete, :data => { :confirm => "Unlink err issues?" }, :class => "unlink-issue"
5   - - elsif @problem.issue_link == "pending"
6   - %span.disabled= link_to 'creating...', '#', :class => "#{@problem.issue_type}_inactive create-issue"
7   - = link_to 'retry', create_issue_app_err_path(@app, @problem), :method => :post
8   - - else
9   - - if @app.github_repo?
10   - - if current_user.can_create_github_issues?
11   - %span= link_to 'create issue', create_issue_app_err_path(@app, @problem, :tracker => 'user_github'), :method => :post, :class => "github_create create-issue"
12   - - elsif @app.issue_tracker_configured? && @app.issue_tracker.is_a?(GithubIssuesTracker)
13   - %span= link_to 'create issue', create_issue_app_err_path(@app, @problem), :method => :post, :class => "github_create create-issue"
14   - - if @app.issue_tracker_configured? && !@app.issue_tracker.is_a?(GithubIssuesTracker)
15   - %span= link_to 'create issue', create_issue_app_err_path(@app, @problem), :method => :post, :class => "#{@app.issue_tracker.label}_create create-issue"
app/views/errs/_list.atom.builder
... ... @@ -1,15 +0,0 @@
1   -feed.updated(@problems.first.try(:created_at) || Time.now)
2   -
3   -for problem in @problems
4   - notice = problem.notices.first
5   -
6   - feed.entry(problem, :url => app_err_url(problem.app, problem)) do |entry|
7   - entry.title "[#{ problem.where }] #{problem.message.to_s.truncate(27)}"
8   - entry.author do |author|
9   - author.name "#{ problem.app.name } [#{ problem.environment }]"
10   - end
11   - if notice
12   - entry.summary(notice_atom_summary(notice), :type => "html")
13   - end
14   - end
15   -end
app/views/errs/_table.html.haml
... ... @@ -1,56 +0,0 @@
1   -- any_issue_links = errs.any?{|e| e.issue_link.present? && e.issue_link != 'pending' }
2   -=form_tag do
3   - %table.errs.selectable
4   - %thead
5   - %tr
6   - %th= check_box_tag "toggle_problems_checkboxes"
7   - %th= link_for_sort "App"
8   - %th= link_for_sort "What &amp; Where".html_safe, "message"
9   - %th= link_for_sort "Latest", "last_notice_at"
10   - %th= link_for_sort "Deploy", "last_deploy_at"
11   - %th= link_for_sort "Count"
12   - - if any_issue_links
13   - %th Issue
14   - %th Resolve
15   - %tbody
16   - - errs.each do |problem|
17   - %tr{:class => problem.resolved? ? 'resolved' : 'unresolved'}
18   - %td.select
19   - = check_box_tag "problems[]", problem.id, @selected_problems.member?(problem.id.to_s)
20   - %td.app
21   - = link_to problem.app.name, app_path(problem.app)
22   - - if current_page?(:controller => 'errs')
23   - %span.environment= link_to problem.environment, errs_path(:environment => problem.environment)
24   - - else
25   - %span.environment= link_to problem.environment, app_path(problem.app, :environment => problem.environment)
26   - %td.message
27   - = link_to truncated_err_message(problem), app_err_path(problem.app, problem)
28   - %em= problem.where
29   - - if problem.comments_count > 0
30   - - comment = problem.comments.last
31   - %br
32   - .inline_comment
33   - - if comment.user
34   - %em.commenter= (Errbit::Config.user_has_username ? comment.user.username : comment.user.email).to_s << ":"
35   - %em= truncate(comment.body, :length => 100, :separator => ' ')
36   - %td.latest #{time_ago_in_words(problem.last_notice_at)} ago
37   - %td.deploy= problem.last_deploy_at ? problem.last_deploy_at.to_s(:micro) : 'n/a'
38   - %td.count= link_to problem.notices_count, app_err_path(problem.app, problem)
39   - - if any_issue_links
40   - %td.issue_link
41   - - if problem.app.issue_tracker_configured? && problem.issue_link.present? && problem.issue_link != 'pending'
42   - = link_to image_tag("#{problem.issue_type}_goto.png"), problem.issue_link, :target => "_blank"
43   - %td.resolve= link_to image_tag("thumbs-up.png"), resolve_app_err_path(problem.app, problem), :title => "Resolve", :method => :put, :data => { :confirm => err_confirm }, :class => 'resolve' if problem.unresolved?
44   - - if errs.none?
45   - %tr
46   - %td{:colspan => (any_issue_links ? 8 : 7)}
47   - %em No errs here
48   - = paginate errs
49   - .tab-bar
50   - %ul
51   - %li= submit_tag 'Merge', :id => 'merge_errs', :class => 'button', 'data-action' => merge_several_errs_path
52   - %li= submit_tag 'Unmerge', :id => 'unmerge_errs', :class => 'button', 'data-action' => unmerge_several_errs_path
53   - %li= submit_tag 'Resolve', :id => 'resolve_errs', :class => 'button', 'data-action' => resolve_several_errs_path
54   - %li= submit_tag 'Unresolve', :id => 'unresolve_errs', :class => 'button', 'data-action' => unresolve_several_errs_path
55   - %li= submit_tag 'Delete', :id => 'delete_errs', :class => 'button', 'data-action' => destroy_several_errs_path
56   -
app/views/errs/_tally_table.html.haml
... ... @@ -1,18 +0,0 @@
1   -.head_and_tail
2   - %table.tally.head
3   - %tbody
4   - - head(rows).each do |row|
5   - %tr
6   - %td.percent= number_to_percentage(row[0], :precision => 1)
7   - %th.value= row[1]
8   - - if rows.size > head_size
9   - %tfoot
10   - %tr
11   - %td{:colspan => 2}
12   - = link_to 'Show more...', '#', :class => :show_tail
13   - %table.tally.tail{:style => "display: none"}
14   - %tbody
15   - - tail(rows).each do |row|
16   - %tr
17   - %td.percent= number_to_percentage(row[0], :precision => 1)
18   - %th.value= row[1]
app/views/errs/all.html.haml
... ... @@ -1,4 +0,0 @@
1   -- content_for :title, 'All Errors'
2   -- content_for :action_bar do
3   - = link_to 'hide resolved', errs_path, :class => 'button'
4   -= render 'table', :errs => @problems
app/views/errs/index.atom.builder
... ... @@ -1,4 +0,0 @@
1   -atom_feed do |feed|
2   - feed.title("Errbit notices at #{root_url}")
3   - render "errs/list", :feed => feed
4   -end
app/views/errs/index.html.haml
... ... @@ -1,6 +0,0 @@
1   -- content_for :title, 'Unresolved Errors'
2   -- content_for :head do
3   - = auto_discovery_link_tag :atom, errs_path(User.token_authentication_key => current_user.authentication_token, :format => "atom"), :title => "Errbit notices at #{request.host}"
4   -- content_for :action_bar do
5   - = link_to 'show resolved', all_errs_path, :class => 'button'
6   -= render 'table', :errs => @problems
app/views/errs/show.html.haml
... ... @@ -1,83 +0,0 @@
1   -- content_for :page_title, @problem.message
2   -- content_for :title_css_class, 'err_show'
3   -- content_for :title, @problem.error_class || truncate(@problem.message, :length => 32)
4   -- content_for :meta do
5   - %strong App:
6   - = link_to @app.name, app_path(@app)
7   - %strong Where:
8   - = @problem.where
9   - %br
10   - %strong Environment:
11   - = @problem.environment
12   - %strong Last Notice:
13   - = @problem.last_notice_at.to_s(:precise)
14   -- content_for :action_bar do
15   - - if @problem.unresolved?
16   - %span= link_to 'resolve', resolve_app_err_path(@app, @problem), :method => :put, :data => { :confirm => err_confirm }, :class => 'resolve'
17   - - if current_user.authentication_token
18   - %span= link_to 'iCal', app_err_path(:app_id => @app.id, :id => @problem.id, :format => "ics", :auth_token => current_user.authentication_token), :class => "calendar_link"
19   - %span>= link_to 'up', (request.env['HTTP_REFERER'] ? :back : app_errs_path(@app)), :class => 'up'
20   - %br
21   - = render "issue_tracker_links"
22   -
23   -- if Errbit::Config.allow_comments_with_issue_tracker || !@app.issue_tracker_configured? || @problem.comments.any?
24   - - content_for :comments do
25   - %h3 Comments
26   - - @problem.comments.each do |comment|
27   - .window
28   - %table.comment
29   - %tr
30   - %th
31   - - if Errbit::Config.use_gravatar
32   - = gravatar_tag comment.user.email, :s => 24
33   - %span.comment-info
34   - = time_ago_in_words(comment.created_at, true) << " ago by "
35   - = link_to comment.user.email, user_path(comment.user)
36   - %span.delete= link_to '&#10008;'.html_safe, app_err_comment_path(@app, @problem, comment), :method => :delete, :data => { :confirm => "Are sure you don't need this comment?" }, :class => "destroy-comment"
37   - %tr
38   - %td= comment.body.gsub("\n", "<br>").html_safe
39   - - if Errbit::Config.allow_comments_with_issue_tracker || !@app.issue_tracker_configured?
40   - = form_for @comment, :url => app_err_comments_path(@app, @problem) do |comment_form|
41   - %p Add a comment
42   - = comment_form.text_area :body, :style => "width: 420px; height: 80px;"
43   - = comment_form.submit "Save Comment"
44   -
45   -%h4= @notice.try(:message)
46   -
47   -= paginate @notices, :param_name => :notice, :theme => :notices
48   -
49   -.tab-bar
50   - %ul
51   - %li= link_to 'Summary', '#summary', :rel => 'summary', :class => 'button'
52   - %li= link_to 'Backtrace', '#backtrace', :rel => 'backtrace', :class => 'button'
53   - - if @notice && @notice.user_attributes.present?
54   - %li= link_to 'User Details', '#user_attributes', :rel => 'user_attributes', :class => 'button'
55   - %li= link_to 'Environment', '#environment', :rel => 'environment', :class => 'button'
56   - %li= link_to 'Parameters', '#params', :rel => 'params', :class => 'button'
57   - %li= link_to 'Session', '#session', :rel => 'session', :class => 'button'
58   -
59   -- if @notice
60   - #summary
61   - %h3 Summary
62   - = render 'notices/summary', :notice => @notice, :problem => @problem
63   -
64   - #backtrace
65   - %h3 Backtrace
66   - = render 'notices/backtrace', :lines => @notice.backtrace
67   -
68   - - if @notice.user_attributes.present?
69   - #user_attributes
70   - %h3 User Details
71   - = render 'notices/user_attributes', :user => @notice.user_attributes
72   -
73   - #environment
74   - %h3 Environment
75   - = render 'notices/environment', :notice => @notice
76   -
77   - #params
78   - %h3 Parameters
79   - = render 'notices/params', :notice => @notice
80   -
81   - #session
82   - %h3 Session
83   - = render 'notices/session', :notice => @notice
app/views/errs/show.ics.haml
... ... @@ -1 +0,0 @@
1   -= generate_problem_ical(@problem.notices.order_by(:created_at.asc))
app/views/issue_trackers/fogbugz_body.txt.erb
1   -"See this exception on Errbit": <%= app_err_url(problem.app, problem) %>
  1 +"See this exception on Errbit": <%= app_problem_url(problem.app, problem) %>
2 2 <% if notice = problem.notices.first %>
3 3 <%= notice.message %>
4 4  
... ...
app/views/issue_trackers/github_issues_body.txt.erb
1   -[See this exception on Errbit](<%= app_err_url problem.app, problem %> "See this exception on Errbit")
  1 +[See this exception on Errbit](<%= app_problem_url problem.app, problem %> "See this exception on Errbit")
2 2 <% if notice = problem.notices.first %>
3 3 # <%= notice.message %> #
4 4 ## Summary ##
... ...
app/views/issue_trackers/lighthouseapp_body.txt.erb
1   -[See this exception on Errbit](<%= app_err_url problem.app, problem %> "See this exception on Errbit")
  1 +[See this exception on Errbit](<%= app_problem_url problem.app, problem %> "See this exception on Errbit")
2 2 <% if notice = problem.notices.first %>
3 3 # <%= notice.message %> #
4 4 ## Summary ##
... ...
app/views/issue_trackers/pivotal_body.txt.erb
1   -See this exception on Errbit: <%= app_err_url problem.app, problem %>
  1 +See this exception on Errbit: <%= app_problem_url problem.app, problem %>
2 2 <% if notice = problem.notices.first %>
3 3 <% if notice.request['url'].present? %>URL: <%= notice.request['url'] %><% end %>
4 4 Where: <%= notice.where %>
... ...
app/views/issue_trackers/textile_body.txt.erb
1 1 <% if notice = problem.notices.first %>
2 2 h1. <%= notice.message %>
3 3  
4   -h3. "See this exception on Errbit":<%= app_err_url problem.app, problem %>
  4 +h3. "See this exception on Errbit":<%= app_problem_url problem.app, problem %>
5 5  
6 6 h2. Summary
7 7 <% if notice.request['url'].present? %>
... ...
app/views/mailer/err_notification.html.haml
... ... @@ -14,7 +14,7 @@
14 14 %br
15 15 This err has occurred #{pluralize @notice.problem.notices_count, 'time'}.
16 16 %p
17   - = link_to("Click here to view the error on Errbit", app_err_url(@app, @notice.problem), :class => "bold") << "."
  17 + = link_to("Click here to view the error on Errbit", app_problem_url(@app, @notice.problem), :class => "bold") << "."
18 18 %tr
19 19 %td.section
20 20 %table(cellpadding="0" cellspacing="0" border="0" align="left")
... ...
app/views/mailer/err_notification.text.erb
... ... @@ -2,7 +2,7 @@ An err has just occurred in &lt;%= @notice.environment_name %&gt;: &lt;%= raw(@notice.mes
2 2  
3 3 This err has occurred <%= pluralize @notice.problem.notices_count, 'time' %>. You should really look into it here:
4 4  
5   - <%= app_err_url(@app, @notice.problem) %>
  5 + <%= app_problem_url(@app, @notice.problem) %>
6 6  
7 7  
8 8 ERROR MESSAGE:
... ...
app/views/problems/_issue_tracker_links.html.haml 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +- if @app.issue_tracker_configured? || current_user.github_account?
  2 + - if @problem.issue_link.present?
  3 + %span= link_to 'go to issue', @problem.issue_link, :class => "#{@problem.issue_type}_goto goto-issue"
  4 + = link_to 'unlink issue', unlink_issue_app_problem_path(@app, @problem), :method => :delete, :data => { :confirm => "Unlink err issues?" }, :class => "unlink-issue"
  5 + - elsif @problem.issue_link == "pending"
  6 + %span.disabled= link_to 'creating...', '#', :class => "#{@problem.issue_type}_inactive create-issue"
  7 + = link_to 'retry', create_issue_app_problem_path(@app, @problem), :method => :post
  8 + - else
  9 + - if @app.github_repo?
  10 + - if current_user.can_create_github_issues?
  11 + %span= link_to 'create issue', create_issue_app_problem_path(@app, @problem, :tracker => 'user_github'), :method => :post, :class => "github_create create-issue"
  12 + - elsif @app.issue_tracker_configured? && @app.issue_tracker.is_a?(GithubIssuesTracker)
  13 + %span= link_to 'create issue', create_issue_app_problem_path(@app, @problem), :method => :post, :class => "github_create create-issue"
  14 + - if @app.issue_tracker_configured? && !@app.issue_tracker.is_a?(GithubIssuesTracker)
  15 + %span= link_to 'create issue', create_issue_app_problem_path(@app, @problem), :method => :post, :class => "#{@app.issue_tracker.label}_create create-issue"
... ...
app/views/problems/_list.atom.builder 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +feed.updated(@problems.first.try(:created_at) || Time.now)
  2 +
  3 +for problem in @problems
  4 + notice = problem.notices.first
  5 +
  6 + feed.entry(problem, :url => app_problem_url(problem.app, problem)) do |entry|
  7 + entry.title "[#{ problem.where }] #{problem.message.to_s.truncate(27)}"
  8 + entry.author do |author|
  9 + author.name "#{ problem.app.name } [#{ problem.environment }]"
  10 + end
  11 + if notice
  12 + entry.summary(notice_atom_summary(notice), :type => "html")
  13 + end
  14 + end
  15 +end
... ...
app/views/problems/_table.html.haml 0 → 100644
... ... @@ -0,0 +1,56 @@
  1 +- any_issue_links = problems.any?{|e| e.issue_link.present? && e.issue_link != 'pending' }
  2 +=form_tag do
  3 + %table.errs.selectable
  4 + %thead
  5 + %tr
  6 + %th= check_box_tag "toggle_problems_checkboxes"
  7 + %th= link_for_sort "App"
  8 + %th= link_for_sort "What &amp; Where".html_safe, "message"
  9 + %th= link_for_sort "Latest", "last_notice_at"
  10 + %th= link_for_sort "Deploy", "last_deploy_at"
  11 + %th= link_for_sort "Count"
  12 + - if any_issue_links
  13 + %th Issue
  14 + %th Resolve
  15 + %tbody
  16 + - problems.each do |problem|
  17 + %tr{:class => problem.resolved? ? 'resolved' : 'unresolved'}
  18 + %td.select
  19 + = check_box_tag "problems[]", problem.id, @selected_problems.member?(problem.id.to_s)
  20 + %td.app
  21 + = link_to problem.app.name, app_path(problem.app)
  22 + - if current_page?(:controller => 'problems')
  23 + %span.environment= link_to problem.environment, problems_path(:environment => problem.environment)
  24 + - else
  25 + %span.environment= link_to problem.environment, app_path(problem.app, :environment => problem.environment)
  26 + %td.message
  27 + = link_to truncated_problem_message(problem), app_problem_path(problem.app, problem)
  28 + %em= problem.where
  29 + - if problem.comments_count > 0
  30 + - comment = problem.comments.last
  31 + %br
  32 + .inline_comment
  33 + - if comment.user
  34 + %em.commenter= (Errbit::Config.user_has_username ? comment.user.username : comment.user.email).to_s << ":"
  35 + %em= truncate(comment.body, :length => 100, :separator => ' ')
  36 + %td.latest #{time_ago_in_words(problem.last_notice_at)} ago
  37 + %td.deploy= problem.last_deploy_at ? problem.last_deploy_at.to_s(:micro) : 'n/a'
  38 + %td.count= link_to problem.notices_count, app_problem_path(problem.app, problem)
  39 + - if any_issue_links
  40 + %td.issue_link
  41 + - if problem.app.issue_tracker_configured? && problem.issue_link.present? && problem.issue_link != 'pending'
  42 + = link_to image_tag("#{problem.issue_type}_goto.png"), problem.issue_link, :target => "_blank"
  43 + %td.resolve= link_to image_tag("thumbs-up.png"), resolve_app_problem_path(problem.app, problem), :title => "Resolve", :method => :put, :data => { :confirm => problem_confirm }, :class => 'resolve' if problem.unresolved?
  44 + - if problems.none?
  45 + %tr
  46 + %td{:colspan => (any_issue_links ? 8 : 7)}
  47 + %em No errs here
  48 + = paginate problems
  49 + .tab-bar
  50 + %ul
  51 + %li= submit_tag 'Merge', :id => 'merge_problems', :class => 'button', 'data-action' => merge_several_problems_path
  52 + %li= submit_tag 'Unmerge', :id => 'unmerge_problems', :class => 'button', 'data-action' => unmerge_several_problems_path
  53 + %li= submit_tag 'Resolve', :id => 'resolve_problems', :class => 'button', 'data-action' => resolve_several_problems_path
  54 + %li= submit_tag 'Unresolve', :id => 'unresolve_problems', :class => 'button', 'data-action' => unresolve_several_problems_path
  55 + %li= submit_tag 'Delete', :id => 'delete_problems', :class => 'button', 'data-action' => destroy_several_problems_path
  56 +
... ...
app/views/problems/_tally_table.html.haml 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +.head_and_tail
  2 + %table.tally.head
  3 + %tbody
  4 + - head(rows).each do |row|
  5 + %tr
  6 + %td.percent= number_to_percentage(row[0], :precision => 1)
  7 + %th.value= row[1]
  8 + - if rows.size > head_size
  9 + %tfoot
  10 + %tr
  11 + %td{:colspan => 2}
  12 + = link_to 'Show more...', '#', :class => :show_tail
  13 + %table.tally.tail{:style => "display: none"}
  14 + %tbody
  15 + - tail(rows).each do |row|
  16 + %tr
  17 + %td.percent= number_to_percentage(row[0], :precision => 1)
  18 + %th.value= row[1]
... ...
app/views/problems/all.html.haml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +- content_for :title, 'All Errors'
  2 +- content_for :action_bar do
  3 + = link_to 'hide resolved', problems_path, :class => 'button'
  4 += render 'table', :problems => @problems
... ...
app/views/problems/index.atom.builder 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +atom_feed do |feed|
  2 + feed.title("Errbit notices at #{root_url}")
  3 + render "problems/list", :feed => feed
  4 +end
... ...
app/views/problems/index.html.haml 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +- content_for :title, 'Unresolved Errors'
  2 +- content_for :head do
  3 + = auto_discovery_link_tag :atom, problems_path(User.token_authentication_key => current_user.authentication_token, :format => "atom"), :title => "Errbit notices at #{request.host}"
  4 +- content_for :action_bar do
  5 + = link_to 'show resolved', all_problems_path, :class => 'button'
  6 += render 'table', :problems => @problems
... ...
app/views/problems/show.html.haml 0 → 100644
... ... @@ -0,0 +1,83 @@
  1 +- content_for :page_title, @problem.message
  2 +- content_for :title_css_class, 'err_show'
  3 +- content_for :title, @problem.error_class || truncate(@problem.message, :length => 32)
  4 +- content_for :meta do
  5 + %strong App:
  6 + = link_to @app.name, app_path(@app)
  7 + %strong Where:
  8 + = @problem.where
  9 + %br
  10 + %strong Environment:
  11 + = @problem.environment
  12 + %strong Last Notice:
  13 + = @problem.last_notice_at.to_s(:precise)
  14 +- content_for :action_bar do
  15 + - if @problem.unresolved?
  16 + %span= link_to 'resolve', resolve_app_problem_path(@app, @problem), :method => :put, :data => { :confirm => problem_confirm }, :class => 'resolve'
  17 + - if current_user.authentication_token
  18 + %span= link_to 'iCal', app_problem_path(:app_id => @app.id, :id => @problem.id, :format => "ics", :auth_token => current_user.authentication_token), :class => "calendar_link"
  19 + %span>= link_to 'up', (request.env['HTTP_REFERER'] ? :back : app_problems_path(@app)), :class => 'up'
  20 + %br
  21 + = render "issue_tracker_links"
  22 +
  23 +- if Errbit::Config.allow_comments_with_issue_tracker || !@app.issue_tracker_configured? || @problem.comments.any?
  24 + - content_for :comments do
  25 + %h3 Comments
  26 + - @problem.comments.each do |comment|
  27 + .window
  28 + %table.comment
  29 + %tr
  30 + %th
  31 + - if Errbit::Config.use_gravatar
  32 + = gravatar_tag comment.user.email, :s => 24
  33 + %span.comment-info
  34 + = time_ago_in_words(comment.created_at, true) << " ago by "
  35 + = link_to comment.user.email, user_path(comment.user)
  36 + %span.delete= link_to '&#10008;'.html_safe, app_problem_comment_path(@app, @problem, comment), :method => :delete, :data => { :confirm => "Are sure you don't need this comment?" }, :class => "destroy-comment"
  37 + %tr
  38 + %td= comment.body.gsub("\n", "<br>").html_safe
  39 + - if Errbit::Config.allow_comments_with_issue_tracker || !@app.issue_tracker_configured?
  40 + = form_for @comment, :url => app_problem_comments_path(@app, @problem) do |comment_form|
  41 + %p Add a comment
  42 + = comment_form.text_area :body, :style => "width: 420px; height: 80px;"
  43 + = comment_form.submit "Save Comment"
  44 +
  45 +%h4= @notice.try(:message)
  46 +
  47 += paginate @notices, :param_name => :notice, :theme => :notices
  48 +
  49 +.tab-bar
  50 + %ul
  51 + %li= link_to 'Summary', '#summary', :rel => 'summary', :class => 'button'
  52 + %li= link_to 'Backtrace', '#backtrace', :rel => 'backtrace', :class => 'button'
  53 + - if @notice && @notice.user_attributes.present?
  54 + %li= link_to 'User Details', '#user_attributes', :rel => 'user_attributes', :class => 'button'
  55 + %li= link_to 'Environment', '#environment', :rel => 'environment', :class => 'button'
  56 + %li= link_to 'Parameters', '#params', :rel => 'params', :class => 'button'
  57 + %li= link_to 'Session', '#session', :rel => 'session', :class => 'button'
  58 +
  59 +- if @notice
  60 + #summary
  61 + %h3 Summary
  62 + = render 'notices/summary', :notice => @notice, :problem => @problem
  63 +
  64 + #backtrace
  65 + %h3 Backtrace
  66 + = render 'notices/backtrace', :lines => @notice.backtrace
  67 +
  68 + - if @notice.user_attributes.present?
  69 + #user_attributes
  70 + %h3 User Details
  71 + = render 'notices/user_attributes', :user => @notice.user_attributes
  72 +
  73 + #environment
  74 + %h3 Environment
  75 + = render 'notices/environment', :notice => @notice
  76 +
  77 + #params
  78 + %h3 Parameters
  79 + = render 'notices/params', :notice => @notice
  80 +
  81 + #session
  82 + %h3 Session
  83 + = render 'notices/session', :notice => @notice
... ...
app/views/problems/show.ics.haml 0 → 100644
... ... @@ -0,0 +1 @@
  1 += generate_problem_ical(@problem.notices.order_by(:created_at.asc))
... ...
app/views/shared/_navigation.html.haml
... ... @@ -2,7 +2,7 @@
2 2 %ul
3 3 //%li= link_to 'Dashboard', admin_dashboard_path, :class => active_if_here(:dashboards)
4 4 %li.apps{:class => active_if_here(:apps)}= link_to 'Apps', apps_path
5   - %li.errs{:class => active_if_here(:errs)}= link_to 'Errors', errs_path
  5 + %li.errs{:class => active_if_here(:problems)}= link_to 'Errors', problems_path
6 6 - if user_signed_in? && current_user.admin?
7 7 %li.users{:class => active_if_here(:users)}= link_to 'Users', users_path
8   - %div.clear
9 8 \ No newline at end of file
  9 + %div.clear
... ...
config/routes.rb
... ... @@ -14,7 +14,7 @@ Errbit::Application.routes.draw do
14 14 delete :unlink_github
15 15 end
16 16 end
17   - resources :errs, :only => [:index] do
  17 + resources :problems, :only => [:index] do
18 18 collection do
19 19 post :destroy_several
20 20 post :resolve_several
... ... @@ -26,7 +26,7 @@ Errbit::Application.routes.draw do
26 26 end
27 27  
28 28 resources :apps do
29   - resources :errs do
  29 + resources :problems do
30 30 resources :notices
31 31 resources :comments, :only => [:create, :destroy]
32 32  
... ... @@ -37,7 +37,7 @@ Errbit::Application.routes.draw do
37 37 delete :unlink_issue
38 38 end
39 39 end
40   -
  40 +
41 41 resources :deploys, :only => [:index]
42 42 end
43 43  
... ... @@ -46,7 +46,7 @@ Errbit::Application.routes.draw do
46 46 resources :problems, :only => [:index], :defaults => { :format => 'json' }
47 47 resources :notices, :only => [:index], :defaults => { :format => 'json' }
48 48 end
49   - end
  49 + end
50 50  
51 51 root :to => 'apps#index'
52 52  
... ...
spec/controllers/comments_controller_spec.rb
... ... @@ -16,7 +16,7 @@ describe CommentsController do
16 16 let(:user) { Fabricate(:user) }
17 17  
18 18 before(:each) do
19   - post :create, :app_id => problem.app.id, :err_id => problem.id,
  19 + post :create, :app_id => problem.app.id, :problem_id => problem.id,
20 20 :comment => { :body => "One test comment", :user_id => user.id }
21 21 problem.reload
22 22 end
... ... @@ -26,7 +26,7 @@ describe CommentsController do
26 26 end
27 27  
28 28 it "should redirect to problem page" do
29   - response.should redirect_to( app_err_path(problem.app, problem) )
  29 + response.should redirect_to( app_problem_path(problem.app, problem) )
30 30 end
31 31 end
32 32 end
... ... @@ -43,7 +43,7 @@ describe CommentsController do
43 43 let(:comment) { problem.reload.comments.first }
44 44  
45 45 before(:each) do
46   - delete :destroy, :app_id => problem.app.id, :err_id => problem.id, :id => comment.id.to_s
  46 + delete :destroy, :app_id => problem.app.id, :problem_id => problem.id, :id => comment.id.to_s
47 47 problem.reload
48 48 end
49 49  
... ... @@ -52,7 +52,7 @@ describe CommentsController do
52 52 end
53 53  
54 54 it "should redirect to problem page" do
55   - response.should redirect_to( app_err_path(problem.app, problem) )
  55 + response.should redirect_to( app_problem_path(problem.app, problem) )
56 56 end
57 57 end
58 58 end
... ...
spec/controllers/errs_controller_spec.rb
... ... @@ -1,441 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe ErrsController do
4   -
5   - it_requires_authentication :for => {
6   - :index => :get, :all => :get, :show => :get, :resolve => :put
7   - },
8   - :params => {:app_id => 'dummyid', :id => 'dummyid'}
9   -
10   - let(:app) { Fabricate(:app) }
11   - let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :app => app, :environment => "production")) }
12   -
13   -
14   - describe "GET /errs" do
15   - render_views
16   - context 'when logged in as an admin' do
17   - before(:each) do
18   - @user = Fabricate(:admin)
19   - sign_in @user
20   - @problem = Fabricate(:notice, :err => Fabricate(:err, :problem => Fabricate(:problem, :app => app, :environment => "production"))).problem
21   - end
22   -
23   - it "should successfully list errs" do
24   - get :index
25   - response.should be_success
26   - response.body.gsub("&#8203;", "").should match(@problem.message)
27   - end
28   -
29   - it "should list atom feed successfully" do
30   - get :index, :format => "atom"
31   - response.should be_success
32   - response.body.should match(@problem.message)
33   - end
34   -
35   - context "pagination" do
36   - before(:each) do
37   - 35.times { Fabricate :err }
38   - end
39   -
40   - it "should have default per_page value for user" do
41   - get :index
42   - assigns(:problems).to_a.size.should == User::PER_PAGE
43   - end
44   -
45   - it "should be able to override default per_page value" do
46   - @user.update_attribute :per_page, 10
47   - get :index
48   - assigns(:problems).to_a.size.should == 10
49   - end
50   - end
51   -
52   - context 'with environment filters' do
53   - before(:each) do
54   - environments = ['production', 'test', 'development', 'staging']
55   - 20.times do |i|
56   - Fabricate(:problem, :environment => environments[i % environments.length])
57   - end
58   - end
59   -
60   - context 'no params' do
61   - it 'shows errs for all environments' do
62   - get :index
63   - assigns(:problems).size.should == 21
64   - end
65   - end
66   -
67   - context 'environment production' do
68   - it 'shows errs for just production' do
69   - get :index, :environment => 'production'
70   - assigns(:problems).size.should == 6
71   - end
72   - end
73   -
74   - context 'environment staging' do
75   - it 'shows errs for just staging' do
76   - get :index, :environment => 'staging'
77   - assigns(:problems).size.should == 5
78   - end
79   - end
80   -
81   - context 'environment development' do
82   - it 'shows errs for just development' do
83   - get :index, :environment => 'development'
84   - assigns(:problems).size.should == 5
85   - end
86   - end
87   -
88   - context 'environment test' do
89   - it 'shows errs for just test' do
90   - get :index, :environment => 'test'
91   - assigns(:problems).size.should == 5
92   - end
93   - end
94   - end
95   - end
96   -
97   - context 'when logged in as a user' do
98   - it 'gets a paginated list of unresolved errs for the users apps' do
99   - sign_in(user = Fabricate(:user))
100   - unwatched_err = Fabricate(:err)
101   - watched_unresolved_err = Fabricate(:err, :problem => Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => false))
102   - watched_resolved_err = Fabricate(:err, :problem => Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => true))
103   - get :index
104   - assigns(:problems).should include(watched_unresolved_err.problem)
105   - assigns(:problems).should_not include(unwatched_err.problem, watched_resolved_err.problem)
106   - end
107   - end
108   - end
109   -
110   - describe "GET /errs/all" do
111   - context 'when logged in as an admin' do
112   - it "gets a paginated list of all errs" do
113   - sign_in Fabricate(:admin)
114   - errs = Kaminari.paginate_array((1..30).to_a)
115   - 3.times { errs << Fabricate(:err).problem }
116   - 3.times { errs << Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem }
117   - Problem.should_receive(:ordered_by).and_return(
118   - mock('proxy', :page => mock('other_proxy', :per => errs))
119   - )
120   - get :all
121   - assigns(:problems).should == errs
122   - end
123   - end
124   -
125   - context 'when logged in as a user' do
126   - it 'gets a paginated list of all errs for the users apps' do
127   - sign_in(user = Fabricate(:user))
128   - unwatched_err = Fabricate(:problem)
129   - watched_unresolved_err = Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => false)
130   - watched_resolved_err = Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => true)
131   - get :all
132   - assigns(:problems).should include(watched_resolved_err, watched_unresolved_err)
133   - assigns(:problems).should_not include(unwatched_err)
134   - end
135   - end
136   - end
137   -
138   - describe "GET /apps/:app_id/errs/:id" do
139   - render_views
140   -
141   - context 'when logged in as an admin' do
142   - before do
143   - sign_in Fabricate(:admin)
144   - end
145   -
146   - it "finds the app" do
147   - get :show, :app_id => app.id, :id => err.problem.id
148   - assigns(:app).should == app
149   - end
150   -
151   - it "finds the err" do
152   - get :show, :app_id => app.id, :id => err.problem.id
153   - assigns(:problem).should == err.problem
154   - end
155   -
156   - it "successfully render page" do
157   - get :show, :app_id => app.id, :id => err.problem.id
158   - response.should be_success
159   - end
160   -
161   - context 'pagination' do
162   - let!(:notices) do
163   - 3.times.reduce([]) do |coll, i|
164   - coll << Fabricate(:notice, :err => err, :created_at => (Time.now + i))
165   - end
166   - end
167   -
168   - it "paginates the notices 1 at a time, starting with the most recent" do
169   - get :show, :app_id => app.id, :id => err.problem.id
170   - assigns(:notices).entries.count.should == 1
171   - assigns(:notices).should include(notices.last)
172   - end
173   -
174   - it "paginates the notices 1 at a time, based on then notice param" do
175   - get :show, :app_id => app.id, :id => err.problem.id, :notice => 3
176   - assigns(:notices).entries.count.should == 1
177   - assigns(:notices).should include(notices.first)
178   - end
179   - end
180   -
181   - context "create issue button" do
182   - let(:button_matcher) { match(/create issue/) }
183   -
184   - it "should not exist for err's app without issue tracker" do
185   - err = Fabricate :err
186   - get :show, :app_id => err.app.id, :id => err.problem.id
187   -
188   - response.body.should_not button_matcher
189   - end
190   -
191   - it "should exist for err's app with issue tracker" do
192   - tracker = Fabricate(:lighthouse_tracker)
193   - err = Fabricate(:err, :problem => Fabricate(:problem, :app => tracker.app))
194   - get :show, :app_id => err.app.id, :id => err.problem.id
195   -
196   - response.body.should button_matcher
197   - end
198   -
199   - it "should not exist for err with issue_link" do
200   - tracker = Fabricate(:lighthouse_tracker)
201   - err = Fabricate(:err, :problem => Fabricate(:problem, :app => tracker.app, :issue_link => "http://some.host"))
202   - get :show, :app_id => err.app.id, :id => err.problem.id
203   -
204   - response.body.should_not button_matcher
205   - end
206   - end
207   - end
208   -
209   - context 'when logged in as a user' do
210   - before do
211   - sign_in(@user = Fabricate(:user))
212   - @unwatched_err = Fabricate(:err)
213   - @watched_app = Fabricate(:app)
214   - @watcher = Fabricate(:user_watcher, :user => @user, :app => @watched_app)
215   - @watched_err = Fabricate(:err, :problem => Fabricate(:problem, :app => @watched_app))
216   - end
217   -
218   - it 'finds the err if the user is watching the app' do
219   - get :show, :app_id => @watched_app.to_param, :id => @watched_err.problem.id
220   - assigns(:problem).should == @watched_err.problem
221   - end
222   -
223   - it 'raises a DocumentNotFound error if the user is not watching the app' do
224   - lambda {
225   - get :show, :app_id => @unwatched_err.problem.app_id, :id => @unwatched_err.problem.id
226   - }.should raise_error(Mongoid::Errors::DocumentNotFound)
227   - end
228   - end
229   - end
230   -
231   - describe "PUT /apps/:app_id/errs/:id/resolve" do
232   - before do
233   - sign_in Fabricate(:admin)
234   -
235   - @problem = Fabricate(:err)
236   - App.stub(:find).with(@problem.app.id).and_return(@problem.app)
237   - @problem.app.problems.stub(:find).and_return(@problem.problem)
238   - @problem.problem.stub(:resolve!)
239   - end
240   -
241   - it 'finds the app and the err' do
242   - App.should_receive(:find).with(@problem.app.id).and_return(@problem.app)
243   - @problem.app.problems.should_receive(:find).and_return(@problem.problem)
244   - put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
245   - assigns(:app).should == @problem.app
246   - assigns(:problem).should == @problem.problem
247   - end
248   -
249   - it "should resolve the issue" do
250   - @problem.problem.should_receive(:resolve!).and_return(true)
251   - put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
252   - end
253   -
254   - it "should display a message" do
255   - put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
256   - request.flash[:success].should match(/Great news/)
257   - end
258   -
259   - it "should redirect to the app page" do
260   - put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
261   - response.should redirect_to(app_path(@problem.app))
262   - end
263   -
264   - it "should redirect back to errs page" do
265   - request.env["Referer"] = errs_path
266   - put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
267   - response.should redirect_to(errs_path)
268   - end
269   - end
270   -
271   - describe "POST /apps/:app_id/errs/:id/create_issue" do
272   - render_views
273   -
274   - before(:each) do
275   - sign_in Fabricate(:admin)
276   - end
277   -
278   - context "successful issue creation" do
279   - context "lighthouseapp tracker" do
280   - let(:notice) { Fabricate :notice }
281   - let(:tracker) { Fabricate :lighthouse_tracker, :app => notice.app }
282   - let(:problem) { notice.problem }
283   -
284   - before(:each) do
285   - number = 5
286   - @issue_link = "http://#{tracker.account}.lighthouseapp.com/projects/#{tracker.project_id}/tickets/#{number}.xml"
287   - body = "<ticket><number type=\"integer\">#{number}</number></ticket>"
288   - stub_request(:post, "http://#{tracker.account}.lighthouseapp.com/projects/#{tracker.project_id}/tickets.xml").
289   - to_return(:status => 201, :headers => {'Location' => @issue_link}, :body => body )
290   -
291   - post :create_issue, :app_id => problem.app.id, :id => problem.id
292   - problem.reload
293   - end
294   -
295   - it "should redirect to problem page" do
296   - response.should redirect_to( app_err_path(problem.app, problem) )
297   - end
298   - end
299   - end
300   -
301   - context "absent issue tracker" do
302   - let(:problem) { Fabricate :problem }
303   -
304   - before(:each) do
305   - post :create_issue, :app_id => problem.app.id, :id => problem.id
306   - end
307   -
308   - it "should redirect to problem page" do
309   - response.should redirect_to( app_err_path(problem.app, problem) )
310   - end
311   -
312   - it "should set flash error message telling issue tracker of the app doesn't exist" do
313   - flash[:error].should == "This app has no issue tracker setup."
314   - end
315   - end
316   -
317   - context "error during request to a tracker" do
318   - context "lighthouseapp tracker" do
319   - let(:tracker) { Fabricate :lighthouse_tracker }
320   - let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :app => tracker.app)) }
321   -
322   - before(:each) do
323   - stub_request(:post, "http://#{tracker.account}.lighthouseapp.com/projects/#{tracker.project_id}/tickets.xml").to_return(:status => 500)
324   -
325   - post :create_issue, :app_id => err.app.id, :id => err.problem.id
326   - end
327   -
328   - it "should redirect to err page" do
329   - response.should redirect_to( app_err_path(err.app, err.problem) )
330   - end
331   -
332   - it "should notify of connection error" do
333   - flash[:error].should include("There was an error during issue creation:")
334   - end
335   - end
336   - end
337   - end
338   -
339   - describe "DELETE /apps/:app_id/errs/:id/unlink_issue" do
340   - before(:each) do
341   - sign_in Fabricate(:admin)
342   - end
343   -
344   - context "err with issue" do
345   - let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :issue_link => "http://some.host")) }
346   -
347   - before(:each) do
348   - delete :unlink_issue, :app_id => err.app.id, :id => err.problem.id
349   - err.problem.reload
350   - end
351   -
352   - it "should redirect to err page" do
353   - response.should redirect_to( app_err_path(err.app, err.problem) )
354   - end
355   -
356   - it "should clear issue link" do
357   - err.problem.issue_link.should be_nil
358   - end
359   - end
360   -
361   - context "err without issue" do
362   - let(:err) { Fabricate :err }
363   -
364   - before(:each) do
365   - delete :unlink_issue, :app_id => err.app.id, :id => err.problem.id
366   - err.problem.reload
367   - end
368   -
369   - it "should redirect to err page" do
370   - response.should redirect_to( app_err_path(err.app, err.problem) )
371   - end
372   - end
373   - end
374   -
375   - describe "Bulk Actions" do
376   - before(:each) do
377   - sign_in Fabricate(:admin)
378   - @problem1 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem
379   - @problem2 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => false)).problem
380   - end
381   -
382   - it "should apply to multiple problems" do
383   - post :resolve_several, :problems => [@problem1.id.to_s, @problem2.id.to_s]
384   - assigns(:selected_problems).should == [@problem1, @problem2]
385   - end
386   -
387   - it "should require at least one problem" do
388   - post :resolve_several, :problems => []
389   - request.flash[:notice].should match(/You have not selected any/)
390   - end
391   -
392   - context "POST /errs/merge_several" do
393   - it "should require at least two problems" do
394   - post :merge_several, :problems => [@problem1.id.to_s]
395   - request.flash[:notice].should match(/You must select at least two/)
396   - end
397   -
398   - it "should merge the problems" do
399   - lambda {
400   - post :merge_several, :problems => [@problem1.id.to_s, @problem2.id.to_s]
401   - assigns(:merged_problem).reload.errs.length.should == 2
402   - }.should change(Problem, :count).by(-1)
403   - end
404   - end
405   -
406   - context "POST /errs/unmerge_several" do
407   - it "should unmerge a merged problem" do
408   - merged_problem = Problem.merge!(@problem1, @problem2)
409   - merged_problem.errs.length.should == 2
410   - lambda {
411   - post :unmerge_several, :problems => [merged_problem.id.to_s]
412   - merged_problem.reload.errs.length.should == 1
413   - }.should change(Problem, :count).by(1)
414   - end
415   - end
416   -
417   - context "POST /errs/resolve_several" do
418   - it "should resolve the issue" do
419   - post :resolve_several, :problems => [@problem2.id.to_s]
420   - @problem2.reload.resolved?.should == true
421   - end
422   - end
423   -
424   - context "POST /errs/unresolve_several" do
425   - it "should unresolve the issue" do
426   - post :unresolve_several, :problems => [@problem1.id.to_s]
427   - @problem1.reload.resolved?.should == false
428   - end
429   - end
430   -
431   - context "POST /errs/destroy_several" do
432   - it "should delete the errs" do
433   - lambda {
434   - post :destroy_several, :problems => [@problem1.id.to_s]
435   - }.should change(Problem, :count).by(-1)
436   - end
437   - end
438   - end
439   -
440   -end
441   -
spec/controllers/notices_controller_spec.rb
... ... @@ -68,7 +68,7 @@ describe NoticesController do
68 68 problem = Fabricate(:problem, :app => app, :environment => "production")
69 69 notice = Fabricate(:notice, :err => Fabricate(:err, :problem => problem))
70 70 get :locate, :id => notice.id
71   - response.should redirect_to(app_err_path(problem.app, problem))
  71 + response.should redirect_to(app_problem_path(problem.app, problem))
72 72 end
73 73 end
74 74 end
... ...
spec/controllers/problems_controller_spec.rb 0 → 100644
... ... @@ -0,0 +1,441 @@
  1 +require 'spec_helper'
  2 +
  3 +describe ProblemsController do
  4 +
  5 + it_requires_authentication :for => {
  6 + :index => :get, :all => :get, :show => :get, :resolve => :put
  7 + },
  8 + :params => {:app_id => 'dummyid', :id => 'dummyid'}
  9 +
  10 + let(:app) { Fabricate(:app) }
  11 + let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :app => app, :environment => "production")) }
  12 +
  13 +
  14 + describe "GET /problems" do
  15 + render_views
  16 + context 'when logged in as an admin' do
  17 + before(:each) do
  18 + @user = Fabricate(:admin)
  19 + sign_in @user
  20 + @problem = Fabricate(:notice, :err => Fabricate(:err, :problem => Fabricate(:problem, :app => app, :environment => "production"))).problem
  21 + end
  22 +
  23 + it "should successfully list problems" do
  24 + get :index
  25 + response.should be_success
  26 + response.body.gsub("&#8203;", "").should match(@problem.message)
  27 + end
  28 +
  29 + it "should list atom feed successfully" do
  30 + get :index, :format => "atom"
  31 + response.should be_success
  32 + response.body.should match(@problem.message)
  33 + end
  34 +
  35 + context "pagination" do
  36 + before(:each) do
  37 + 35.times { Fabricate :err }
  38 + end
  39 +
  40 + it "should have default per_page value for user" do
  41 + get :index
  42 + assigns(:problems).to_a.size.should == User::PER_PAGE
  43 + end
  44 +
  45 + it "should be able to override default per_page value" do
  46 + @user.update_attribute :per_page, 10
  47 + get :index
  48 + assigns(:problems).to_a.size.should == 10
  49 + end
  50 + end
  51 +
  52 + context 'with environment filters' do
  53 + before(:each) do
  54 + environments = ['production', 'test', 'development', 'staging']
  55 + 20.times do |i|
  56 + Fabricate(:problem, :environment => environments[i % environments.length])
  57 + end
  58 + end
  59 +
  60 + context 'no params' do
  61 + it 'shows problems for all environments' do
  62 + get :index
  63 + assigns(:problems).size.should == 21
  64 + end
  65 + end
  66 +
  67 + context 'environment production' do
  68 + it 'shows problems for just production' do
  69 + get :index, :environment => 'production'
  70 + assigns(:problems).size.should == 6
  71 + end
  72 + end
  73 +
  74 + context 'environment staging' do
  75 + it 'shows problems for just staging' do
  76 + get :index, :environment => 'staging'
  77 + assigns(:problems).size.should == 5
  78 + end
  79 + end
  80 +
  81 + context 'environment development' do
  82 + it 'shows problems for just development' do
  83 + get :index, :environment => 'development'
  84 + assigns(:problems).size.should == 5
  85 + end
  86 + end
  87 +
  88 + context 'environment test' do
  89 + it 'shows problems for just test' do
  90 + get :index, :environment => 'test'
  91 + assigns(:problems).size.should == 5
  92 + end
  93 + end
  94 + end
  95 + end
  96 +
  97 + context 'when logged in as a user' do
  98 + it 'gets a paginated list of unresolved problems for the users apps' do
  99 + sign_in(user = Fabricate(:user))
  100 + unwatched_err = Fabricate(:err)
  101 + watched_unresolved_err = Fabricate(:err, :problem => Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => false))
  102 + watched_resolved_err = Fabricate(:err, :problem => Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => true))
  103 + get :index
  104 + assigns(:problems).should include(watched_unresolved_err.problem)
  105 + assigns(:problems).should_not include(unwatched_err.problem, watched_resolved_err.problem)
  106 + end
  107 + end
  108 + end
  109 +
  110 + describe "GET /problems/all" do
  111 + context 'when logged in as an admin' do
  112 + it "gets a paginated list of all problems" do
  113 + sign_in Fabricate(:admin)
  114 + problems = Kaminari.paginate_array((1..30).to_a)
  115 + 3.times { problems << Fabricate(:err).problem }
  116 + 3.times { problems << Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem }
  117 + Problem.should_receive(:ordered_by).and_return(
  118 + mock('proxy', :page => mock('other_proxy', :per => problems))
  119 + )
  120 + get :all
  121 + assigns(:problems).should == problems
  122 + end
  123 + end
  124 +
  125 + context 'when logged in as a user' do
  126 + it 'gets a paginated list of all problems for the users apps' do
  127 + sign_in(user = Fabricate(:user))
  128 + unwatched_problem = Fabricate(:problem)
  129 + watched_unresolved_problem = Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => false)
  130 + watched_resolved_problem = Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => true)
  131 + get :all
  132 + assigns(:problems).should include(watched_resolved_problem, watched_unresolved_problem)
  133 + assigns(:problems).should_not include(unwatched_problem)
  134 + end
  135 + end
  136 + end
  137 +
  138 + describe "GET /apps/:app_id/problems/:id" do
  139 + render_views
  140 +
  141 + context 'when logged in as an admin' do
  142 + before do
  143 + sign_in Fabricate(:admin)
  144 + end
  145 +
  146 + it "finds the app" do
  147 + get :show, :app_id => app.id, :id => err.problem.id
  148 + assigns(:app).should == app
  149 + end
  150 +
  151 + it "finds the problem" do
  152 + get :show, :app_id => app.id, :id => err.problem.id
  153 + assigns(:problem).should == err.problem
  154 + end
  155 +
  156 + it "successfully render page" do
  157 + get :show, :app_id => app.id, :id => err.problem.id
  158 + response.should be_success
  159 + end
  160 +
  161 + context 'pagination' do
  162 + let!(:notices) do
  163 + 3.times.reduce([]) do |coll, i|
  164 + coll << Fabricate(:notice, :err => err, :created_at => (Time.now + i))
  165 + end
  166 + end
  167 +
  168 + it "paginates the notices 1 at a time, starting with the most recent" do
  169 + get :show, :app_id => app.id, :id => err.problem.id
  170 + assigns(:notices).entries.count.should == 1
  171 + assigns(:notices).should include(notices.last)
  172 + end
  173 +
  174 + it "paginates the notices 1 at a time, based on then notice param" do
  175 + get :show, :app_id => app.id, :id => err.problem.id, :notice => 3
  176 + assigns(:notices).entries.count.should == 1
  177 + assigns(:notices).should include(notices.first)
  178 + end
  179 + end
  180 +
  181 + context "create issue button" do
  182 + let(:button_matcher) { match(/create issue/) }
  183 +
  184 + it "should not exist for problem's app without issue tracker" do
  185 + err = Fabricate :err
  186 + get :show, :app_id => err.app.id, :id => err.problem.id
  187 +
  188 + response.body.should_not button_matcher
  189 + end
  190 +
  191 + it "should exist for problem's app with issue tracker" do
  192 + tracker = Fabricate(:lighthouse_tracker)
  193 + err = Fabricate(:err, :problem => Fabricate(:problem, :app => tracker.app))
  194 + get :show, :app_id => err.app.id, :id => err.problem.id
  195 +
  196 + response.body.should button_matcher
  197 + end
  198 +
  199 + it "should not exist for problem with issue_link" do
  200 + tracker = Fabricate(:lighthouse_tracker)
  201 + err = Fabricate(:err, :problem => Fabricate(:problem, :app => tracker.app, :issue_link => "http://some.host"))
  202 + get :show, :app_id => err.app.id, :id => err.problem.id
  203 +
  204 + response.body.should_not button_matcher
  205 + end
  206 + end
  207 + end
  208 +
  209 + context 'when logged in as a user' do
  210 + before do
  211 + sign_in(@user = Fabricate(:user))
  212 + @unwatched_err = Fabricate(:err)
  213 + @watched_app = Fabricate(:app)
  214 + @watcher = Fabricate(:user_watcher, :user => @user, :app => @watched_app)
  215 + @watched_err = Fabricate(:err, :problem => Fabricate(:problem, :app => @watched_app))
  216 + end
  217 +
  218 + it 'finds the problem if the user is watching the app' do
  219 + get :show, :app_id => @watched_app.to_param, :id => @watched_err.problem.id
  220 + assigns(:problem).should == @watched_err.problem
  221 + end
  222 +
  223 + it 'raises a DocumentNotFound error if the user is not watching the app' do
  224 + lambda {
  225 + get :show, :app_id => @unwatched_err.problem.app_id, :id => @unwatched_err.problem.id
  226 + }.should raise_error(Mongoid::Errors::DocumentNotFound)
  227 + end
  228 + end
  229 + end
  230 +
  231 + describe "PUT /apps/:app_id/problems/:id/resolve" do
  232 + before do
  233 + sign_in Fabricate(:admin)
  234 +
  235 + @problem = Fabricate(:err)
  236 + App.stub(:find).with(@problem.app.id).and_return(@problem.app)
  237 + @problem.app.problems.stub(:find).and_return(@problem.problem)
  238 + @problem.problem.stub(:resolve!)
  239 + end
  240 +
  241 + it 'finds the app and the problem' do
  242 + App.should_receive(:find).with(@problem.app.id).and_return(@problem.app)
  243 + @problem.app.problems.should_receive(:find).and_return(@problem.problem)
  244 + put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
  245 + assigns(:app).should == @problem.app
  246 + assigns(:problem).should == @problem.problem
  247 + end
  248 +
  249 + it "should resolve the issue" do
  250 + @problem.problem.should_receive(:resolve!).and_return(true)
  251 + put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
  252 + end
  253 +
  254 + it "should display a message" do
  255 + put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
  256 + request.flash[:success].should match(/Great news/)
  257 + end
  258 +
  259 + it "should redirect to the app page" do
  260 + put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
  261 + response.should redirect_to(app_path(@problem.app))
  262 + end
  263 +
  264 + it "should redirect back to problems page" do
  265 + request.env["Referer"] = problems_path
  266 + put :resolve, :app_id => @problem.app.id, :id => @problem.problem.id
  267 + response.should redirect_to(problems_path)
  268 + end
  269 + end
  270 +
  271 + describe "POST /apps/:app_id/problems/:id/create_issue" do
  272 + render_views
  273 +
  274 + before(:each) do
  275 + sign_in Fabricate(:admin)
  276 + end
  277 +
  278 + context "successful issue creation" do
  279 + context "lighthouseapp tracker" do
  280 + let(:notice) { Fabricate :notice }
  281 + let(:tracker) { Fabricate :lighthouse_tracker, :app => notice.app }
  282 + let(:problem) { notice.problem }
  283 +
  284 + before(:each) do
  285 + number = 5
  286 + @issue_link = "http://#{tracker.account}.lighthouseapp.com/projects/#{tracker.project_id}/tickets/#{number}.xml"
  287 + body = "<ticket><number type=\"integer\">#{number}</number></ticket>"
  288 + stub_request(:post, "http://#{tracker.account}.lighthouseapp.com/projects/#{tracker.project_id}/tickets.xml").
  289 + to_return(:status => 201, :headers => {'Location' => @issue_link}, :body => body )
  290 +
  291 + post :create_issue, :app_id => problem.app.id, :id => problem.id
  292 + problem.reload
  293 + end
  294 +
  295 + it "should redirect to problem page" do
  296 + response.should redirect_to( app_problem_path(problem.app, problem) )
  297 + end
  298 + end
  299 + end
  300 +
  301 + context "absent issue tracker" do
  302 + let(:problem) { Fabricate :problem }
  303 +
  304 + before(:each) do
  305 + post :create_issue, :app_id => problem.app.id, :id => problem.id
  306 + end
  307 +
  308 + it "should redirect to problem page" do
  309 + response.should redirect_to( app_problem_path(problem.app, problem) )
  310 + end
  311 +
  312 + it "should set flash error message telling issue tracker of the app doesn't exist" do
  313 + flash[:error].should == "This app has no issue tracker setup."
  314 + end
  315 + end
  316 +
  317 + context "error during request to a tracker" do
  318 + context "lighthouseapp tracker" do
  319 + let(:tracker) { Fabricate :lighthouse_tracker }
  320 + let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :app => tracker.app)) }
  321 +
  322 + before(:each) do
  323 + stub_request(:post, "http://#{tracker.account}.lighthouseapp.com/projects/#{tracker.project_id}/tickets.xml").to_return(:status => 500)
  324 +
  325 + post :create_issue, :app_id => err.app.id, :id => err.problem.id
  326 + end
  327 +
  328 + it "should redirect to problem page" do
  329 + response.should redirect_to( app_problem_path(err.app, err.problem) )
  330 + end
  331 +
  332 + it "should notify of connection error" do
  333 + flash[:error].should include("There was an error during issue creation:")
  334 + end
  335 + end
  336 + end
  337 + end
  338 +
  339 + describe "DELETE /apps/:app_id/problems/:id/unlink_issue" do
  340 + before(:each) do
  341 + sign_in Fabricate(:admin)
  342 + end
  343 +
  344 + context "problem with issue" do
  345 + let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :issue_link => "http://some.host")) }
  346 +
  347 + before(:each) do
  348 + delete :unlink_issue, :app_id => err.app.id, :id => err.problem.id
  349 + err.problem.reload
  350 + end
  351 +
  352 + it "should redirect to problem page" do
  353 + response.should redirect_to( app_problem_path(err.app, err.problem) )
  354 + end
  355 +
  356 + it "should clear issue link" do
  357 + err.problem.issue_link.should be_nil
  358 + end
  359 + end
  360 +
  361 + context "err without issue" do
  362 + let(:err) { Fabricate :err }
  363 +
  364 + before(:each) do
  365 + delete :unlink_issue, :app_id => err.app.id, :id => err.problem.id
  366 + err.problem.reload
  367 + end
  368 +
  369 + it "should redirect to problem page" do
  370 + response.should redirect_to( app_problem_path(err.app, err.problem) )
  371 + end
  372 + end
  373 + end
  374 +
  375 + describe "Bulk Actions" do
  376 + before(:each) do
  377 + sign_in Fabricate(:admin)
  378 + @problem1 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem
  379 + @problem2 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => false)).problem
  380 + end
  381 +
  382 + it "should apply to multiple problems" do
  383 + post :resolve_several, :problems => [@problem1.id.to_s, @problem2.id.to_s]
  384 + assigns(:selected_problems).should == [@problem1, @problem2]
  385 + end
  386 +
  387 + it "should require at least one problem" do
  388 + post :resolve_several, :problems => []
  389 + request.flash[:notice].should match(/You have not selected any/)
  390 + end
  391 +
  392 + context "POST /problems/merge_several" do
  393 + it "should require at least two problems" do
  394 + post :merge_several, :problems => [@problem1.id.to_s]
  395 + request.flash[:notice].should match(/You must select at least two/)
  396 + end
  397 +
  398 + it "should merge the problems" do
  399 + lambda {
  400 + post :merge_several, :problems => [@problem1.id.to_s, @problem2.id.to_s]
  401 + assigns(:merged_problem).reload.errs.length.should == 2
  402 + }.should change(Problem, :count).by(-1)
  403 + end
  404 + end
  405 +
  406 + context "POST /problems/unmerge_several" do
  407 + it "should unmerge a merged problem" do
  408 + merged_problem = Problem.merge!(@problem1, @problem2)
  409 + merged_problem.errs.length.should == 2
  410 + lambda {
  411 + post :unmerge_several, :problems => [merged_problem.id.to_s]
  412 + merged_problem.reload.errs.length.should == 1
  413 + }.should change(Problem, :count).by(1)
  414 + end
  415 + end
  416 +
  417 + context "POST /problems/resolve_several" do
  418 + it "should resolve the issue" do
  419 + post :resolve_several, :problems => [@problem2.id.to_s]
  420 + @problem2.reload.resolved?.should == true
  421 + end
  422 + end
  423 +
  424 + context "POST /problems/unresolve_several" do
  425 + it "should unresolve the issue" do
  426 + post :unresolve_several, :problems => [@problem1.id.to_s]
  427 + @problem1.reload.resolved?.should == false
  428 + end
  429 + end
  430 +
  431 + context "POST /problems/destroy_several" do
  432 + it "should delete the problems" do
  433 + lambda {
  434 + post :destroy_several, :problems => [@problem1.id.to_s]
  435 + }.should change(Problem, :count).by(-1)
  436 + end
  437 + end
  438 + end
  439 +
  440 +end
  441 +
... ...
spec/helpers/errs_helper_spec.rb
... ... @@ -1,35 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe ErrsHelper do
4   - describe '#truncated_err_message' do
5   - it 'is html safe' do
6   - problem = double('problem', :message => '#<NoMethodError: ...>')
7   - truncated = helper.truncated_err_message(problem)
8   - truncated.should be_html_safe
9   - truncated.should_not include('<', '>')
10   - end
11   - end
12   -
13   - describe "#gravatar_tag" do
14   - let(:email) { "gravatar@example.com" }
15   - let(:email_hash) { Digest::MD5.hexdigest email }
16   - let(:base_url) { "http://www.gravatar.com/avatar/#{email_hash}" }
17   -
18   - context "default config" do
19   - before do
20   - Errbit::Config.stub(:use_gravatar).and_return(true)
21   - Errbit::Config.stub(:gravatar_default).and_return('identicon')
22   - end
23   -
24   - it "should render image_tag with correct alt and src" do
25   - expected = "<img alt=\"#{email}\" class=\"gravatar\" src=\"#{base_url}?d=identicon&amp;s=48\" />"
26   - helper.gravatar_tag(email, :s => 48).should eq(expected)
27   - end
28   -
29   - it "should override :d" do
30   - expected = "<img alt=\"#{email}\" class=\"gravatar\" src=\"#{base_url}?d=retro&amp;s=48\" />"
31   - helper.gravatar_tag(email, :d => 'retro', :s => 48).should eq(expected)
32   - end
33   - end
34   - end
35   -end
spec/helpers/problems_helper_spec.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +require 'spec_helper'
  2 +
  3 +describe ProblemsHelper do
  4 + describe '#truncated_problem_message' do
  5 + it 'is html safe' do
  6 + problem = double('problem', :message => '#<NoMethodError: ...>')
  7 + truncated = helper.truncated_problem_message(problem)
  8 + truncated.should be_html_safe
  9 + truncated.should_not include('<', '>')
  10 + end
  11 + end
  12 +
  13 + describe "#gravatar_tag" do
  14 + let(:email) { "gravatar@example.com" }
  15 + let(:email_hash) { Digest::MD5.hexdigest email }
  16 + let(:base_url) { "http://www.gravatar.com/avatar/#{email_hash}" }
  17 +
  18 + context "default config" do
  19 + before do
  20 + Errbit::Config.stub(:use_gravatar).and_return(true)
  21 + Errbit::Config.stub(:gravatar_default).and_return('identicon')
  22 + end
  23 +
  24 + it "should render image_tag with correct alt and src" do
  25 + expected = "<img alt=\"#{email}\" class=\"gravatar\" src=\"#{base_url}?d=identicon&amp;s=48\" />"
  26 + helper.gravatar_tag(email, :s => 48).should eq(expected)
  27 + end
  28 +
  29 + it "should override :d" do
  30 + expected = "<img alt=\"#{email}\" class=\"gravatar\" src=\"#{base_url}?d=retro&amp;s=48\" />"
  31 + helper.gravatar_tag(email, :d => 'retro', :s => 48).should eq(expected)
  32 + end
  33 + end
  34 + end
  35 +end
... ...
spec/views/errs/show.html.haml_spec.rb
... ... @@ -1,128 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe "errs/show.html.haml" do
4   - before do
5   - err = Fabricate(:err)
6   - problem = err.problem
7   - comment = Fabricate(:comment)
8   - assign :problem, problem
9   - assign :comment, comment
10   - assign :app, problem.app
11   - assign :notices, err.notices.page(1).per(1)
12   - assign :notice, err.notices.first
13   - controller.stub(:current_user) { Fabricate(:user) }
14   - end
15   -
16   - def with_issue_tracker(tracker, problem)
17   - problem.app.issue_tracker = tracker.new :api_token => "token token token", :project_id => "1234"
18   - assign :problem, problem
19   - assign :app, problem.app
20   - end
21   -
22   - describe "content_for :action_bar" do
23   - def action_bar
24   - view.content_for(:action_bar)
25   - end
26   -
27   - it "should confirm the 'resolve' link by default" do
28   - render
29   -
30   - action_bar.should have_selector('a.resolve[data-confirm="Seriously?"]')
31   - end
32   -
33   - it "should confirm the 'resolve' link if configuration is unset" do
34   - Errbit::Config.stub(:confirm_resolve_err).and_return(nil)
35   - render
36   -
37   - action_bar.should have_selector('a.resolve[data-confirm="Seriously?"]')
38   - end
39   -
40   - it "should not confirm the 'resolve' link if configured not to" do
41   - Errbit::Config.stub(:confirm_resolve_err).and_return(false)
42   - render
43   -
44   - action_bar.should have_selector('a.resolve[data-confirm="null"]')
45   - end
46   -
47   - it "should link 'up' to HTTP_REFERER if is set" do
48   - url = 'http://localhost:3000/errs'
49   - controller.request.env['HTTP_REFERER'] = url
50   - render
51   -
52   - action_bar.should have_selector("span a.up[href='#{url}']", :text => 'up')
53   - end
54   -
55   - it "should link 'up' to app_errs_path if HTTP_REFERER isn't set'" do
56   - controller.request.env['HTTP_REFERER'] = nil
57   - problem = Fabricate(:problem_with_comments)
58   - assign :problem, problem
59   - assign :app, problem.app
60   - render
61   -
62   - action_bar.should have_selector("span a.up[href='#{app_errs_path(problem.app)}']", :text => 'up')
63   - end
64   -
65   - context 'create issue links' do
66   - it 'should allow creating issue for github if current user has linked their github account' do
67   - user = Fabricate(:user, :github_login => 'test_user', :github_oauth_token => 'abcdef')
68   - controller.stub(:current_user) { user }
69   -
70   - problem = Fabricate(:problem_with_comments, :app => Fabricate(:app, :github_repo => "test_user/test_repo"))
71   - assign :problem, problem
72   - assign :app, problem.app
73   - render
74   -
75   - action_bar.should have_selector("span a.github_create.create-issue", :text => 'create issue')
76   - end
77   -
78   - it 'should allow creating issue for github if application has a github tracker' do
79   - problem = Fabricate(:problem_with_comments, :app => Fabricate(:app, :github_repo => "test_user/test_repo"))
80   - with_issue_tracker(GithubIssuesTracker, problem)
81   - assign :problem, problem
82   - assign :app, problem.app
83   - render
84   -
85   - action_bar.should have_selector("span a.github_create.create-issue", :text => 'create issue')
86   - end
87   - end
88   - end
89   -
90   - describe "content_for :comments with comments disabled for configured issue tracker" do
91   - before do
92   - Errbit::Config.stub(:allow_comments_with_issue_tracker).and_return(false)
93   - Errbit::Config.stub(:use_gravatar).and_return(true)
94   - end
95   -
96   - it 'should display comments and new comment form when no issue tracker' do
97   - problem = Fabricate(:problem_with_comments)
98   - assign :problem, problem
99   - assign :app, problem.app
100   - render
101   -
102   - view.content_for(:comments).should include('Test comment')
103   - view.content_for(:comments).should have_selector('img[src^="http://www.gravatar.com/avatar"]')
104   - view.content_for(:comments).should include('Add a comment')
105   - end
106   -
107   - context "with issue tracker" do
108   - it 'should not display the comments section' do
109   - problem = Fabricate(:problem)
110   - with_issue_tracker(PivotalLabsTracker, problem)
111   - render
112   - view.view_flow.get(:comments).should be_blank
113   - end
114   -
115   - it 'should display existing comments' do
116   - problem = Fabricate(:problem_with_comments)
117   - problem.reload
118   - with_issue_tracker(PivotalLabsTracker, problem)
119   - render
120   -
121   - view.content_for(:comments).should include('Test comment')
122   - view.content_for(:comments).should have_selector('img[src^="http://www.gravatar.com/avatar"]')
123   - view.content_for(:comments).should_not include('Add a comment')
124   - end
125   - end
126   - end
127   -end
128   -
spec/views/problems/show.html.haml_spec.rb 0 → 100644
... ... @@ -0,0 +1,127 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "problems/show.html.haml" do
  4 + before do
  5 + problem = Fabricate(:problem)
  6 + comment = Fabricate(:comment)
  7 + assign :problem, problem
  8 + assign :comment, comment
  9 + assign :app, problem.app
  10 + assign :notices, problem.notices.page(1).per(1)
  11 + assign :notice, problem.notices.first
  12 + controller.stub(:current_user) { Fabricate(:user) }
  13 + end
  14 +
  15 + def with_issue_tracker(tracker, problem)
  16 + problem.app.issue_tracker = tracker.new :api_token => "token token token", :project_id => "1234"
  17 + assign :problem, problem
  18 + assign :app, problem.app
  19 + end
  20 +
  21 + describe "content_for :action_bar" do
  22 + def action_bar
  23 + view.content_for(:action_bar)
  24 + end
  25 +
  26 + it "should confirm the 'resolve' link by default" do
  27 + render
  28 +
  29 + action_bar.should have_selector('a.resolve[data-confirm="Seriously?"]')
  30 + end
  31 +
  32 + it "should confirm the 'resolve' link if configuration is unset" do
  33 + Errbit::Config.stub(:confirm_resolve_err).and_return(nil)
  34 + render
  35 +
  36 + action_bar.should have_selector('a.resolve[data-confirm="Seriously?"]')
  37 + end
  38 +
  39 + it "should not confirm the 'resolve' link if configured not to" do
  40 + Errbit::Config.stub(:confirm_resolve_err).and_return(false)
  41 + render
  42 +
  43 + action_bar.should have_selector('a.resolve[data-confirm="null"]')
  44 + end
  45 +
  46 + it "should link 'up' to HTTP_REFERER if is set" do
  47 + url = 'http://localhost:3000/problems'
  48 + controller.request.env['HTTP_REFERER'] = url
  49 + render
  50 +
  51 + action_bar.should have_selector("span a.up[href='#{url}']", :text => 'up')
  52 + end
  53 +
  54 + it "should link 'up' to app_problems_path if HTTP_REFERER isn't set'" do
  55 + controller.request.env['HTTP_REFERER'] = nil
  56 + problem = Fabricate(:problem_with_comments)
  57 + assign :problem, problem
  58 + assign :app, problem.app
  59 + render
  60 +
  61 + action_bar.should have_selector("span a.up[href='#{app_problems_path(problem.app)}']", :text => 'up')
  62 + end
  63 +
  64 + context 'create issue links' do
  65 + it 'should allow creating issue for github if current user has linked their github account' do
  66 + user = Fabricate(:user, :github_login => 'test_user', :github_oauth_token => 'abcdef')
  67 + controller.stub(:current_user) { user }
  68 +
  69 + problem = Fabricate(:problem_with_comments, :app => Fabricate(:app, :github_repo => "test_user/test_repo"))
  70 + assign :problem, problem
  71 + assign :app, problem.app
  72 + render
  73 +
  74 + action_bar.should have_selector("span a.github_create.create-issue", :text => 'create issue')
  75 + end
  76 +
  77 + it 'should allow creating issue for github if application has a github tracker' do
  78 + problem = Fabricate(:problem_with_comments, :app => Fabricate(:app, :github_repo => "test_user/test_repo"))
  79 + with_issue_tracker(GithubIssuesTracker, problem)
  80 + assign :problem, problem
  81 + assign :app, problem.app
  82 + render
  83 +
  84 + action_bar.should have_selector("span a.github_create.create-issue", :text => 'create issue')
  85 + end
  86 + end
  87 + end
  88 +
  89 + describe "content_for :comments with comments disabled for configured issue tracker" do
  90 + before do
  91 + Errbit::Config.stub(:allow_comments_with_issue_tracker).and_return(false)
  92 + Errbit::Config.stub(:use_gravatar).and_return(true)
  93 + end
  94 +
  95 + it 'should display comments and new comment form when no issue tracker' do
  96 + problem = Fabricate(:problem_with_comments)
  97 + assign :problem, problem
  98 + assign :app, problem.app
  99 + render
  100 +
  101 + view.content_for(:comments).should include('Test comment')
  102 + view.content_for(:comments).should have_selector('img[src^="http://www.gravatar.com/avatar"]')
  103 + view.content_for(:comments).should include('Add a comment')
  104 + end
  105 +
  106 + context "with issue tracker" do
  107 + it 'should not display the comments section' do
  108 + problem = Fabricate(:problem)
  109 + with_issue_tracker(PivotalLabsTracker, problem)
  110 + render
  111 + view.view_flow.get(:comments).should be_blank
  112 + end
  113 +
  114 + it 'should display existing comments' do
  115 + problem = Fabricate(:problem_with_comments)
  116 + problem.reload
  117 + with_issue_tracker(PivotalLabsTracker, problem)
  118 + render
  119 +
  120 + view.content_for(:comments).should include('Test comment')
  121 + view.content_for(:comments).should have_selector('img[src^="http://www.gravatar.com/avatar"]')
  122 + view.content_for(:comments).should_not include('Add a comment')
  123 + end
  124 + end
  125 + end
  126 +end
  127 +
... ...