Commit c6548a8e1514f78d2770307a92158b24b7e71b4f

Authored by Stephen Crosby
2 parents 0ff2eb5a 74429ae6
Exists in master and in 1 other branch production

Merge pull request #938 from stevecrozz/users_can_see_all_apps

Refs #561 users can see all apps
app/assets/stylesheets/errbit.css.erb
... ... @@ -540,8 +540,8 @@ a.button.active {
540 540 display: inline-block;
541 541 }
542 542  
543   -/* Watchers / Issue Tracker / Notification Forms */
544   -div.watcher.nested .watcher_params, div.issue_tracker.nested .tracker_params, div.notification_service.nested .notification_params {
  543 +/* Issue Tracker / Notification Forms */
  544 +div.issue_tracker.nested .tracker_params, div.notification_service.nested .notification_params {
545 545 display: none;
546 546 }
547 547  
... ...
app/controllers/application_controller.rb
... ... @@ -5,13 +5,6 @@ class ApplicationController < ActionController::Base
5 5 before_action :authenticate_user!
6 6 before_action :set_time_zone
7 7  
8   - # Devise override - After login, if there is only one app,
9   - # redirect to that app's path instead of the root path (apps#index).
10   - def stored_location_for(resource)
11   - location = super || root_path
12   - (location == root_path && current_user.apps.count == 1) ? app_path(current_user.apps.first) : location
13   - end
14   -
15 8 rescue_from ActionController::RedirectBackError, :with => :redirect_to_root
16 9  
17 10 class StrongParametersWithEagerAttributesStrategy < DecentExposure::StrongParametersStrategy
... ...
app/controllers/apps_controller.rb
... ... @@ -7,9 +7,7 @@ class AppsController &lt; ApplicationController
7 7 before_action :parse_notice_at_notices_or_set_default, :only => [:create, :update]
8 8 respond_to :html
9 9  
10   - expose(:app_scope) {
11   - (current_user.admin? ? App : current_user.apps)
12   - }
  10 + expose(:app_scope) { App }
13 11  
14 12 expose(:apps) {
15 13 app_scope.asc(:name).map { |app| AppDecorator.new(app) }
... ...
app/controllers/comments_controller.rb
... ... @@ -27,10 +27,6 @@ class CommentsController &lt; ApplicationController
27 27 protected
28 28 def find_app
29 29 @app = App.find(params[:app_id])
30   -
31   - # Mongoid Bug: could not chain: current_user.apps.find_by_id!
32   - # apparently finding by 'watchers.email' and 'id' is broken
33   - raise(Mongoid::Errors::DocumentNotFound.new(App,@app.id)) unless current_user.admin? || current_user.watching?(@app)
34 30 end
35 31  
36 32 def find_problem
... ...
app/controllers/deploys_controller.rb
... ... @@ -12,13 +12,9 @@ class DeploysController &lt; ApplicationController
12 12 end
13 13  
14 14 def index
15   - # See AppsController#find_app for the reasoning behind this code.
16   - app = App.find(params[:app_id])
17   - raise Mongoid::Errors::DocumentNotFound.new(App, app.id) unless current_user.admin? || current_user.watching?(app)
18   -
19   - @deploys = Kaminari.paginate_array(app.deploys.order_by(:created_at.desc)).
  15 + @app = App.find(params[:app_id])
  16 + @deploys = Kaminari.paginate_array(@app.deploys.order_by(:created_at.desc)).
20 17 page(params[:page]).per(10)
21   - @app = app
22 18 end
23 19  
24 20 private
... ...
app/controllers/problems_controller.rb
... ... @@ -13,8 +13,7 @@ class ProblemsController &lt; ApplicationController
13 13 ]
14 14  
15 15 expose(:app_scope) {
16   - apps = current_user.admin? ? App.all : current_user.apps
17   - params[:app_id] ? apps.where(:_id => params[:app_id]) : apps
  16 + params[:app_id] ? App.where(:_id => params[:app_id]) : App.all
18 17 }
19 18  
20 19 expose(:app) {
... ... @@ -34,11 +33,11 @@ class ProblemsController &lt; ApplicationController
34 33 }
35 34  
36 35 expose(:problems) {
37   - pro = Problem.for_apps(
38   - app_scope
39   - ).in_env(
40   - params_environement
41   - ).all_else_unresolved(all_errs).ordered_by(params_sort, params_order)
  36 + pro = Problem
  37 + .for_apps(app_scope)
  38 + .in_env(params_environement)
  39 + .all_else_unresolved(all_errs)
  40 + .ordered_by(params_sort, params_order)
42 41  
43 42 if request.format == :html
44 43 pro.page(params[:page]).per(current_user.per_page)
... ...
app/controllers/watchers_controller.rb
... ... @@ -5,23 +5,16 @@ class WatchersController &lt; ApplicationController
5 5 App.find(params[:app_id])
6 6 end
7 7  
8   - expose(:watcher) do
9   - app.watchers.where(:user_id => params[:id]).first
10   - end
11   -
12   - before_action :require_watcher_edit_priviledges, :only => [:destroy]
13   -
14 8 def destroy
  9 + watcher = app.watchers.where(:user_id => params[:id]).first
15 10 app.watchers.delete(watcher)
16   - flash[:success] = "That's sad. #{watcher.label} is no longer watcher."
17   - redirect_to root_path
  11 + flash[:success] = t('.success', app: app.name)
  12 + redirect_to app_path(app)
18 13 end
19 14  
20   - private
21   -
22   - def require_watcher_edit_priviledges
23   - redirect_to(root_path) unless current_user == watcher.user || current_user.admin?
  15 + def update
  16 + app.watchers.create(user_id: current_user.id)
  17 + flash[:success] = t('.success', app: app.name)
  18 + redirect_to app_path(app)
24 19 end
25   -
26 20 end
27   -
... ...
app/interactors/user_destroy.rb
... ... @@ -4,8 +4,11 @@ class UserDestroy
4 4 end
5 5  
6 6 def destroy
  7 + App.watched_by(@user).each do |app|
  8 + watcher = app.watchers.where(user_id: @user.id).first
  9 + app.watchers.delete(watcher)
  10 + end
  11 +
7 12 @user.destroy
8   - @user.watchers.each(&:destroy)
9 13 end
10   -
11 14 end
... ...
app/models/app.rb
... ... @@ -23,7 +23,6 @@ class App
23 23 pre_processed: true,
24 24 default: ->{ BSON::ObjectId.new.to_s }
25 25  
26   -
27 26 embeds_many :watchers
28 27 embeds_many :deploys
29 28 embeds_one :issue_tracker, :class_name => 'IssueTracker'
... ... @@ -48,6 +47,14 @@ class App
48 47 accepts_nested_attributes_for :notification_service, :allow_destroy => true,
49 48 :reject_if => proc { |attrs| !NotificationService.subclasses.map(&:to_s).include?(attrs[:type].to_s) }
50 49  
  50 + scope :watched_by, ->(user) do
  51 + where watchers: { "$elemMatch" => { "user_id" => user.id } }
  52 + end
  53 +
  54 + def watched_by?(user)
  55 + watchers.pluck("user_id").include? user.id
  56 + end
  57 +
51 58 # Acceps a hash with the following attributes:
52 59 #
53 60 # * <tt>:error_class</tt> - the class of error (required to create a new Problem)
... ...
app/models/user.rb
... ... @@ -41,17 +41,11 @@ class User
41 41 validates_presence_of :name
42 42 validates_uniqueness_of :github_login, :allow_nil => true
43 43  
44   - has_many :apps, :foreign_key => 'watchers.user_id'
45   -
46 44 if Errbit::Config.user_has_username
47 45 field :username
48 46 validates_presence_of :username
49 47 end
50 48  
51   - def watchers
52   - apps.map(&:watchers).flatten.select {|w| w.user_id.to_s == id.to_s}
53   - end
54   -
55 49 def per_page
56 50 super || PER_PAGE
57 51 end
... ...
app/views/apps/_fields.html.haml
... ... @@ -44,21 +44,6 @@
44 44 = f.check_box :notify_all_users
45 45 = f.label :notify_all_users, 'Send notifications to all users'
46 46  
47   -
48   -%fieldset.watchers.nested-wrapper{:style => app_decorate.notify_user_display}
49   - %legend Watchers
50   - = f.fields_for :watchers do |w|
51   - %div.watcher.nested
52   - %div.choose
53   - = w.radio_button :watcher_type, :user
54   - = w.label :watcher_type_user, 'User'
55   - = w.radio_button :watcher_type, :email
56   - = label_tag :watcher_type_email, 'Email Address', :for => label_for_attr(w, 'watcher_type_email')
57   - %div.watcher_params.user{:class => w.object.email.blank? ? 'chosen' : nil}
58   - = w.select :user_id, users.map{|u| [u.name,u.id.to_s]}, :include_blank => '-- Select a User --'
59   - %div.watcher_params.email{:class => w.object.email.present? ? 'chosen' : nil}
60   - = w.text_field :email
61   -
62 47 %div.checkbox
63 48 = f.check_box :resolve_errs_on_deploy
64 49 = f.label :resolve_errs_on_deploy, 'Resolve errs on deploy'
... ...
app/views/apps/show.html.haml
... ... @@ -19,8 +19,11 @@
19 19 - else
20 20 = link_to t('.all_errs'), app_path(app, :all_errs => true), :class => 'button'
21 21  
22   - - if current_user.watching?(app)
23   - = link_to t('.unwatch'), app_watcher_path({app_id: app, id: current_user.id}), method: :delete, class: 'button', data: {confirm: t('.are_you_sure')}
  22 + - if app.watched_by?(current_user)
  23 + = link_to t('.unwatch'), app_watcher_path(app_id: app, id: current_user.id), method: :delete, class: 'button'
  24 + - else
  25 + = link_to t('.watch'), app_watcher_path(app_id: app, id: current_user.id), method: :put, class: 'button'
  26 +
24 27 %h3#watchers_toggle
25 28 =t('.watchers')
26 29 %span.click_span=t('.show_hide')
... ...
config/locales/en.yml
... ... @@ -124,6 +124,7 @@ en:
124 124 unresolved_errs: unresolved errors
125 125 unwatch: unwatch
126 126 user_or_email: User or Email
  127 + watch: watch
127 128 watchers: Watchers
128 129 when: When
129 130 who: Who
... ... @@ -139,4 +140,8 @@ en:
139 140 cancel: 'cancel'
140 141 seriously: 'Seriously?'
141 142 update: 'Update App'
142   -
  143 + watchers:
  144 + destroy:
  145 + success: "You are no longer watching %{app}"
  146 + update:
  147 + success: "You are now watching %{app}"
... ...
config/routes.rb
... ... @@ -42,7 +42,7 @@ Rails.application.routes.draw do
42 42 end
43 43 end
44 44 resources :deploys, :only => [:index]
45   - resources :watchers, :only => [:destroy]
  45 + resources :watchers, :only => [:destroy, :update]
46 46 member do
47 47 post :regenerate_api_key
48 48 end
... ...
public/mockup.html
... ... @@ -1,90 +0,0 @@
1   -<!DOCTYPE html>
2   -<html>
3   - <head>
4   - <title>
5   - Errbit &mdash;
6   - Add App
7   - </title>
8   - <meta content='text/html; charset=utf-8' http-equiv='content-type'>
9   - <meta name="csrf-param" content="authenticity_token"/>
10   - <meta name="csrf-token" content="2xxr2t/FRsJU1jXFRJYSbR/x7dk4jIPwmEhE2sgrWFA="/>
11   - <script src="/javascripts/jquery.js?1281707549" type="text/javascript"></script>
12   - <script src="/javascripts/rails.js?1281707549" type="text/javascript"></script>
13   - <script src="/javascripts/form.js?1281727831" type="text/javascript"></script>
14   - <script src="/javascripts/application.js?1281707549" type="text/javascript"></script>
15   -
16   -
17   - <link href="/stylesheets/reset.css?1281707549" media="screen" rel="stylesheet" type="text/css" />
18   - <link href="/stylesheets/application.css?1281730151" media="screen" rel="stylesheet" type="text/css" />
19   -
20   - <style type="text/css" media="screen">
21   - #app_watchers_attributes_0_user_id,
22   - #app_watchers_attributes_0_email {
23   - display:none;
24   - }
25   - #app_watchers_attributes_0_user_id.show,
26   - #app_watchers_attributes_0_email.show {
27   - display: block;
28   - }
29   - </style>
30   -
31   - </head>
32   - <body class='new' id='apps'>
33   - <div id='header'>
34   - <div>
35   - <a href="/" id="site-name">Errbit</a>
36   - <ul id='session-links'>
37   - <li><a href="/users/sign_out" id="sign-out">Sign out</a></li>
38   - </ul>
39   - </div>
40   - </div>
41   - <div id='nav-bar'>
42   - <ul>
43   - <!-- /%li= link_to 'Dashboard', admin_dashboard_path, :class => active_if_here(:dashboards) -->
44   - <li class='active apps'><a href="/apps">Apps</a></li>
45   - <li class='errs'><a href="/errs">Errs</a></li>
46   - <li class='users'><a href="/users">Users</a></li>
47   - </ul>
48   - <div class='clear'></div>
49   - </div>
50   - <div id='content-wrapper'>
51   - <div id='content-title'>
52   - <h1>Add App</h1>
53   - <span class='meta'></span>
54   - <div id='action-bar'>
55   - <a href="/apps">cancel</a>
56   - </div>
57   - </div>
58   - <div id='content'>
59   -
60   - <form accept-charset="UTF-8" action="/apps" class="new_app" id="new_app" method="post"><div style="margin:0;padding:0;display:inline"><input name="_snowman" type="hidden" value="&#9731;" /><input name="authenticity_token" type="hidden" value="2xxr2t/FRsJU1jXFRJYSbR/x7dk4jIPwmEhE2sgrWFA=" /></div>
61   - <div class='required'>
62   - <label for="app_name">Name</label>
63   - <input id="app_name" name="app[name]" size="30" type="text" />
64   - </div>
65   - <div class='checkbox'>
66   - <input name="app[resolve_errs_on_deploy]" type="hidden" value="0" /><input id="app_resolve_errs_on_deploy" name="app[resolve_errs_on_deploy]" type="checkbox" value="1" />
67   - <label for="app_resolve_errs_on_deploy">Resolve errs on deploy</label>
68   - </div>
69   - <fieldset class='nested-wrapper'>
70   - <legend>Watchers</legend>
71   - <div class='nested'>
72   - <div>
73   - <input type="radio" name="watcher_type" id="watcher_name"/> <label class="inline">Name</label>&nbsp;&nbsp;
74   - <input type="radio" name="watcher_type" id="watcher_email"/> <label class="inline">Email</label><br/><br/>
75   - </div>
76   - <div>
77   - <select id="app_watchers_attributes_0_user_id" name="app[watchers_attributes][0][user_id]"><option value="">-- Select a User --</option>
78   - <option value="4c654f41eacf8d2ae8000001">Errbit Admin</option></select>
79   - <input id="app_watchers_attributes_0_email" name="app[watchers_attributes][0][email]" size="30" type="text" />
80   - </div>
81   - </div>
82   - </fieldset>
83   - <div class='add_app'><input id="app_submit" name="commit" type="submit" value="Add" /></div>
84   - </form>
85   - </div>
86   - </div>
87   - <div id='footer'>Powered by <a href="http://github.com/errbit/errbit" target="_blank">Errbit</a>: the open source Hoptoad server.</div>
88   -
89   - </body>
90   -</html>
spec/acceptance/watch_unwatch_app_spec.rb
1 1 require 'acceptance/acceptance_helper'
2 2  
3 3 feature 'A user can watch and unwatch an application' do
4   -
5 4 let!(:app) { Fabricate(:app) }
6   - let!(:user) do
7   - user = Fabricate(:user)
8   - app.watchers.create!(
9   - :user_id => user.id
10   - )
  5 + let!(:user) { Fabricate(:user) }
  6 +
  7 + scenario 'log in and unwatch a project' do
  8 + app.watchers.create!(user_id: user.id)
