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 | 1 | $(function() { |
| 2 | + | |
| 2 | 3 | $("#watchers_toggle").click(function() { |
| 3 | 4 | $("#watchers_div").slideToggle("slow"); |
| 4 | 5 | }); |
| 6 | + | |
| 5 | 7 | $("#repository_toggle").click(function() { |
| 6 | 8 | $("#repository_div").slideToggle("slow"); |
| 7 | 9 | }); |
| 10 | + | |
| 8 | 11 | $("#deploys_toggle").click(function() { |
| 9 | 12 | $("#deploys_div").slideToggle("slow"); |
| 10 | 13 | }); | ... | ... |
| ... | ... | @@ -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 | 1 | - content_for :title, app.name |
| 2 | 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 | 4 | - content_for :meta do |
| 5 | - %strong Errors Caught: | |
| 5 | + %strong=t('.errors_caught') | |
| 6 | 6 | = app.problems.count |
| 7 | - %strong Deploy Count: | |
| 7 | + %strong=t('.deploy_count') | |
| 8 | 8 | = app.deploys.count |
| 9 | - %strong API Key: | |
| 9 | + %strong=t('.api_key') | |
| 10 | 10 | = app.api_key |
| 11 | 11 | - content_for :action_bar do |
| 12 | 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 | 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 | 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 | 21 | %h3#watchers_toggle |
| 20 | - Watchers | |
| 21 | - %span.click_span (show/hide) | |
| 22 | + =t('.watchers') | |
| 23 | + %span.click_span=t('.show_hide') | |
| 22 | 24 | #watchers_div |
| 23 | 25 | - if app.notify_all_users |
| 24 | 26 | %table.watchers |
| 25 | 27 | %thead |
| 26 | 28 | %tr |
| 27 | - %th All users will be notified when something happens. | |
| 29 | + %th=t('.all_users_notified') | |
| 28 | 30 | - else |
| 29 | 31 | %table.watchers |
| 30 | 32 | %thead |
| 31 | 33 | %tr |
| 32 | - %th User or Email | |
| 34 | + %th=t('.user_or_email') | |
| 33 | 35 | %tbody |
| 34 | 36 | - app.watchers.each do |watcher| |
| 35 | 37 | %tr |
| ... | ... | @@ -37,35 +39,35 @@ |
| 37 | 39 | - if app.watchers.none? |
| 38 | 40 | %tr |
| 39 | 41 | %td |
| 40 | - %em Sadly, no one is watching this app | |
| 42 | + %em= t('.no_watcher') | |
| 41 | 43 | |
| 42 | 44 | - if app.github_repo? |
| 43 | 45 | %h3#repository_toggle |
| 44 | - Repository | |
| 45 | - %span.click_span (show/hide) | |
| 46 | + =t('.repository') | |
| 47 | + %span.click_span=t('.show_hide') | |
| 46 | 48 | #repository_div |
| 47 | 49 | %table.repository |
| 48 | 50 | %thead |
| 49 | 51 | %tr |
| 50 | - %th GitHub Repo | |
| 52 | + %th=t('.github_repo') | |
| 51 | 53 | %tbody |
| 52 | 54 | %tr |
| 53 | 55 | %td= link_to(app.github_repo, app.github_url, :target => '_blank') |
| 54 | 56 | |
| 55 | 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 | 60 | #deploys_div |
| 59 | 61 | - if deploys.any? |
| 60 | 62 | %table.deploys |
| 61 | 63 | %thead |
| 62 | 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 | 72 | %tbody |
| 71 | 73 | - deploys.each do |deploy| |
| ... | ... | @@ -76,20 +78,20 @@ |
| 76 | 78 | %td.message #{deploy.message} |
| 77 | 79 | %td.repository #{deploy.repository} |
| 78 | 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 | 82 | - else |
| 81 | - %h3 No deploys | |
| 83 | + %h3=t('.no_deploys') | |
| 82 | 84 | |
| 83 | 85 | - if app.problems.any? |
| 84 | - %h3.clear Errors | |
| 86 | + %h3.clear=t('.errors') | |
| 85 | 87 | %section |
| 86 | 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 | 90 | %br |
| 89 | 91 | %section |
| 90 | 92 | .problem_table{:id => 'problem_table'} |
| 91 | 93 | = render 'problems/table', :problems => problems |
| 92 | 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 | 96 | = render 'configuration_instructions', :app => app |
| 95 | 97 | ... | ... |
app/views/devise/sessions/new.html.haml
config/locales/en.yml
| ... | ... | @@ -65,6 +65,9 @@ en: |
| 65 | 65 | omniauth_callbacks: |
| 66 | 66 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." |
| 67 | 67 | success: "Successfully authenticated from %{kind} account." |
| 68 | + sessions: | |
| 69 | + new: | |
| 70 | + sign_in: "Sign in" | |
| 68 | 71 | |
| 69 | 72 | apps: |
| 70 | 73 | index: |
| ... | ... | @@ -78,3 +81,32 @@ en: |
| 78 | 81 | new_app: Add a New App |
| 79 | 82 | no_apps: 'No apps here.' |
| 80 | 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
spec/acceptance/sign_in_with_github_spec.rb
| ... | ... | @@ -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 @@ |
| 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 | 2 | |
| 3 | 3 | describe "apps/show.html.haml" do |
| 4 | 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 | 11 | before do |
| 6 | 12 | view.stub(:app).and_return(app) |
| 7 | 13 | view.stub(:all_errs).and_return(false) |
| 8 | 14 | view.stub(:deploys).and_return([]) |
| 9 | - controller.stub(:current_user) { stub_model(User) } | |
| 15 | + controller.stub(:current_user) { user } | |
| 10 | 16 | end |
| 11 | 17 | |
| 12 | 18 | describe "content_for :action_bar" do |
| 13 | - def action_bar | |
| 14 | - view.content_for(:action_bar) | |
| 15 | - end | |
| 16 | 19 | |
| 17 | 20 | it "should confirm the 'cancel' link" do |
| 18 | 21 | render |
| ... | ... | @@ -28,5 +31,26 @@ describe "apps/show.html.haml" do |
| 28 | 31 | rendered.should match(/No errs have been/) |
| 29 | 32 | end |
| 30 | 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 | 55 | end |
| 32 | 56 | ... | ... |