Commit 9ce0dc764fd5347f985bb36017e4468d93d3f9b8
Exists in
master
and in
1 other branch
Merge pull request #289
Showing
10 changed files
with
182 additions
and
34 deletions
Show diff stats
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 | }); |
@@ -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') |
@@ -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 |
@@ -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 'spec_helper' | @@ -2,17 +2,20 @@ require 'spec_helper' | ||
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 "apps/show.html.haml" do | @@ -28,5 +31,26 @@ describe "apps/show.html.haml" 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 |