11 9 user.reload
12   - end
13 10  
14   - scenario 'log in watch a project and unwatch it' do
15 11 log_in user
  12 + click_on app.name
16 13 click_on I18n.t('apps.show.unwatch')
17   - expect(page).to have_content(I18n.t('apps.index.no_apps'))
  14 + expect(page).to have_content(
  15 + I18n.t('watchers.destroy.success', app: app.name))
18 16 end
19 17  
  18 + scenario 'log in and watch a project' do
  19 + log_in user
  20 + click_on app.name
  21 + click_on I18n.t('apps.show.watch')
  22 + expect(page).to have_content(
  23 + I18n.t('watchers.update.success', app: app.name))
  24 + end
20 25 end
... ...
spec/controllers/apps_controller_spec.rb
... ... @@ -39,12 +39,11 @@ describe AppsController, type: &#39;controller&#39; do
39 39 end
40 40  
41 41 context 'when logged in as a regular user' do
42   - it 'finds apps the user is watching' do
43   - sign_in(user)
44   - watched_app1 && watched_app2 && unwatched_app
  42 + it 'finds all apps' do
  43 + sign_in user
  44 + unwatched_app && watched_app1 && watched_app2
45 45 get :index
46   - expect(controller.apps).to include(watched_app1, watched_app2)
47   - expect(controller.apps).to_not include(unwatched_app)
  46 + expect(controller.apps.entries).to eq App.all.sort.entries
