Commit 9ce0dc764fd5347f985bb36017e4468d93d3f9b8

Authored by Cyril Mougel
2 parents cd44ad81 88aea500
Exists in master and in 1 other branch production

Merge pull request #289

app/assets/javascripts/apps.show.js
1 $(function() { 1 $(function() {
  2 +
2 $("#watchers_toggle").click(function() { 3 $("#watchers_toggle").click(function() {
3 $("#watchers_div").slideToggle("slow"); 4 $("#watchers_div").slideToggle("slow");
4 }); 5 });
  6 +
5 $("#repository_toggle").click(function() { 7 $("#repository_toggle").click(function() {
6 $("#repository_div").slideToggle("slow"); 8 $("#repository_div").slideToggle("slow");
7 }); 9 });
  10 +
8 $("#deploys_toggle").click(function() { 11 $("#deploys_toggle").click(function() {
9 $("#deploys_div").slideToggle("slow"); 12 $("#deploys_div").slideToggle("slow");
10 }); 13 });
app/controllers/watchers_controller.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +class WatchersController < ApplicationController
  2 + respond_to :html
  3 +
  4 + expose(:app) do
  5 + App.find(params[:app_id])
  6 + end
  7 +
  8 + expose(:watcher) do
  9 + app.watchers.where(:user_id => params[:id]).first
  10 + end
  11 +
  12 + before_filter :require_watcher_edit_priviledges, :only => [:destroy]
  13 +
  14 + def destroy
  15 + app.watchers.delete(watcher)
  16 + flash[:success] = "That's sad. #{watcher.label} is no longer watcher."
  17 + redirect_to root_path
  18 + end
  19 +
  20 + private
  21 +
  22 + def require_watcher_edit_priviledges
  23 + redirect_to(root_path) unless current_user == watcher.user || current_user.admin?
  24 + end
  25 +
  26 +end
  27 +
app/views/apps/show.html.haml
1 - content_for :title, app.name 1 - content_for :title, app.name
2 - content_for :head do 2 - content_for :head do
3 - = auto_discovery_link_tag :atom, app_path(app, User.token_authentication_key => current_user.authentication_token, :format => "atom"), :title => "Errbit notices for #{app.name} at #{request.host}" 3 + = auto_discovery_link_tag :atom, app_path(app, User.token_authentication_key => current_user.authentication_token, :format => "atom"), :title => t('.atom_title', :name => app.name, :host => request.host)
4 - content_for :meta do 4 - content_for :meta do
5 - %strong Errors Caught: 5 + %strong=t('.errors_caught')
6 = app.problems.count 6 = app.problems.count
7 - %strong Deploy Count: 7 + %strong=t('.deploy_count')
8 = app.deploys.count 8 = app.deploys.count
9 - %strong API Key: 9 + %strong=t('.api_key')
10 = app.api_key 10 = app.api_key
11 - content_for :action_bar do 11 - content_for :action_bar do
12 - if current_user.admin? 12 - if current_user.admin?
13 - = link_to 'edit', edit_app_path(app), :class => 'button' 13 + = link_to t('.edit'), edit_app_path(app), :class => 'button'
14 - if all_errs 14 - if all_errs
15 - = link_to 'unresolved errs', app_path(app), :class => 'button' 15 + = link_to t('.unresolved_errs'), app_path(app), :class => 'button'
16 - else 16 - else
17 - = link_to 'all errs', app_path(app, :all_errs => true), :class => 'button' 17 + = link_to t('.all_errs'), app_path(app, :all_errs => true), :class => 'button'
18 18
  19 + - if current_user.watching?(app)
  20 + = link_to t('.unwatch'), app_watcher_path({:app_id => app, :id => current_user.id}), :method => :delete, :class => 'button', :confirm => t('.are_you_sure')
19 %h3#watchers_toggle 21 %h3#watchers_toggle
20 - Watchers  
21 - %span.click_span (show/hide) 22 + =t('.watchers')
  23 + %span.click_span=t('.show_hide')
22 #watchers_div 24 #watchers_div
23 - if app.notify_all_users 25 - if app.notify_all_users
24 %table.watchers 26 %table.watchers
25 %thead 27 %thead
26 %tr 28 %tr
27 - %th All users will be notified when something happens. 29 + %th=t('.all_users_notified')
28 - else 30 - else
29 %table.watchers 31 %table.watchers
30 %thead 32 %thead
31 %tr 33 %tr
32 - %th User or Email 34 + %th=t('.user_or_email')
33 %tbody 35 %tbody
34 - app.watchers.each do |watcher| 36 - app.watchers.each do |watcher|
35 %tr 37 %tr
@@ -37,35 +39,35 @@ @@ -37,35 +39,35 @@
37 - if app.watchers.none? 39 - if app.watchers.none?
38 %tr 40 %tr
39 %td 41 %td
40 - %em Sadly, no one is watching this app 42 + %em= t('.no_watcher')
41 43
42 - if app.github_repo? 44 - if app.github_repo?
43 %h3#repository_toggle 45 %h3#repository_toggle
44 - Repository  
45 - %span.click_span (show/hide) 46 + =t('.repository')
  47 + %span.click_span=t('.show_hide')
46 #repository_div 48 #repository_div
47 %table.repository 49 %table.repository
48 %thead 50 %thead
49 %tr 51 %tr
50 - %th GitHub Repo 52 + %th=t('.github_repo')
51 %tbody 53 %tbody
52 %tr 54 %tr
53 %td= link_to(app.github_repo, app.github_url, :target => '_blank') 55 %td= link_to(app.github_repo, app.github_url, :target => '_blank')
54 56
55 %h3#deploys_toggle 57 %h3#deploys_toggle
56 - Latest Deploys  
57 - %span.click_span (show/hide) 58 + =t('.latest_deploys')
  59 + %span.click_span=t('.show_hide')
58 #deploys_div 60 #deploys_div
59 - if deploys.any? 61 - if deploys.any?
60 %table.deploys 62 %table.deploys
61 %thead 63 %thead
62 %tr 64 %tr
63 - %th When  
64 - %th Environment  
65 - %th Who  
66 - %th Message  
67 - %th Repository  
68 - %th Revision 65 + %th=t('.when')
  66 + %th=t('.environment')
  67 + %th=t('.who')
  68 + %th=t('.message')
  69 + %th=t('.repository')
  70 + %th=t('.revision')
69 71
70 %tbody 72 %tbody
71 - deploys.each do |deploy| 73 - deploys.each do |deploy|
@@ -76,20 +78,20 @@ @@ -76,20 +78,20 @@
76 %td.message #{deploy.message} 78 %td.message #{deploy.message}
77 %td.repository #{deploy.repository} 79 %td.repository #{deploy.repository}
78 %td.revision #{deploy.short_revision} 80 %td.revision #{deploy.short_revision}
79 - = link_to "All Deploys (#{app.deploys.count})", app_deploys_path(app), :class => 'button' 81 + = link_to t('.all_deploys', :count => app.deploys.count), app_deploys_path(app), :class => 'button'
80 - else 82 - else
81 - %h3 No deploys 83 + %h3=t('.no_deploys')
82 84
83 - if app.problems.any? 85 - if app.problems.any?
84 - %h3.clear Errors 86 + %h3.clear=t('.errors')
85 %section 87 %section
86 = form_tag search_problems_path(:all_errs => all_errs, :app_id => app.id), :method => :get, :remote => true do 88 = form_tag search_problems_path(:all_errs => all_errs, :app_id => app.id), :method => :get, :remote => true do
87 - = text_field_tag :search, params[:search], :placeholder => 'Search for issues' 89 + = text_field_tag :search, params[:search], :placeholder => t('.search_placeholder')
88 %br 90 %br
89 %section 91 %section
90 .problem_table{:id => 'problem_table'} 92 .problem_table{:id => 'problem_table'}
91 = render 'problems/table', :problems => problems 93 = render 'problems/table', :problems => problems
92 - else 94 - else
93 - %h3.clear No errs have been caught yet, make sure you setup your app 95 + %h3.clear=t('.no_error_yet')
94 = render 'configuration_instructions', :app => app 96 = render 'configuration_instructions', :app => app
95 97
app/views/devise/sessions/new.html.haml
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 = f.label :remember_me 22 = f.label :remember_me
23 23
24 %div.buttons 24 %div.buttons
25 - %button{:type => 'submit', :class => 'sign_in'}= "Sign in" 25 + %button{:type => 'submit', :class => 'sign_in'}=t('.sign_in')
26 26
27 :javascript 27 :javascript
28 $('a#forgot_password').click(function(){ 28 $('a#forgot_password').click(function(){
config/locales/en.yml
@@ -65,6 +65,9 @@ en: @@ -65,6 +65,9 @@ en:
65 omniauth_callbacks: 65 omniauth_callbacks:
66 failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 66 failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
67 success: "Successfully authenticated from %{kind} account." 67 success: "Successfully authenticated from %{kind} account."
  68 + sessions:
  69 + new:
  70 + sign_in: "Sign in"
68 71
69 apps: 72 apps:
70 index: 73 index:
@@ -78,3 +81,32 @@ en: @@ -78,3 +81,32 @@ en:
78 new_app: Add a New App 81 new_app: Add a New App
79 no_apps: 'No apps here.' 82 no_apps: 'No apps here.'
80 click_to_create: 'Click here to create your first one' 83 click_to_create: 'Click here to create your first one'
  84 + show:
  85 + all_deploys: "All Deploys (%{count})"
  86 + all_errs: all errs
  87 + all_users_notified: "All users will be notified when something happens."
  88 + api_key: "API Key:"
  89 + are_you_sure: 'Are you sure?'
  90 + atom_title: "Errbit notices for %{name} at %{host}"
  91 + deploy_count: "Deploy Count:"
  92 + edit: edit
  93 + environment: Environment
  94 + errors: Errors
  95 + errors_caught: "Errors Caught:"
  96 + github_repo: GitHub Repo
  97 + latest_deploys: Latest Deploys
  98 + message: Message
  99 + no_deploys: No deploys
  100 + no_error_yet: "No errs have been caught yet, make sure you setup your app"
  101 + no_watcher: "Sadly, no one is watching this app"
  102 + repository: Repository
  103 + repository: Repository
  104 + revision: Revision
  105 + search_placeholder: 'Search for issues'
  106 + show_hide: "(show/hide)"
  107 + unresolved_errs: unresolved errs
  108 + unwatch: unwatch
  109 + user_or_email: User or Email
  110 + watchers: Watchers
  111 + when: When
  112 + who: Who
config/routes.rb
@@ -37,8 +37,8 @@ Errbit::Application.routes.draw do @@ -37,8 +37,8 @@ Errbit::Application.routes.draw do
37 delete :unlink_issue 37 delete :unlink_issue
38 end 38 end
39 end 39 end
40 -  
41 resources :deploys, :only => [:index] 40 resources :deploys, :only => [:index]
  41 + resources :watchers, :only => [:destroy]
42 end 42 end
43 43
44 namespace :api do 44 namespace :api do
spec/acceptance/sign_in_with_github_spec.rb
1 require 'acceptance/acceptance_helper' 1 require 'acceptance/acceptance_helper'
2 2
3 feature 'Sign in with GitHub' do 3 feature 'Sign in with GitHub' do
  4 +
4 background do 5 background do
5 Errbit::Config.stub(:github_authentication) { true } 6 Errbit::Config.stub(:github_authentication) { true }
6 Fabricate(:user, :github_login => 'nashby') 7 Fabricate(:user, :github_login => 'nashby')
spec/acceptance/watch_unwatch_app.rb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +require 'acceptance/acceptance_helper'
  2 +
  3 +feature 'A user can watch and unwatch an application' do
  4 +
  5 + let!(:app) { Fabricate(:app) }
  6 + let!(:user) do
  7 + user = Fabricate(:user)
  8 + app.watchers.create!(
  9 + :user_id => user.id
  10 + )
  11 + user.reload
  12 + end
  13 +
  14 + scenario 'log in watch a project and unwatch it' do
  15 + visit '/'
  16 + fill_in :user_email, :with => user.email
  17 + fill_in :user_password, :with => 'password'
  18 + click_on I18n.t('devise.sessions.new.sign_in')
  19 + click_on I18n.t('apps.show.unwatch')
  20 + expect(page).to have_content(I18n.t('apps.index.no_apps')
  21 + end
  22 +
  23 +end
spec/controllers/watchers_controller_spec.rb 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +require 'spec_helper'
  2 +
  3 +describe WatchersController do
  4 + let(:app) do
  5 + a = Fabricate(:app)
  6 + Fabricate(:user_watcher, :app => a)
  7 + a
  8 + end
  9 +
  10 + describe "DELETE /apps/:app_id/watchers/:id/destroy" do
  11 +
  12 + context "with admin user" do
  13 + before(:each) do
  14 + sign_in Fabricate(:admin)
  15 + end
  16 +
  17 + context "successful watcher deletion" do
  18 + let(:problem) { Fabricate(:problem_with_comments) }
  19 + let(:watcher) { app.watchers.first }
  20 +
  21 + before(:each) do
  22 + delete :destroy, :app_id => app.id, :id => watcher.user.id.to_s
  23 + problem.reload
  24 + end
  25 +
  26 + it "should delete the watcher" do
  27 + app.watchers.detect{|w| w.id.to_s == watcher.id }.should == nil
  28 + end
  29 +
  30 + it "should redirect to index page" do
  31 + response.should redirect_to(root_path)
  32 + end
  33 + end
  34 + end
  35 + end
  36 +end
spec/views/apps/show.html.haml_spec.rb
@@ -2,17 +2,20 @@ require &#39;spec_helper&#39; @@ -2,17 +2,20 @@ require &#39;spec_helper&#39;
2 2
3 describe "apps/show.html.haml" do 3 describe "apps/show.html.haml" do
4 let(:app) { stub_model(App) } 4 let(:app) { stub_model(App) }
  5 + let(:user) { stub_model(User) }
  6 +
  7 + let(:action_bar) do
  8 + view.content_for(:action_bar)
  9 + end
  10 +
5 before do 11 before do
6 view.stub(:app).and_return(app) 12 view.stub(:app).and_return(app)
7 view.stub(:all_errs).and_return(false) 13 view.stub(:all_errs).and_return(false)
8 view.stub(:deploys).and_return([]) 14 view.stub(:deploys).and_return([])
9 - controller.stub(:current_user) { stub_model(User) } 15 + controller.stub(:current_user) { user }
10 end 16 end
11 17
12 describe "content_for :action_bar" do 18 describe "content_for :action_bar" do
13 - def action_bar  
14 - view.content_for(:action_bar)  
15 - end  
16 19
17 it "should confirm the 'cancel' link" do 20 it "should confirm the 'cancel' link" do
18 render 21 render
@@ -28,5 +31,26 @@ describe &quot;apps/show.html.haml&quot; do @@ -28,5 +31,26 @@ describe &quot;apps/show.html.haml&quot; do
28 rendered.should match(/No errs have been/) 31 rendered.should match(/No errs have been/)
29 end 32 end
30 end 33 end
  34 +
  35 + context "with user watch application" do
  36 + before do
  37 + user.stub(:watching?).with(app).and_return(true)
  38 + end
  39 + it 'see the unwatch button' do
  40 + render
  41 + expect(action_bar).to include(I18n.t('apps.show.unwatch'))
  42 + end
  43 + end
  44 +
  45 + context "with user not watch application" do
  46 + before do
  47 + user.stub(:watching?).with(app).and_return(false)
  48 + end
  49 + it 'not see the unwatch button' do
  50 + render
  51 + expect(action_bar).to_not include(I18n.t('apps.show.unwatch'))
  52 + end
  53 + end
  54 +
31 end 55 end
32 56