Commit
99334d4b57b6f07e002eaa5145f529d6b63fdce2
Merge branch 'feature/broadcast_messages' of /home/git/repositories/gitlab/gitlabhq
Showing
21 changed files
with
230 additions
and
1 deletions
Show diff stats
| @@ -351,3 +351,10 @@ table { |
| @@ -351,3 +351,10 @@ table { |
351
| @extend .btn-new; |
351
| @extend .btn-new; |
352
| padding: 5px 15px; |
352
| padding: 5px 15px; |
353
| } |
353
| } |
| |
354
| + |
| |
355
| +.broadcast-message { |
| |
356
| + padding: 10px; |
| |
357
| + text-align: center; |
| |
358
| + background: #555; |
| |
359
| + color: #BBB; |
| |
360
| +} |
| @@ -49,3 +49,9 @@ fieldset legend { |
| @@ -49,3 +49,9 @@ fieldset legend { |
49
| font-size: 16px; |
49
| font-size: 16px; |
50
| margin-bottom: 10px; |
50
| margin-bottom: 10px; |
51
| } |
51
| } |
| |
52
| + |
| |
53
| +.datetime-controls { |
| |
54
| + select { |
| |
55
| + width: 100px; |
| |
56
| + } |
| |
57
| +} |
| @@ -21,3 +21,9 @@ |
| @@ -21,3 +21,9 @@ |
21
| .controls { margin-left: 130px; } |
21
| .controls { margin-left: 130px; } |
22
| .form-actions { padding-left: 130px; background: #fff } |
22
| .form-actions { padding-left: 130px; background: #fff } |
23
| } |
23
| } |
| |
24
| + |
| |
25
| +.broadcast-messages { |
| |
26
| + .message { |
| |
27
| + line-height: 2; |
| |
28
| + } |
| |
29
| +} |
| @@ -0,0 +1,32 @@ |
| @@ -0,0 +1,32 @@ |
| |
1
| +class Admin::BroadcastMessagesController < Admin::ApplicationController |
| |
2
| + before_filter :broadcast_messages |
| |
3
| + |
| |
4
| + def index |
| |
5
| + @broadcast_message = BroadcastMessage.new |
| |
6
| + end |
| |
7
| + |
| |
8
| + def create |
| |
9
| + @broadcast_message = BroadcastMessage.new(params[:broadcast_message]) |
| |
10
| + |
| |
11
| + if @broadcast_message.save |
| |
12
| + redirect_to admin_broadcast_messages_path, notice: 'Broadcast Message was successfully created.' |
| |
13
| + else |
| |
14
| + render :index |
| |
15
| + end |
| |
16
| + end |
| |
17
| + |
| |
18
| + def destroy |
| |
19
| + BroadcastMessage.find(params[:id]).destroy |
| |
20
| + |
| |
21
| + respond_to do |format| |
| |
22
| + format.html { redirect_to :back } |
| |
23
| + format.js { render nothing: true } |
| |
24
| + end |
| |
25
| + end |
| |
26
| + |
| |
27
| + protected |
| |
28
| + |
| |
29
| + def broadcast_messages |
| |
30
| + @broadcast_messages ||= BroadcastMessage.order("starts_at DESC").page(params[:page]) |
| |
31
| + end |
| |
32
| +end |
| @@ -208,4 +208,8 @@ module ApplicationHelper |
| @@ -208,4 +208,8 @@ module ApplicationHelper |
208
| line += "..." if lines.size > 1 |
208
| line += "..." if lines.size > 1 |
209
| line |
209
| line |
210
| end |
210
| end |
| |
211
| + |
| |
212
| + def broadcast_message |
| |
213
| + BroadcastMessage.current |
| |
214
| + end |
211
| end |
215
| end |
| @@ -0,0 +1,11 @@ |
| @@ -0,0 +1,11 @@ |
| |
1
| +class BroadcastMessage < ActiveRecord::Base |
| |
2
| + attr_accessible :alert_type, :ends_at, :message, :starts_at |
| |
3
| + |
| |
4
| + validates :message, presence: true |
| |
5
| + validates :starts_at, presence: true |
| |
6
| + validates :ends_at, presence: true |
| |
7
| + |
| |
8
| + def self.current |
| |
9
| + where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last |
| |
10
| + end |
| |
11
| +end |
| @@ -0,0 +1,46 @@ |
| @@ -0,0 +1,46 @@ |
| |
1
| +%h3.page-title |
| |
2
| + Broadcast Messages |
| |
3
| +%p.light |
| |
4
| + Broadcast messages displayed for every user and can be used to notify application about scheduled maintenance. |
| |
5
| +%hr |
| |
6
| + |
| |
7
| += form_for [:admin, @broadcast_message] do |f| |
| |
8
| + -if @broadcast_message.errors.any? |
| |
9
| + .alert.alert-error |
| |
10
| + - @broadcast_message.errors.full_messages.each do |msg| |
| |
11
| + %p= msg |
| |
12
| + .control-group |
| |
13
| + = f.label :message |
| |
14
| + .controls |
| |
15
| + = f.text_area :message, class: "input-xxlarge", rows: 2, required: true |
| |
16
| + .control-group |
| |
17
| + = f.label :starts_at |
| |
18
| + .controls.datetime-controls |
| |
19
| + = f.datetime_select :starts_at |
| |
20
| + .control-group |
| |
21
| + = f.label :ends_at |
| |
22
| + .controls.datetime-controls |
| |
23
| + = f.datetime_select :ends_at |
| |
24
| + .form-actions |
| |
25
| + = f.submit "Add broadcast message", class: "btn btn-create" |
| |
26
| + |
| |
27
| +-if @broadcast_messages.any? |
| |
28
| + %ul.bordered-list.broadcast-messages |
| |
29
| + - @broadcast_messages.each do |broadcast_message| |
| |
30
| + %li |
| |
31
| + .pull-right |
| |
32
| + - if broadcast_message.starts_at |
| |
33
| + %strong |
| |
34
| + #{broadcast_message.starts_at.to_s(:short)} |
| |
35
| + \... |
| |
36
| + - if broadcast_message.ends_at |
| |
37
| + %strong |
| |
38
| + #{broadcast_message.ends_at.to_s(:short)} |
| |
39
| + |
| |
40
| + = link_to [:admin, broadcast_message], method: :delete, remote: true, class: 'remove-row btn btn-tiny' do |
| |
41
| + %i.icon-remove.cred |
| |
42
| + |
| |
43
| + .message= broadcast_message.message |
| |
44
| + |
| |
45
| + |
| |
46
| + = paginate @broadcast_messages |
| @@ -0,0 +1,4 @@ |
| @@ -0,0 +1,4 @@ |
| |
1
| +- if broadcast_message.present? |
| |
2
| + .broadcast-message |
| |
3
| + %i.icon-bullhorn |
| |
4
| + = broadcast_message.message |
| @@ -2,6 +2,7 @@ |
| @@ -2,6 +2,7 @@ |
2
| %html{ lang: "en"} |
2
| %html{ lang: "en"} |
3
| = render "layouts/head", title: "Dashboard" |
3
| = render "layouts/head", title: "Dashboard" |
4
| %body{class: "#{app_theme} application", :'data-page' => body_data_page } |
4
| %body{class: "#{app_theme} application", :'data-page' => body_data_page } |
| |
5
| + = render "layouts/broadcast" |
5
| = render "layouts/head_panel", title: "Dashboard" |
6
| = render "layouts/head_panel", title: "Dashboard" |
6
| = render "layouts/flash" |
7
| = render "layouts/flash" |
7
| %nav.main-nav |
8
| %nav.main-nav |
| @@ -10,6 +10,8 @@ |
| @@ -10,6 +10,8 @@ |
10
| = link_to "Users", admin_users_path |
10
| = link_to "Users", admin_users_path |
11
| = nav_link(controller: :logs) do |
11
| = nav_link(controller: :logs) do |
12
| = link_to "Logs", admin_logs_path |
12
| = link_to "Logs", admin_logs_path |
| |
13
| + = nav_link(controller: :broadcast_messages) do |
| |
14
| + = link_to "Messages", admin_broadcast_messages_path |
13
| = nav_link(controller: :hooks) do |
15
| = nav_link(controller: :hooks) do |
14
| = link_to "Hooks", admin_hooks_path |
16
| = link_to "Hooks", admin_hooks_path |
15
| = nav_link(controller: :background_jobs) do |
17
| = nav_link(controller: :background_jobs) do |
| @@ -2,6 +2,7 @@ |
| @@ -2,6 +2,7 @@ |
2
| %html{ lang: "en"} |
2
| %html{ lang: "en"} |
3
| = render "layouts/head", title: @project.name_with_namespace |
3
| = render "layouts/head", title: @project.name_with_namespace |
4
| %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } |
4
| %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } |
| |
5
| + = render "layouts/broadcast" |
5
| = render "layouts/head_panel", title: project_title(@project) |
6
| = render "layouts/head_panel", title: project_title(@project) |
6
| = render "layouts/init_auto_complete" |
7
| = render "layouts/init_auto_complete" |
7
| = render "layouts/flash" |
8
| = render "layouts/flash" |
| @@ -86,6 +86,7 @@ Gitlab::Application.routes.draw do |
| @@ -86,6 +86,7 @@ Gitlab::Application.routes.draw do |
86
| get :test |
86
| get :test |
87
| end |
87
| end |
88
| |
88
| |
| |
89
| + resources :broadcast_messages, only: [:index, :create, :destroy] |
89
| resource :logs, only: [:show] |
90
| resource :logs, only: [:show] |
90
| resource :background_jobs, controller: 'background_jobs', only: [:show] |
91
| resource :background_jobs, controller: 'background_jobs', only: [:show] |
91
| resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] |
92
| resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] |
| @@ -0,0 +1,12 @@ |
| @@ -0,0 +1,12 @@ |
| |
1
| +class CreateBroadcastMessages < ActiveRecord::Migration |
| |
2
| + def change |
| |
3
| + create_table :broadcast_messages do |t| |
| |
4
| + t.text :message, null: false |
| |
5
| + t.datetime :starts_at |
| |
6
| + t.datetime :ends_at |
| |
7
| + t.integer :alert_type |
| |
8
| + |
| |
9
| + t.timestamps |
| |
10
| + end |
| |
11
| + end |
| |
12
| +end |
| @@ -11,7 +11,16 @@ |
| @@ -11,7 +11,16 @@ |
11
| # |
11
| # |
12
| # It's strongly recommended to check this file into your version control system. |
12
| # It's strongly recommended to check this file into your version control system. |
13
| |
13
| |
14
| -ActiveRecord::Schema.define(:version => 20131106151520) do |
14
| +ActiveRecord::Schema.define(:version => 20131112114325) do |
| |
15
| + |
| |
16
| + create_table "broadcast_messages", :force => true do |t| |
| |
17
| + t.text "message", :null => false |
| |
18
| + t.datetime "starts_at" |
| |
19
| + t.datetime "ends_at" |
| |
20
| + t.integer "alert_type" |
| |
21
| + t.datetime "created_at", :null => false |
| |
22
| + t.datetime "updated_at", :null => false |
| |
23
| + end |
15
| |
24
| |
16
| create_table "deploy_keys_projects", :force => true do |t| |
25
| create_table "deploy_keys_projects", :force => true do |t| |
17
| t.integer "deploy_key_id", :null => false |
26
| t.integer "deploy_key_id", :null => false |
| @@ -27,6 +27,11 @@ Feature: Admin active tab |
| @@ -27,6 +27,11 @@ Feature: Admin active tab |
27
| Then the active main tab should be Logs |
27
| Then the active main tab should be Logs |
28
| And no other main tabs should be active |
28
| And no other main tabs should be active |
29
| |
29
| |
| |
30
| + Scenario: On Admin Messages |
| |
31
| + Given I visit admin messages page |
| |
32
| + Then the active main tab should be Messages |
| |
33
| + And no other main tabs should be active |
| |
34
| + |
30
| Scenario: On Admin Hooks |
35
| Scenario: On Admin Hooks |
31
| Given I visit admin hooks page |
36
| Given I visit admin hooks page |
32
| Then the active main tab should be Hooks |
37
| Then the active main tab should be Hooks |
| @@ -0,0 +1,13 @@ |
| @@ -0,0 +1,13 @@ |
| |
1
| +Feature: Admin Broadcast Messages |
| |
2
| + Background: |
| |
3
| + Given I sign in as an admin |
| |
4
| + And application already has admin messages |
| |
5
| + And I visit admin messages page |
| |
6
| + |
| |
7
| + Scenario: See broadcast messages list |
| |
8
| + Then I should be all broadcast messages |
| |
9
| + |
| |
10
| + Scenario: Create a broadcast message |
| |
11
| + When submit form with new broadcast message |
| |
12
| + Then I should be redirected to admin messages page |
| |
13
| + And I should see newly created broadcast message |
| @@ -30,4 +30,8 @@ class AdminActiveTab < Spinach::FeatureSteps |
| @@ -30,4 +30,8 @@ class AdminActiveTab < Spinach::FeatureSteps |
30
| Then 'the active main tab should be Resque' do |
30
| Then 'the active main tab should be Resque' do |
31
| ensure_active_main_tab('Background Jobs') |
31
| ensure_active_main_tab('Background Jobs') |
32
| end |
32
| end |
| |
33
| + |
| |
34
| + Then 'the active main tab should be Messages' do |
| |
35
| + ensure_active_main_tab('Messages') |
| |
36
| + end |
33
| end |
37
| end |
| @@ -0,0 +1,27 @@ |
| @@ -0,0 +1,27 @@ |
| |
1
| +class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps |
| |
2
| + include SharedAuthentication |
| |
3
| + include SharedPaths |
| |
4
| + include SharedAdmin |
| |
5
| + |
| |
6
| + step 'application already has admin messages' do |
| |
7
| + FactoryGirl.create(:broadcast_message, message: "Migration to new server") |
| |
8
| + end |
| |
9
| + |
| |
10
| + step 'I should be all broadcast messages' do |
| |
11
| + page.should have_content "Migration to new server" |
| |
12
| + end |
| |
13
| + |
| |
14
| + step 'submit form with new broadcast message' do |
| |
15
| + fill_in 'broadcast_message_message', with: 'Application update from 4:00 CST to 5:00 CST' |
| |
16
| + select '2018', from: "broadcast_message_ends_at_1i" |
| |
17
| + click_button "Add broadcast message" |
| |
18
| + end |
| |
19
| + |
| |
20
| + step 'I should be redirected to admin messages page' do |
| |
21
| + current_path.should == admin_broadcast_messages_path |
| |
22
| + end |
| |
23
| + |
| |
24
| + step 'I should see newly created broadcast message' do |
| |
25
| + page.should have_content 'Application update from 4:00 CST to 5:00 CST' |
| |
26
| + end |
| |
27
| +end |
| @@ -105,6 +105,10 @@ module SharedPaths |
| @@ -105,6 +105,10 @@ module SharedPaths |
105
| visit admin_logs_path |
105
| visit admin_logs_path |
106
| end |
106
| end |
107
| |
107
| |
| |
108
| + step 'I visit admin messages page' do |
| |
109
| + visit admin_broadcast_messages_path |
| |
110
| + end |
| |
111
| + |
108
| step 'I visit admin hooks page' do |
112
| step 'I visit admin hooks page' do |
109
| visit admin_hooks_path |
113
| visit admin_hooks_path |
110
| end |
114
| end |
| @@ -0,0 +1,10 @@ |
| @@ -0,0 +1,10 @@ |
| |
1
| +# Read about factories at https://github.com/thoughtbot/factory_girl |
| |
2
| + |
| |
3
| +FactoryGirl.define do |
| |
4
| + factory :broadcast_message do |
| |
5
| + message "MyText" |
| |
6
| + starts_at "2013-11-12 13:43:25" |
| |
7
| + ends_at "2013-11-12 13:43:25" |
| |
8
| + alert_type 1 |
| |
9
| + end |
| |
10
| +end |
| @@ -0,0 +1,24 @@ |
| @@ -0,0 +1,24 @@ |
| |
1
| +require 'spec_helper' |
| |
2
| + |
| |
3
| +describe BroadcastMessage do |
| |
4
| + subject { create(:broadcast_message) } |
| |
5
| + |
| |
6
| + it { should be_valid } |
| |
7
| + |
| |
8
| + describe :current do |
| |
9
| + it "should return last message if time match" do |
| |
10
| + broadcast_message = create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow) |
| |
11
| + BroadcastMessage.current.should == broadcast_message |
| |
12
| + end |
| |
13
| + |
| |
14
| + it "should return nil if time not come" do |
| |
15
| + broadcast_message = create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days) |
| |
16
| + BroadcastMessage.current.should be_nil |
| |
17
| + end |
| |
18
| + |
| |
19
| + it "should return nil if time has passed" do |
| |
20
| + broadcast_message = create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday) |
| |
21
| + BroadcastMessage.current.should be_nil |
| |
22
| + end |
| |
23
| + end |
| |
24
| +end |