48 47 end
49 48 end
50 49 end
... ... @@ -163,19 +162,12 @@ describe AppsController, type: &#39;controller&#39; do
163 162 end
164 163  
165 164 context 'logged in as a user' do
166   - it 'finds the app if the user is watching it' do
167   - watcher
168   - sign_in user
169   - get :show, :id => app.id
170   - expect(controller.app).to eq app
171   - end
172   -
173   - it 'does not find the app if the user is not watching it' do
  165 + it 'finds the app even when not watching it' do
174 166 sign_in Fabricate(:user)
175 167 app = Fabricate(:app)
176   - expect{
177   - get :show, :id => app.id
178   - }.to raise_error(Mongoid::Errors::DocumentNotFound)
  168 +
  169 + get :show, :id => app.id
  170 + expect(controller.app).to eq app
179 171 end
180 172 end
181 173 end
... ...
spec/controllers/devise_sessions_controller_spec.rb
... ... @@ -14,12 +14,6 @@ describe Devise::SessionsController, type: &#39;controller&#39; do
14 14 expect(response).to redirect_to(root_path)
15 15 end
16 16  
17   - it 'redirects to app page if there is app for the user' do
18   - Fabricate(:user_watcher, :app => app, :user => user)
19   - post :create, { :user => { 'email' => user.email, 'password' => user.password } }
20   - expect(response).to redirect_to(app_path(app))
21   - end
22   -
23 17 it 'displays a friendly error when credentials are invalid' do
24 18 post :create, { :user => { 'email' => 'whatever', 'password' => 'somethinginvalid' } }
25 19 expect(request.flash["alert"]).to eq(I18n.t 'devise.failure.user.email_invalid')
... ...
spec/controllers/problems_controller_spec.rb
... ... @@ -6,122 +6,94 @@ describe ProblemsController, type: &#39;controller&#39; do
6 6  
7 7 let(:app) { Fabricate(:app) }
8 8 let(:err) { Fabricate(:err, :problem => problem) }
9   - let(:admin) { Fabricate(:admin) }
  9 + let(:user) { Fabricate(:user) }
