Commit 8f13caf0bffe3dfd579dc52b76f54fe84c943154
1 parent
b4fc56cc
Exists in
master
and in
1 other branch
Add capabilities to addmin to regenerate the API key of his app
Now the api_key of app can be regenerate. In previous this api-key can't be regenerate by the web front. To regenerate this api_key you need go to the edit app page. See #547
Showing
12 changed files
with
164 additions
and
63 deletions
Show diff stats
app/controllers/apps_controller.rb
| @@ -80,6 +80,11 @@ class AppsController < ApplicationController | @@ -80,6 +80,11 @@ class AppsController < ApplicationController | ||
| 80 | end | 80 | end |
| 81 | end | 81 | end |
| 82 | 82 | ||
| 83 | + def regenerate_api_key | ||
| 84 | + app.regenerate_api_key! | ||
| 85 | + redirect_to edit_app_path(app) | ||
| 86 | + end | ||
| 87 | + | ||
| 83 | protected | 88 | protected |
| 84 | 89 | ||
| 85 | def initialize_subclassed_issue_tracker | 90 | def initialize_subclassed_issue_tracker |
app/models/app.rb
| @@ -170,6 +170,10 @@ class App | @@ -170,6 +170,10 @@ class App | ||
| 170 | Errbit::Config.per_app_email_at_notices ? super : Errbit::Config.email_at_notices | 170 | Errbit::Config.per_app_email_at_notices ? super : Errbit::Config.email_at_notices |
| 171 | end | 171 | end |
| 172 | 172 | ||
| 173 | + def regenerate_api_key! | ||
| 174 | + set(:api_key, SecureRandom.hex) | ||
| 175 | + end | ||
| 176 | + | ||
| 173 | protected | 177 | protected |
| 174 | 178 | ||
| 175 | def store_cached_attributes_on_problems | 179 | def store_cached_attributes_on_problems |
app/views/apps/_fields.html.haml
| @@ -5,6 +5,10 @@ | @@ -5,6 +5,10 @@ | ||
| 5 | = f.text_field :name | 5 | = f.text_field :name |
| 6 | 6 | ||
| 7 | %div | 7 | %div |
| 8 | + %label Api Key | ||
| 9 | + %span= app.api_key | ||
| 10 | + = link_to t('.regenerate_api_key'), regenerate_api_key_app_path(app), :class => 'button', :method => 'post' | ||
| 11 | +%div | ||
| 8 | = f.label :repository_branch | 12 | = f.label :repository_branch |
| 9 | = f.text_field :repository_branch, :placeholder => "master" | 13 | = f.text_field :repository_branch, :placeholder => "master" |
| 10 | %div | 14 | %div |
config/locales/en.yml
| @@ -81,6 +81,8 @@ en: | @@ -81,6 +81,8 @@ en: | ||
| 81 | new_app: Add a New App | 81 | new_app: Add a New App |
| 82 | no_apps: 'No apps here.' | 82 | no_apps: 'No apps here.' |
| 83 | click_to_create: 'Click here to create your first one' | 83 | click_to_create: 'Click here to create your first one' |
| 84 | + fields: | ||
| 85 | + regenerate_api_key: "Regenerate API key" | ||
| 84 | show: | 86 | show: |
| 85 | all_deploys: "All Deploys (%{count})" | 87 | all_deploys: "All Deploys (%{count})" |
| 86 | all_errs: all errs | 88 | all_errs: all errs |
| @@ -100,7 +102,6 @@ en: | @@ -100,7 +102,6 @@ en: | ||
| 100 | no_error_yet: "No errs have been caught yet, make sure you setup your app" | 102 | 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" | 103 | no_watcher: "Sadly, no one is watching this app" |
| 102 | repository: Repository | 104 | repository: Repository |
| 103 | - repository: Repository | ||
| 104 | revision: Revision | 105 | revision: Revision |
| 105 | search_placeholder: 'Search for issues' | 106 | search_placeholder: 'Search for issues' |
| 106 | show_hide: "(show/hide)" | 107 | show_hide: "(show/hide)" |
| @@ -110,3 +111,4 @@ en: | @@ -110,3 +111,4 @@ en: | ||
| 110 | watchers: Watchers | 111 | watchers: Watchers |
| 111 | when: When | 112 | when: When |
| 112 | who: Who | 113 | who: Who |
| 114 | + |
config/routes.rb
| @@ -39,6 +39,9 @@ Errbit::Application.routes.draw do | @@ -39,6 +39,9 @@ Errbit::Application.routes.draw do | ||
| 39 | end | 39 | end |
| 40 | resources :deploys, :only => [:index] | 40 | resources :deploys, :only => [:index] |
| 41 | resources :watchers, :only => [:destroy] | 41 | resources :watchers, :only => [:destroy] |
| 42 | + member do | ||
| 43 | + post :regenerate_api_key | ||
| 44 | + end | ||
| 42 | end | 45 | end |
| 43 | 46 | ||
| 44 | namespace :api do | 47 | namespace :api do |
spec/acceptance/acceptance_helper.rb
| @@ -17,3 +17,10 @@ def mock_auth(user = "test_user", token = "abcdef") | @@ -17,3 +17,10 @@ def mock_auth(user = "test_user", token = "abcdef") | ||
| 17 | } | 17 | } |
| 18 | ) | 18 | ) |
| 19 | end | 19 | end |
| 20 | + | ||
| 21 | +def log_in(user) | ||
| 22 | + visit '/' | ||
| 23 | + fill_in :user_email, :with => user.email | ||
| 24 | + fill_in :user_password, :with => 'password' | ||
| 25 | + click_on I18n.t('devise.sessions.new.sign_in') | ||
| 26 | +end |
| @@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
| 1 | +require 'acceptance/acceptance_helper' | ||
| 2 | + | ||
| 3 | +feature "Regeneration api_Key" do | ||
| 4 | + let!(:app) { Fabricate(:app) } | ||
| 5 | + let!(:admin) { Fabricate(:admin) } | ||
| 6 | + let(:user) { | ||
| 7 | + Fabricate(:user_watcher, :app => app).user | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + scenario "an admin change api_key" do | ||
| 11 | + visit '/' | ||
| 12 | + log_in admin | ||
| 13 | + click_link app.name | ||
| 14 | + click_link I18n.t('apps.show.edit') | ||
| 15 | + expect { | ||
| 16 | + click_link I18n.t('apps.fields.regenerate_api_key') | ||
| 17 | + }.to change { | ||
| 18 | + app.reload.api_key | ||
| 19 | + } | ||
| 20 | + end | ||
| 21 | + | ||
| 22 | + scenario "a user cannot access to edit page" do | ||
| 23 | + visit '/' | ||
| 24 | + log_in user | ||
| 25 | + click_link app.name if page.current_url != app_url(app) | ||
| 26 | + expect(page).to_not have_button I18n.t('apps.show.edit') | ||
| 27 | + end | ||
| 28 | + | ||
| 29 | +end |
spec/acceptance/watch_unwatch_app.rb
| @@ -1,23 +0,0 @@ | @@ -1,23 +0,0 @@ | ||
| 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,20 @@ | @@ -0,0 +1,20 @@ | ||
| 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 | + log_in user | ||
| 16 | + click_on I18n.t('apps.show.unwatch') | ||
| 17 | + expect(page).to have_content(I18n.t('apps.index.no_apps')) | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | +end |
spec/controllers/apps_controller_spec.rb
| @@ -5,11 +5,37 @@ describe AppsController do | @@ -5,11 +5,37 @@ describe AppsController do | ||
| 5 | it_requires_authentication | 5 | it_requires_authentication |
| 6 | it_requires_admin_privileges :for => {:new => :get, :edit => :get, :create => :post, :update => :put, :destroy => :delete} | 6 | it_requires_admin_privileges :for => {:new => :get, :edit => :get, :create => :post, :update => :put, :destroy => :delete} |
| 7 | 7 | ||
| 8 | + let(:admin) { Fabricate(:admin) } | ||
| 9 | + let(:user) { Fabricate(:user) } | ||
| 10 | + let(:watcher) { Fabricate(:user_watcher, :app => app, :user => user) } | ||
| 11 | + let(:unwatched_app) { Fabricate(:app) } | ||
| 12 | + let(:app) { unwatched_app } | ||
| 13 | + let(:watched_app1) do | ||
| 14 | + a = Fabricate(:app) | ||
| 15 | + Fabricate(:user_watcher, :user => user, :app => a) | ||
| 16 | + a | ||
| 17 | + end | ||
| 18 | + let(:watched_app2) do | ||
| 19 | + a = Fabricate(:app) | ||
| 20 | + Fabricate(:user_watcher, :user => user, :app => a) | ||
| 21 | + a | ||
| 22 | + end | ||
| 23 | + let(:err) do | ||
| 24 | + Fabricate(:err, :problem => problem) | ||
| 25 | + end | ||
| 26 | + let(:notice) do | ||
| 27 | + Fabricate(:notice, :err => err) | ||
| 28 | + end | ||
| 29 | + let(:problem) do | ||
| 30 | + Fabricate(:problem, :app => app) | ||
| 31 | + end | ||
| 32 | + let(:problem_resolved) { Fabricate(:problem_resolved, :app => app) } | ||
| 33 | + | ||
| 8 | describe "GET /apps" do | 34 | describe "GET /apps" do |
| 9 | context 'when logged in as an admin' do | 35 | context 'when logged in as an admin' do |
| 10 | it 'finds all apps' do | 36 | it 'finds all apps' do |
| 11 | - sign_in Fabricate(:admin) | ||
| 12 | - 3.times { Fabricate(:app) } | 37 | + sign_in admin |
| 38 | + unwatched_app && watched_app1 && watched_app2 | ||
| 13 | get :index | 39 | get :index |
| 14 | controller.apps.entries.should == App.all.sort.entries | 40 | controller.apps.entries.should == App.all.sort.entries |
| 15 | end | 41 | end |
| @@ -17,12 +43,8 @@ describe AppsController do | @@ -17,12 +43,8 @@ describe AppsController do | ||
| 17 | 43 | ||
| 18 | context 'when logged in as a regular user' do | 44 | context 'when logged in as a regular user' do |
| 19 | it 'finds apps the user is watching' do | 45 | it 'finds apps the user is watching' do |
| 20 | - sign_in(user = Fabricate(:user)) | ||
| 21 | - unwatched_app = Fabricate(:app) | ||
| 22 | - watched_app1 = Fabricate(:app) | ||
| 23 | - watched_app2 = Fabricate(:app) | ||
| 24 | - Fabricate(:user_watcher, :user => user, :app => watched_app1) | ||
| 25 | - Fabricate(:user_watcher, :user => user, :app => watched_app2) | 46 | + sign_in(user) |
| 47 | + watched_app1 && watched_app2 && unwatched_app | ||
| 26 | get :index | 48 | get :index |
| 27 | controller.apps.should include(watched_app1, watched_app2) | 49 | controller.apps.should include(watched_app1, watched_app2) |
| 28 | controller.apps.should_not include(unwatched_app) | 50 | controller.apps.should_not include(unwatched_app) |
| @@ -33,61 +55,56 @@ describe AppsController do | @@ -33,61 +55,56 @@ describe AppsController do | ||
| 33 | describe "GET /apps/:id" do | 55 | describe "GET /apps/:id" do |
| 34 | context 'logged in as an admin' do | 56 | context 'logged in as an admin' do |
| 35 | before(:each) do | 57 | before(:each) do |
| 36 | - @user = Fabricate(:admin) | ||
| 37 | - sign_in @user | ||
| 38 | - @app = Fabricate(:app) | ||
| 39 | - @problem = Fabricate(:notice, :err => Fabricate(:err, :problem => Fabricate(:problem, :app => @app))).problem | 58 | + sign_in admin |
| 40 | end | 59 | end |
| 41 | 60 | ||
| 42 | it 'finds the app' do | 61 | it 'finds the app' do |
| 43 | - get :show, :id => @app.id | ||
| 44 | - controller.app.should == @app | 62 | + get :show, :id => app.id |
| 63 | + controller.app.should == app | ||
| 45 | end | 64 | end |
| 46 | 65 | ||
| 47 | it "should not raise errors for app with err without notices" do | 66 | it "should not raise errors for app with err without notices" do |
| 48 | - Fabricate(:err, :problem => Fabricate(:problem, :app => @app)) | ||
| 49 | - lambda { get :show, :id => @app.id }.should_not raise_error | 67 | + err |
| 68 | + lambda { get :show, :id => app.id }.should_not raise_error | ||
| 50 | end | 69 | end |
| 51 | 70 | ||
| 52 | it "should list atom feed successfully" do | 71 | it "should list atom feed successfully" do |
| 53 | - get :show, :id => @app.id, :format => "atom" | 72 | + get :show, :id => app.id, :format => "atom" |
| 54 | response.should be_success | 73 | response.should be_success |
| 55 | end | 74 | end |
| 56 | 75 | ||
| 57 | context "pagination" do | 76 | context "pagination" do |
| 58 | before(:each) do | 77 | before(:each) do |
| 59 | - 35.times { Fabricate(:err, :problem => Fabricate(:problem, :app => @app)) } | 78 | + 35.times { Fabricate(:err, :problem => Fabricate(:problem, :app => app)) } |
| 60 | end | 79 | end |
| 61 | 80 | ||
| 62 | it "should have default per_page value for user" do | 81 | it "should have default per_page value for user" do |
| 63 | - get :show, :id => @app.id | 82 | + get :show, :id => app.id |
| 64 | controller.problems.to_a.size.should == User::PER_PAGE | 83 | controller.problems.to_a.size.should == User::PER_PAGE |
| 65 | end | 84 | end |
| 66 | 85 | ||
| 67 | it "should be able to override default per_page value" do | 86 | it "should be able to override default per_page value" do |
| 68 | - @user.update_attribute :per_page, 10 | ||
| 69 | - get :show, :id => @app.id | 87 | + admin.update_attribute :per_page, 10 |
| 88 | + get :show, :id => app.id | ||
| 70 | controller.problems.to_a.size.should == 10 | 89 | controller.problems.to_a.size.should == 10 |
| 71 | end | 90 | end |
| 72 | end | 91 | end |
| 73 | 92 | ||
| 74 | context 'with resolved errors' do | 93 | context 'with resolved errors' do |
| 75 | before(:each) do | 94 | before(:each) do |
| 76 | - resolved_problem = Fabricate(:problem, :app => @app) | ||
| 77 | - Fabricate(:notice, :err => Fabricate(:err, :problem => resolved_problem)) | ||
| 78 | - resolved_problem.resolve! | 95 | + problem_resolved && problem |
| 79 | end | 96 | end |
| 80 | 97 | ||
| 81 | context 'and no params' do | 98 | context 'and no params' do |
| 82 | it 'shows only unresolved problems' do | 99 | it 'shows only unresolved problems' do |
| 83 | - get :show, :id => @app.id | 100 | + get :show, :id => app.id |
| 84 | controller.problems.size.should == 1 | 101 | controller.problems.size.should == 1 |
| 85 | end | 102 | end |
| 86 | end | 103 | end |
| 87 | 104 | ||
| 88 | context 'and all_problems=true params' do | 105 | context 'and all_problems=true params' do |
| 89 | it 'shows all errors' do | 106 | it 'shows all errors' do |
| 90 | - get :show, :id => @app.id, :all_errs => true | 107 | + get :show, :id => app.id, :all_errs => true |
| 91 | controller.problems.size.should == 2 | 108 | controller.problems.size.should == 2 |
| 92 | end | 109 | end |
| 93 | end | 110 | end |
| @@ -97,41 +114,41 @@ describe AppsController do | @@ -97,41 +114,41 @@ describe AppsController do | ||
| 97 | before(:each) do | 114 | before(:each) do |
| 98 | environments = ['production', 'test', 'development', 'staging'] | 115 | environments = ['production', 'test', 'development', 'staging'] |
| 99 | 20.times do |i| | 116 | 20.times do |i| |
| 100 | - Fabricate(:problem, :app => @app, :environment => environments[i % environments.length]) | 117 | + Fabricate(:problem, :app => app, :environment => environments[i % environments.length]) |
| 101 | end | 118 | end |
| 102 | end | 119 | end |
| 103 | 120 | ||
| 104 | context 'no params' do | 121 | context 'no params' do |
| 105 | it 'shows errs for all environments' do | 122 | it 'shows errs for all environments' do |
| 106 | - get :show, :id => @app.id | ||
| 107 | - controller.problems.size.should == 21 | 123 | + get :show, :id => app.id |
| 124 | + controller.problems.size.should == 20 | ||
| 108 | end | 125 | end |
| 109 | end | 126 | end |
| 110 | 127 | ||
| 111 | context 'environment production' do | 128 | context 'environment production' do |
| 112 | it 'shows errs for just production' do | 129 | it 'shows errs for just production' do |
| 113 | - get :show, :id => @app.id, :environment => 'production' | ||
| 114 | - controller.problems.size.should == 6 | 130 | + get :show, :id => app.id, :environment => 'production' |
| 131 | + controller.problems.size.should == 5 | ||
| 115 | end | 132 | end |
| 116 | end | 133 | end |
| 117 | 134 | ||
| 118 | context 'environment staging' do | 135 | context 'environment staging' do |
| 119 | it 'shows errs for just staging' do | 136 | it 'shows errs for just staging' do |
| 120 | - get :show, :id => @app.id, :environment => 'staging' | 137 | + get :show, :id => app.id, :environment => 'staging' |
| 121 | controller.problems.size.should == 5 | 138 | controller.problems.size.should == 5 |
| 122 | end | 139 | end |
| 123 | end | 140 | end |
| 124 | 141 | ||
| 125 | context 'environment development' do | 142 | context 'environment development' do |
| 126 | it 'shows errs for just development' do | 143 | it 'shows errs for just development' do |
| 127 | - get :show, :id => @app.id, :environment => 'development' | 144 | + get :show, :id => app.id, :environment => 'development' |
| 128 | controller.problems.size.should == 5 | 145 | controller.problems.size.should == 5 |
| 129 | end | 146 | end |
| 130 | end | 147 | end |
| 131 | 148 | ||
| 132 | context 'environment test' do | 149 | context 'environment test' do |
| 133 | it 'shows errs for just test' do | 150 | it 'shows errs for just test' do |
| 134 | - get :show, :id => @app.id, :environment => 'test' | 151 | + get :show, :id => app.id, :environment => 'test' |
| 135 | controller.problems.size.should == 5 | 152 | controller.problems.size.should == 5 |
| 136 | end | 153 | end |
| 137 | end | 154 | end |
| @@ -140,9 +157,7 @@ describe AppsController do | @@ -140,9 +157,7 @@ describe AppsController do | ||
| 140 | 157 | ||
| 141 | context 'logged in as a user' do | 158 | context 'logged in as a user' do |
| 142 | it 'finds the app if the user is watching it' do | 159 | it 'finds the app if the user is watching it' do |
| 143 | - user = Fabricate(:user) | ||
| 144 | - app = Fabricate(:app) | ||
| 145 | - watcher = Fabricate(:user_watcher, :app => app, :user => user) | 160 | + watcher |
| 146 | sign_in user | 161 | sign_in user |
| 147 | get :show, :id => app.id | 162 | get :show, :id => app.id |
| 148 | controller.app.should == app | 163 | controller.app.should == app |
| @@ -160,7 +175,7 @@ describe AppsController do | @@ -160,7 +175,7 @@ describe AppsController do | ||
| 160 | 175 | ||
| 161 | context 'logged in as an admin' do | 176 | context 'logged in as an admin' do |
| 162 | before do | 177 | before do |
| 163 | - sign_in Fabricate(:admin) | 178 | + sign_in admin |
| 164 | end | 179 | end |
| 165 | 180 | ||
| 166 | describe "GET /apps/new" do | 181 | describe "GET /apps/new" do |
| @@ -345,6 +360,34 @@ describe AppsController do | @@ -345,6 +360,34 @@ describe AppsController do | ||
| 345 | end | 360 | end |
| 346 | end | 361 | end |
| 347 | 362 | ||
| 363 | + describe "POST /apps/:id/regenerate_api_key" do | ||
| 364 | + | ||
| 365 | + context "like watcher" do | ||
| 366 | + before do | ||
| 367 | + sign_in watcher.user | ||
| 368 | + end | ||
| 369 | + | ||
| 370 | + it 'redirect to root with flash error' do | ||
| 371 | + post :regenerate_api_key, :id => 'foo' | ||
| 372 | + expect(request).to redirect_to root_path | ||
| 373 | + end | ||
| 374 | + | ||
| 375 | + end | ||
| 376 | + | ||
| 377 | + context "like admin" do | ||
| 378 | + before do | ||
| 379 | + sign_in admin | ||
| 380 | + end | ||
| 381 | + | ||
| 382 | + it 'redirect_to app view' do | ||
| 383 | + expect do | ||
| 384 | + post :regenerate_api_key, :id => app.id | ||
| 385 | + expect(request).to redirect_to edit_app_path(app) | ||
| 386 | + end.to change { app.api_key } | ||
| 387 | + end | ||
| 388 | + end | ||
| 389 | + | ||
| 390 | + end | ||
| 348 | 391 | ||
| 349 | end | 392 | end |
| 350 | 393 |
spec/fabricators/err_fabricator.rb
| @@ -21,3 +21,4 @@ Fabricator :backtrace_line do | @@ -21,3 +21,4 @@ Fabricator :backtrace_line do | ||
| 21 | file { "/path/to/file/#{SecureRandom.hex(4)}.rb" } | 21 | file { "/path/to/file/#{SecureRandom.hex(4)}.rb" } |
| 22 | method(:method) { ActiveSupport.methods.shuffle.first } | 22 | method(:method) { ActiveSupport.methods.shuffle.first } |
| 23 | end | 23 | end |
| 24 | + |
spec/fabricators/problem_fabricator.rb
| @@ -21,4 +21,10 @@ Fabricator(:problem_with_errs, :from => :problem) do | @@ -21,4 +21,10 @@ Fabricator(:problem_with_errs, :from => :problem) do | ||
| 21 | } | 21 | } |
| 22 | end | 22 | end |
| 23 | 23 | ||
| 24 | - | 24 | +Fabricator(:problem_resolved, :from => :problem) do |
| 25 | + after_create do |pr| | ||
| 26 | + Fabricate(:notice, | ||
| 27 | + :err => Fabricate(:err, :problem => pr)) | ||
| 28 | + pr.resolve! | ||
| 29 | + end | ||
| 30 | +end |