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,8 +540,8 @@ a.button.active {
540 display: inline-block; 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 display: none; 545 display: none;
546 } 546 }
547 547
app/controllers/application_controller.rb
@@ -5,13 +5,6 @@ class ApplicationController < ActionController::Base @@ -5,13 +5,6 @@ class ApplicationController < ActionController::Base
5 before_action :authenticate_user! 5 before_action :authenticate_user!
6 before_action :set_time_zone 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 rescue_from ActionController::RedirectBackError, :with => :redirect_to_root 8 rescue_from ActionController::RedirectBackError, :with => :redirect_to_root
16 9
17 class StrongParametersWithEagerAttributesStrategy < DecentExposure::StrongParametersStrategy 10 class StrongParametersWithEagerAttributesStrategy < DecentExposure::StrongParametersStrategy
app/controllers/apps_controller.rb
@@ -7,9 +7,7 @@ class AppsController &lt; ApplicationController @@ -7,9 +7,7 @@ class AppsController &lt; ApplicationController
7 before_action :parse_notice_at_notices_or_set_default, :only => [:create, :update] 7 before_action :parse_notice_at_notices_or_set_default, :only => [:create, :update]
8 respond_to :html 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 expose(:apps) { 12 expose(:apps) {
15 app_scope.asc(:name).map { |app| AppDecorator.new(app) } 13 app_scope.asc(:name).map { |app| AppDecorator.new(app) }
app/controllers/comments_controller.rb
@@ -27,10 +27,6 @@ class CommentsController &lt; ApplicationController @@ -27,10 +27,6 @@ class CommentsController &lt; ApplicationController
27 protected 27 protected
28 def find_app 28 def find_app
29 @app = App.find(params[:app_id]) 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 end 30 end
35 31
36 def find_problem 32 def find_problem
app/controllers/deploys_controller.rb
@@ -12,13 +12,9 @@ class DeploysController &lt; ApplicationController @@ -12,13 +12,9 @@ class DeploysController &lt; ApplicationController
12 end 12 end
13 13
14 def index 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 page(params[:page]).per(10) 17 page(params[:page]).per(10)
21 - @app = app  
22 end 18 end
23 19
24 private 20 private
app/controllers/problems_controller.rb
@@ -13,8 +13,7 @@ class ProblemsController &lt; ApplicationController @@ -13,8 +13,7 @@ class ProblemsController &lt; ApplicationController
13 ] 13 ]
14 14
15 expose(:app_scope) { 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 expose(:app) { 19 expose(:app) {
@@ -34,11 +33,11 @@ class ProblemsController &lt; ApplicationController @@ -34,11 +33,11 @@ class ProblemsController &lt; ApplicationController
34 } 33 }
35 34
36 expose(:problems) { 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 if request.format == :html 42 if request.format == :html
44 pro.page(params[:page]).per(current_user.per_page) 43 pro.page(params[:page]).per(current_user.per_page)
app/controllers/watchers_controller.rb
@@ -5,23 +5,16 @@ class WatchersController &lt; ApplicationController @@ -5,23 +5,16 @@ class WatchersController &lt; ApplicationController
5 App.find(params[:app_id]) 5 App.find(params[:app_id])
6 end 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 def destroy 8 def destroy
  9 + watcher = app.watchers.where(:user_id => params[:id]).first
15 app.watchers.delete(watcher) 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 end 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 end 19 end
25 -  
26 end 20 end
27 -  
app/interactors/user_destroy.rb
@@ -4,8 +4,11 @@ class UserDestroy @@ -4,8 +4,11 @@ class UserDestroy
4 end 4 end
5 5
6 def destroy 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 @user.destroy 12 @user.destroy
8 - @user.watchers.each(&:destroy)  
9 end 13 end
10 -  
11 end 14 end
app/models/app.rb
@@ -23,7 +23,6 @@ class App @@ -23,7 +23,6 @@ class App
23 pre_processed: true, 23 pre_processed: true,
24 default: ->{ BSON::ObjectId.new.to_s } 24 default: ->{ BSON::ObjectId.new.to_s }
25 25
26 -  
27 embeds_many :watchers 26 embeds_many :watchers
28 embeds_many :deploys 27 embeds_many :deploys
29 embeds_one :issue_tracker, :class_name => 'IssueTracker' 28 embeds_one :issue_tracker, :class_name => 'IssueTracker'
@@ -48,6 +47,14 @@ class App @@ -48,6 +47,14 @@ class App
48 accepts_nested_attributes_for :notification_service, :allow_destroy => true, 47 accepts_nested_attributes_for :notification_service, :allow_destroy => true,
49 :reject_if => proc { |attrs| !NotificationService.subclasses.map(&:to_s).include?(attrs[:type].to_s) } 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 # Acceps a hash with the following attributes: 58 # Acceps a hash with the following attributes:
52 # 59 #
53 # * <tt>:error_class</tt> - the class of error (required to create a new Problem) 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,17 +41,11 @@ class User
41 validates_presence_of :name 41 validates_presence_of :name
42 validates_uniqueness_of :github_login, :allow_nil => true 42 validates_uniqueness_of :github_login, :allow_nil => true
43 43
44 - has_many :apps, :foreign_key => 'watchers.user_id'  
45 -  
46 if Errbit::Config.user_has_username 44 if Errbit::Config.user_has_username
47 field :username 45 field :username
48 validates_presence_of :username 46 validates_presence_of :username
49 end 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 def per_page 49 def per_page
56 super || PER_PAGE 50 super || PER_PAGE
57 end 51 end
app/views/apps/_fields.html.haml
@@ -44,21 +44,6 @@ @@ -44,21 +44,6 @@
44 = f.check_box :notify_all_users 44 = f.check_box :notify_all_users
45 = f.label :notify_all_users, 'Send notifications to all users' 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 %div.checkbox 47 %div.checkbox
63 = f.check_box :resolve_errs_on_deploy 48 = f.check_box :resolve_errs_on_deploy
64 = f.label :resolve_errs_on_deploy, 'Resolve errs on deploy' 49 = f.label :resolve_errs_on_deploy, 'Resolve errs on deploy'
app/views/apps/show.html.haml
@@ -19,8 +19,11 @@ @@ -19,8 +19,11 @@
19 - else 19 - else
20 = link_to t('.all_errs'), app_path(app, :all_errs => true), :class => 'button' 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 %h3#watchers_toggle 27 %h3#watchers_toggle
25 =t('.watchers') 28 =t('.watchers')
26 %span.click_span=t('.show_hide') 29 %span.click_span=t('.show_hide')
config/locales/en.yml
@@ -124,6 +124,7 @@ en: @@ -124,6 +124,7 @@ en:
124 unresolved_errs: unresolved errors 124 unresolved_errs: unresolved errors
125 unwatch: unwatch 125 unwatch: unwatch
126 user_or_email: User or Email 126 user_or_email: User or Email
  127 + watch: watch
127 watchers: Watchers 128 watchers: Watchers
128 when: When 129 when: When
129 who: Who 130 who: Who
@@ -139,4 +140,8 @@ en: @@ -139,4 +140,8 @@ en:
139 cancel: 'cancel' 140 cancel: 'cancel'
140 seriously: 'Seriously?' 141 seriously: 'Seriously?'
141 update: 'Update App' 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,7 +42,7 @@ Rails.application.routes.draw do
42 end 42 end
43 end 43 end
44 resources :deploys, :only => [:index] 44 resources :deploys, :only => [:index]
45 - resources :watchers, :only => [:destroy] 45 + resources :watchers, :only => [:destroy, :update]
46 member do 46 member do
47 post :regenerate_api_key 47 post :regenerate_api_key
48 end 48 end
public/mockup.html
@@ -1,90 +0,0 @@ @@ -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 require 'acceptance/acceptance_helper' 1 require 'acceptance/acceptance_helper'
2 2
3 feature 'A user can watch and unwatch an application' do 3 feature 'A user can watch and unwatch an application' do
4 -  
5 let!(:app) { Fabricate(:app) } 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 user.reload 9 user.reload
12 - end  
13 10
14 - scenario 'log in watch a project and unwatch it' do  
15 log_in user 11 log_in user
  12 + click_on app.name
16 click_on I18n.t('apps.show.unwatch') 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 end 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 end 25 end
spec/controllers/apps_controller_spec.rb
@@ -39,12 +39,11 @@ describe AppsController, type: &#39;controller&#39; do @@ -39,12 +39,11 @@ describe AppsController, type: &#39;controller&#39; do
39 end 39 end
40 40
41 context 'when logged in as a regular user' do 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 get :index 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 end 47 end
49 end 48 end
50 end 49 end
@@ -163,19 +162,12 @@ describe AppsController, type: &#39;controller&#39; do @@ -163,19 +162,12 @@ describe AppsController, type: &#39;controller&#39; do
163 end 162 end
164 163
165 context 'logged in as a user' do 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 sign_in Fabricate(:user) 166 sign_in Fabricate(:user)
175 app = Fabricate(:app) 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 end 171 end
180 end 172 end
181 end 173 end
spec/controllers/devise_sessions_controller_spec.rb
@@ -14,12 +14,6 @@ describe Devise::SessionsController, type: &#39;controller&#39; do @@ -14,12 +14,6 @@ describe Devise::SessionsController, type: &#39;controller&#39; do
14 expect(response).to redirect_to(root_path) 14 expect(response).to redirect_to(root_path)
15 end 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 it 'displays a friendly error when credentials are invalid' do 17 it 'displays a friendly error when credentials are invalid' do
24 post :create, { :user => { 'email' => 'whatever', 'password' => 'somethinginvalid' } } 18 post :create, { :user => { 'email' => 'whatever', 'password' => 'somethinginvalid' } }
25 expect(request.flash["alert"]).to eq(I18n.t 'devise.failure.user.email_invalid') 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,122 +6,94 @@ describe ProblemsController, type: &#39;controller&#39; do
6 6
7 let(:app) { Fabricate(:app) } 7 let(:app) { Fabricate(:app) }
8 let(:err) { Fabricate(:err, :problem => problem) } 8 let(:err) { Fabricate(:err, :problem => problem) }
9 - let(:admin) { Fabricate(:admin) } 9 + let(:user) { Fabricate(:user) }
10 let(:problem) { Fabricate(:problem, :app => app, :environment => "production") } 10 let(:problem) { Fabricate(:problem, :app => app, :environment => "production") }
11 11
12 describe "GET /problems" do 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 before(:each) do 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 end 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 end 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 end 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 end 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 end 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 end 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 end 68 end
78 end 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 end 76 end
91 end 77 end
92 end 78 end
93 79
94 describe "GET /problems - previously all" do 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 end 91 end
120 end 92 end
121 93
122 describe "GET /problems/search" do 94 describe "GET /problems/search" do
123 before do 95 before do
124 - sign_in Fabricate(:admin) 96 + sign_in user
125 @app = Fabricate(:app) 97 @app = Fabricate(:app)
126 @problem1 = Fabricate(:problem, :app=>@app, message: "Most important") 98 @problem1 = Fabricate(:problem, :app=>@app, message: "Most important")
127 @problem2 = Fabricate(:problem, :app=>@app, message: "Very very important") 99 @problem2 = Fabricate(:problem, :app=>@app, message: "Very very important")
@@ -145,73 +117,49 @@ describe ProblemsController, type: &#39;controller&#39; do @@ -145,73 +117,49 @@ describe ProblemsController, type: &#39;controller&#39; do
145 end 117 end
146 118
147 describe "GET /apps/:app_id/problems/:id" do 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 end 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 end 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 end 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 end 156 end
209 end 157 end
210 end 158 end
211 159
212 describe "PUT /apps/:app_id/problems/:id/resolve" do 160 describe "PUT /apps/:app_id/problems/:id/resolve" do
213 before do 161 before do
214 - sign_in admin 162 + sign_in user
215 163
216 @err = Fabricate(:err) 164 @err = Fabricate(:err)
217 end 165 end
@@ -245,7 +193,7 @@ describe ProblemsController, type: &#39;controller&#39; do @@ -245,7 +193,7 @@ describe ProblemsController, type: &#39;controller&#39; do
245 end 193 end
246 194
247 describe "POST /apps/:app_id/problems/:id/create_issue" do 195 describe "POST /apps/:app_id/problems/:id/create_issue" do
248 - before { sign_in admin } 196 + before { sign_in user }
249 197
250 context "when app has a issue tracker" do 198 context "when app has a issue tracker" do
251 let(:notice) { NoticeDecorator.new(Fabricate :notice) } 199 let(:notice) { NoticeDecorator.new(Fabricate :notice) }
@@ -259,7 +207,7 @@ describe ProblemsController, type: &#39;controller&#39; do @@ -259,7 +207,7 @@ describe ProblemsController, type: &#39;controller&#39; do
259 before do 207 before do
260 problem.app.issue_tracker = issue_tracker 208 problem.app.issue_tracker = issue_tracker
261 allow(controller).to receive(:problem).and_return(problem) 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 end 211 end
264 212
265 it "should redirect to problem page" do 213 it "should redirect to problem page" do
@@ -316,7 +264,7 @@ describe ProblemsController, type: &#39;controller&#39; do @@ -316,7 +264,7 @@ describe ProblemsController, type: &#39;controller&#39; do
316 264
317 describe "DELETE /apps/:app_id/problems/:id/unlink_issue" do 265 describe "DELETE /apps/:app_id/problems/:id/unlink_issue" do
318 before(:each) do 266 before(:each) do
319 - sign_in admin 267 + sign_in user
320 end 268 end
321 269
322 context "problem with issue" do 270 context "problem with issue" do
@@ -352,7 +300,7 @@ describe ProblemsController, type: &#39;controller&#39; do @@ -352,7 +300,7 @@ describe ProblemsController, type: &#39;controller&#39; do
352 300
353 describe "Bulk Actions" do 301 describe "Bulk Actions" do
354 before(:each) do 302 before(:each) do
355 - sign_in admin 303 + sign_in user
356 @problem1 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem 304 @problem1 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => true)).problem
357 @problem2 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => false)).problem 305 @problem2 = Fabricate(:err, :problem => Fabricate(:problem, :resolved => false)).problem
358 end 306 end
@@ -434,7 +382,7 @@ describe ProblemsController, type: &#39;controller&#39; do @@ -434,7 +382,7 @@ describe ProblemsController, type: &#39;controller&#39; do
434 382
435 describe "POST /apps/:app_id/problems/destroy_all" do 383 describe "POST /apps/:app_id/problems/destroy_all" do
436 before do 384 before do
437 - sign_in Fabricate(:admin) 385 + sign_in user
438 @app = Fabricate(:app) 386 @app = Fabricate(:app)
439 @problem1 = Fabricate(:problem, :app=>@app) 387 @problem1 = Fabricate(:problem, :app=>@app)
440 @problem2 = Fabricate(:problem, :app=>@app) 388 @problem2 = Fabricate(:problem, :app=>@app)
spec/controllers/watchers_controller_spec.rb
1 describe WatchersController, type: 'controller' do 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 before(:each) do 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 end 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 end 48 end
31 end 49 end
32 end 50 end
spec/models/user_spec.rb
@@ -37,24 +37,6 @@ describe User do @@ -37,24 +37,6 @@ describe User do
37 end 37 end
38 end 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 context "First user" do 40 context "First user" do
59 it "should be created this admin access via db:seed" do 41 it "should be created this admin access via db:seed" do
60 expect { 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,7 +30,7 @@ describe &quot;apps/show.html.haml&quot;, type: &#39;view&#39; do
30 30
31 context "with user watch application" do 31 context "with user watch application" do
32 before do 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 end 34 end
35 it 'see the unwatch button' do 35 it 'see the unwatch button' do
36 render 36 render
@@ -40,7 +40,7 @@ describe &quot;apps/show.html.haml&quot;, type: &#39;view&#39; do @@ -40,7 +40,7 @@ describe &quot;apps/show.html.haml&quot;, type: &#39;view&#39; do
40 40
41 context "with user not watch application" do 41 context "with user not watch application" do
42 before do 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 end 44 end
45 it 'not see the unwatch button' do 45 it 'not see the unwatch button' do
46 render 46 render