10 10 let(:problem) { Fabricate(:problem, :app => app, :environment => "production") }
11 11  
12 12 describe "GET /problems" do
13   - context 'when logged in as an admin' do
  13 + before(:each) do
  14 + sign_in user
  15 + @problem = Fabricate(:notice, :err => Fabricate(:err, :problem => Fabricate(:problem, :app => app, :environment => "production"))).problem
  16 + end
  17 +
  18 + context "pagination" do
14 19 before(:each) do
15   - sign_in admin
16   - @problem = Fabricate(:notice, :err => Fabricate(:err, :problem => Fabricate(:problem, :app => app, :environment => "production"))).problem
  20 + 35.times { Fabricate :err }
17 21 end
18 22  
19   - context "pagination" do
20   - before(:each) do
21   - 35.times { Fabricate :err }
22   - end
23   -
24   - it "should have default per_page value for user" do
25   - get :index
26   - expect(controller.problems.to_a.size).to eq User::PER_PAGE
27   - end
28   -
29   - it "should be able to override default per_page value" do
30   - admin.update_attribute :per_page, 10
31   - get :index
32   - expect(controller.problems.to_a.size).to eq 10
33   - end
  23 + it "should have default per_page value for user" do
  24 + get :index
  25 + expect(controller.problems.to_a.size).to eq User::PER_PAGE
