Commit 74429ae687c8acc36ce17c307d669a8e0345ed4e

Authored by Stephen Crosby
1 parent 0ff2eb5a
Exists in master and in 1 other branch production

Refs #561 users can see all apps

In the past users could only follow apps if an admin did it for them.
But now users can follow and unfollow any apps. Following an app is no
longer like a permission to view that app.
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
... ...