34 26 end
35 27  
36   - context 'with environment filters' do
37   - before(:each) do
38   - environments = ['production', 'test', 'development', 'staging']
39   - 20.times do |i|
40   - Fabricate(:problem, :environment => environments[i % environments.length])
41   - end
42   - end
  28 + it "should be able to override default per_page value" do
  29 + user.update_attribute :per_page, 10
  30 + get :index
  31 + expect(controller.problems.to_a.size).to eq 10
  32 + end
  33 + end
43 34  
44   - context 'no params' do
45   - it 'shows problems for all environments' do
46   - get :index
47   - expect(controller.problems.size).to eq 21
48   - end
  35 + context 'with environment filters' do
  36 + before(:each) do
  37 + environments = ['production', 'test', 'development', 'staging']
  38 + 20.times do |i|
  39 + Fabricate(:problem, :environment => environments[i % environments.length])
49 40 end
  41 + end
50 42  
51   - context 'environment production' do
52   - it 'shows problems for just production' do
53   - get :index, :environment => 'production'
54   - expect(controller.problems.size).to eq 6
55   - end
  43 + context 'no params' do
  44 + it 'shows problems for all environments' do
  45 + get :index
  46 + expect(controller.problems.size).to eq 21
56 47 end
  48 + end
57 49  
58   - context 'environment staging' do
59   - it 'shows problems for just staging' do
60   - get :index, :environment => 'staging'
61   - expect(controller.problems.size).to eq 5
62   - end
  50 + context 'environment production' do
  51 + it 'shows problems for just production' do
  52 + get :index, :environment => 'production'
  53 + expect(controller.problems.size).to eq 6
63 54 end
  55 + end
64 56  
65   - context 'environment development' do
66   - it 'shows problems for just development' do
67   - get :index, :environment => 'development'
68   - expect(controller.problems.size).to eq 5
69   - end
  57 + context 'environment staging' do
  58 + it 'shows problems for just staging' do
  59 + get :index, :environment => 'staging'
  60 + expect(controller.problems.size).to eq 5
70 61 end
  62 + end
71 63  
72   - context 'environment test' do
73   - it 'shows problems for just test' do
74   - get :index, :environment => 'test'
75   - expect(controller.problems.size).to eq 5
76   - end
  64 + context 'environment development' do
  65 + it 'shows problems for just development' do
  66 + get :index, :environment => 'development'
  67 + expect(controller.problems.size).to eq 5
77 68 end
78 69 end
79   - end
80 70  
81   - context 'when logged in as a user' do
82   - it 'gets a paginated list of unresolved problems for the users apps' do
83   - sign_in(user = Fabricate(:user))
84   - unwatched_err = Fabricate(:err)
85   - watched_unresolved_err = Fabricate(:err, :problem => Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => false))
86   - watched_resolved_err = Fabricate(:err, :problem => Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => true))
87   - get :index
88   - expect(controller.problems).to include(watched_unresolved_err.problem)
89   - expect(controller.problems).to_not include(unwatched_err.problem, watched_resolved_err.problem)
  71 + context 'environment test' do
  72 + it 'shows problems for just test' do
  73 + get :index, :environment => 'test'
  74 + expect(controller.problems.size).to eq 5
  75 + end
90 76 end
91 77 end
92 78 end
93 79  
94 80 describe "GET /problems - previously all" do
95   - context 'when logged in as an admin' do
96   - it "gets a paginated list of all problems" do
97   - sign_in admin
98   - problems = Kaminari.paginate_array((1..30).to_a)
99   - 3.times { problems << Fabricate(:err).problem }
100   - 3.times { problems << Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem }
101   - expect(Problem).to receive(:ordered_by).and_return(
102   - double('proxy', :page => double('other_proxy', :per => problems))
103   - )
104   - get :index, :all_errs => true
105   - expect(controller.problems).to eq problems
106   - end
107   - end
108   -
109   - context 'when logged in as a user' do
110   - it 'gets a paginated list of all problems for the users apps' do
111   - sign_in(user = Fabricate(:user))
112   - unwatched_problem = Fabricate(:problem)
113   - watched_unresolved_problem = Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => false)
114   - watched_resolved_problem = Fabricate(:problem, :app => Fabricate(:user_watcher, :user => user).app, :resolved => true)
115   - get :index, :all_errs => true
116   - expect(controller.problems).to include(watched_resolved_problem, watched_unresolved_problem)
117   - expect(controller.problems).to_not include(unwatched_problem)
118   - end
  81 + it "gets a paginated list of all problems" do
  82 + sign_in Fabricate(:user)
  83 + problems = Kaminari.paginate_array((1..30).to_a)
  84 + 3.times { problems << Fabricate(:err).problem }
  85 + 3.times { problems << Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem }
  86 + expect(Problem).to receive(:ordered_by).and_return(
  87 + double('proxy', :page => double('other_proxy', :per => problems))
  88 + )
  89 + get :index, :all_errs => true
  90 + expect(controller.problems).to eq problems
119 91 end
120 92 end
121 93  
122 94 describe "GET /problems/search" do
123 95 before do
124   - sign_in Fabricate(:admin)
  96 + sign_in user
125 97 @app = Fabricate(:app)
126 98 @problem1 = Fabricate(:problem, :app=>@app, message: "Most important")
127 99 @problem2 = Fabricate(:problem, :app=>@app, message: "Very very important")
... ... @@ -145,73 +117,49 @@ describe ProblemsController, type: &#39;controller&#39; do
145 117 end
146 118  
147 119 describe "GET /apps/:app_id/problems/:id" do
148   - context 'when logged in as an admin' do
149   - before do
150   - sign_in admin
151   - end
152   -
153   - it "finds the app" do
154   - get :show, :app_id => app.id, :id => err.problem.id
155   - expect(controller.app).to eq app
156   - end
157   -
158   - it "finds the problem" do
159   - get :show, :app_id => app.id, :id => err.problem.id
160   - expect(controller.problem).to eq err.problem
161   - end
162   -
163   - it "successfully render page" do
164   - get :show, :app_id => app.id, :id => err.problem.id
165   - expect(response).to be_success
166   - end
167   -
168   - context 'pagination' do
169   - let!(:notices) do
170   - 3.times.reduce([]) do |coll, i|
171   - coll << Fabricate(:notice, :err => err, :created_at => (Time.now + i))
172   - end
173   - end
  120 + before do
  121 + sign_in user
  122 + end
174 123  
175   - it "paginates the notices 1 at a time, starting with the most recent" do
176   - get :show, :app_id => app.id, :id => err.problem.id
177   - expect(assigns(:notices).entries.count).to eq 1
178   - expect(assigns(:notices)).to include(notices.last)
179   - end
  124 + it "finds the app" do
  125 + get :show, :app_id => app.id, :id => err.problem.id
  126 + expect(controller.app).to eq app
  127 + end
180 128  
181   - it "paginates the notices 1 at a time, based on then notice param" do
182   - get :show, :app_id => app.id, :id => err.problem.id, :notice => 3
183   - expect(assigns(:notices).entries.count).to eq 1
184   - expect(assigns(:notices)).to include(notices.first)
185   - end
186   - end
  129 + it "finds the problem" do
  130 + get :show, :app_id => app.id, :id => err.problem.id
  131 + expect(controller.problem).to eq err.problem
  132 + end
187 133  
  134 + it "successfully render page" do
  135 + get :show, :app_id => app.id, :id => err.problem.id
  136 + expect(response).to be_success
188 137 end
189 138  
190   - context 'when logged in as a user' do
191   - before do
192   - sign_in(@user = Fabricate(:user))
193   - @unwatched_err = Fabricate(:err)
194   - @watched_app = Fabricate(:app)
195   - @watcher = Fabricate(:user_watcher, :user => @user, :app => @watched_app)
196   - @watched_err = Fabricate(:err, :problem => Fabricate(:problem, :app => @watched_app))
  139 + context 'pagination' do
  140 + let!(:notices) do
  141 + 3.times.reduce([]) do |coll, i|
  142 + coll << Fabricate(:notice, :err => err, :created_at => (Time.now + i))
  143 + end
197 144 end
198 145  
199   - it 'finds the problem if the user is watching the app' do
200   - get :show, :app_id => @watched_app.to_param, :id => @watched_err.problem.id
201   - expect(controller.problem).to eq @watched_err.problem
  146 + it "paginates the notices 1 at a time, starting with the most recent" do
  147 + get :show, :app_id => app.id, :id => err.problem.id
  148 + expect(assigns(:notices).entries.count).to eq 1
  149 + expect(assigns(:notices)).to include(notices.last)
202 150 end
203 151  
204   - it 'raises a DocumentNotFound error if the user is not watching the app' do
205   - expect {
206   - get :show, :app_id => @unwatched_err.problem.app_id, :id => @unwatched_err.problem.id
207   - }.to raise_error(Mongoid::Errors::DocumentNotFound)
  152 + it "paginates the notices 1 at a time, based on then notice param" do
  153 + get :show, :app_id => app.id, :id => err.problem.id, :notice => 3
  154 + expect(assigns(:notices).entries.count).to eq 1
  155 + expect(assigns(:notices)).to include(notices.first)
208 156 end
209 157 end
210 158 end
211 159  
212 160 describe "PUT /apps/:app_id/problems/:id/resolve" do
213 161 before do
214   - sign_in admin
  162 + sign_in user
215 163  
216 164 @err = Fabricate(:err)
217 165 end
... ... @@ -245,7 +193,7 @@ describe ProblemsController, type: &#39;controller&#39; do
245 193 end
246 194  
247 195 describe "POST /apps/:app_id/problems/:id/create_issue" do
248   - before { sign_in admin }
  196 + before { sign_in user }
249 197  
250 198 context "when app has a issue tracker" do
251 199 let(:notice) { NoticeDecorator.new(Fabricate :notice) }
... ... @@ -259,7 +207,7 @@ describe ProblemsController, type: &#39;controller&#39; do
259 207 before do
260 208 problem.app.issue_tracker = issue_tracker
261 209 allow(controller).to receive(:problem).and_return(problem)
262   - allow(controller).to receive(:current_user).and_return(admin)
  210 + allow(controller).to receive(:current_user).and_return(user)
263 211 end
264 212  
265 213 it "should redirect to problem page" do
... ... @@ -316,7 +264,7 @@ describe ProblemsController, type: &#39;controller&#39; do
316 264  
317 265 describe "DELETE /apps/:app_id/problems/:id/unlink_issue" do
318 266 before(:each) do
319   - sign_in admin
  267 + sign_in user
320 268 end
321 269  
322 270 context "problem with issue" do
... ... @@ -352,7 +300,7 @@ describe ProblemsController, type: &#39;controller&#39; do
352 300  
353 301 describe "Bulk Actions" do
354 302 before(:each) do
355   - sign_in admin
  303 + sign_in user
356 304 @problem1 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem
357 305 @problem2 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => false)).problem
358 306 end
... ... @@ -434,7 +382,7 @@ describe ProblemsController, type: &#39;controller&#39; do
434 382  
435 383 describe "POST /apps/:app_id/problems/destroy_all" do
436 384 before do
437   - sign_in Fabricate(:admin)
  385 + sign_in user
438 386 @app = Fabricate(:app)
439 387 @problem1 = Fabricate(:problem, :app=>@app)
440 388 @problem2 = Fabricate(:problem, :app=>@app)
... ...
spec/controllers/watchers_controller_spec.rb
1 1 describe WatchersController, type: 'controller' do
2   - let(:app) do
3   - a = Fabricate(:app)
4   - Fabricate(:user_watcher, :app => a)
5   - a
6   - end
  2 + let(:user) { Fabricate(:user) }
  3 + let(:problem) { Fabricate(:problem) }
  4 +
  5 + before(:each) { sign_in user }
  6 +
  7 + describe "#destroy" do
  8 + let(:app) do
  9 + a = Fabricate(:app)
  10 + Fabricate(:user_watcher, app: a, user: user)
  11 + a
  12 + end
  13 +
  14 + context "successful watcher deletion" do
  15 + let(:watcher) { app.watchers.first }
7 16  
8   - describe "DELETE /apps/:app_id/watchers/:id/destroy" do
9   - context "with admin user" do
10 17 before(:each) do
11   - sign_in Fabricate(:admin)
  18 + delete :destroy, :app_id => app.id, :id => watcher.user.id.to_s
  19 + problem.reload
  20 + end
  21 +
  22 + it "should delete the watcher" do
  23 + expect(app.watchers.detect{|w| w.id.to_s == watcher.id }).to be nil
12 24 end
13 25  
14   - context "successful watcher deletion" do
15   - let(:problem) { Fabricate(:problem_with_comments) }
16   - let(:watcher) { app.watchers.first }
  26 + it "should redirect to app page" do
  27 + expect(response).to redirect_to(app_path(app))
  28 + end
  29 + end
  30 + end
17 31  
18   - before(:each) do
19   - delete :destroy, :app_id => app.id, :id => watcher.user.id.to_s
20   - problem.reload
21   - end
  32 + describe "#update" do
  33 + let(:app) { Fabricate(:app) }
22 34  
23   - it "should delete the watcher" do
24   - expect(app.watchers.detect{|w| w.id.to_s == watcher.id }).to be nil
25   - end
  35 + context "successful watcher update" do
  36 + before(:each) do
  37 + put :update, :app_id => app.id, :id => user.id.to_s
  38 + problem.reload
  39 + end
  40 +
  41 + it "should be watching" do
  42 + app.reload
  43 + expect(app.watchers.first.user_id).to eq user.id
  44 + end
26 45  
27   - it "should redirect to index page" do
28   - expect(response).to redirect_to(root_path)
29   - end
  46 + it "should redirect to app page" do
  47 + expect(response).to redirect_to(app_path(app))
30 48 end
31 49 end
32 50 end
... ...
spec/models/user_spec.rb
... ... @@ -37,24 +37,6 @@ describe User do
37 37 end
38 38 end
39 39  
40   - context 'Watchers' do
41   - it 'has many watchers' do
42   - user = Fabricate(:user)
43   - watcher = Fabricate(:user_watcher, :user => user)
44   - expect(user.watchers).to_not be_empty
45   - expect(user.watchers).to include(watcher)
46   - end
47   -
48   - it "has many apps through watchers" do
49   - user = Fabricate(:user)
50   - watched_app = Fabricate(:app)
51   - unwatched_app = Fabricate(:app)
52   - Fabricate(:user_watcher, :app => watched_app, :user => user)
53   - expect(user.apps.all).to include(watched_app)
54   - expect(user.apps.all).to_not include(unwatched_app)
55   - end
56   - end
57   -
58 40 context "First user" do
59 41 it "should be created this admin access via db:seed" do
60 42 expect {
... ...
spec/views/apps/show.html.haml_spec.rb
... ... @@ -30,7 +30,7 @@ describe &quot;apps/show.html.haml&quot;, type: &#39;view&#39; do
30 30  
31 31 context "with user watch application" do
32 32 before do
33   - allow(user).to receive(:watching?).with(app).and_return(true)
  33 + allow(app).to receive(:watched_by?).with(user).and_return(true)
34 34 end
35 35 it 'see the unwatch button' do
36 36 render
... ... @@ -40,7 +40,7 @@ describe &quot;apps/show.html.haml&quot;, type: &#39;view&#39; do
40 40  
41 41 context "with user not watch application" do
42 42 before do
43   - allow(user).to receive(:watching?).with(app).and_return(false)
  43 + allow(app).to receive(:watched_by?).with(user).and_return(false)
44 44 end
45 45 it 'not see the unwatch button' do
46 46 render
... ...