Description:
merge
Commit status:
[Not Reviewed]
References:
merge algo
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r840:b948bb241476 - - 9 files changed: 113 inserted, 49 deleted

@@ -0,0 +1,25
1 + = simple_form_for(@announcement) do |f|
2 + - if @announcement.errors.any?
3 + .form-row
4 + .col-sm-12
5 + #error_explanation.alert.alert-dismissable.alert-danger
6 + %button.close{type: "button", data: { dismiss: "alert"}, aria: {hidden: "true"}} ×
7 + %h3= "เกิดปัญหาในการบันทึกข้อมูลเนื่องจาก"
8 + %ul
9 + - @announcement.errors.full_messages.each do |message|
10 + %li= message
11 + .form-row
12 + .col-md-6.col-12
13 + -# = f.input :lock_version, as: :hidden
14 + = f.input :title
15 + = f.input :notes, label: 'Notes (shown internally, used to organize announcements)'
16 + = f.input :body
17 + = f.input :author
18 + = f.input :published
19 + = f.input :frontpage, label: 'Display in the front page only?'
20 + = f.input :on_nav_bar, label: 'Show on menu bar?', wrapper: :custom_boolean
21 + = f.input :contest_only, label: 'Display in contest only?'
22 + = f.submit "Create", class: 'btn btn-primary'
23 + -if content_for?(:form_buttons)
24 + = yield(:form_buttons)
25 + / = link_to 'Back', announcements_path, class: 'btn btn-default'
@@ -0,0 +1,5
1 + class AddOnNavBarToAnnouncement < ActiveRecord::Migration[5.2]
2 + def change
3 + add_column :announcements, :on_nav_bar, :boolean, default: false
4 + end
5 + end
@@ -18,99 +18,99
18 # GET /announcements/1
18 # GET /announcements/1
19 # GET /announcements/1.xml
19 # GET /announcements/1.xml
20 def show
20 def show
21 @announcement = Announcement.find(params[:id])
21 @announcement = Announcement.find(params[:id])
22
22
23 respond_to do |format|
23 respond_to do |format|
24 format.html # show.html.erb
24 format.html # show.html.erb
25 format.xml { render :xml => @announcement }
25 format.xml { render :xml => @announcement }
26 end
26 end
27 end
27 end
28
28
29 # GET /announcements/new
29 # GET /announcements/new
30 # GET /announcements/new.xml
30 # GET /announcements/new.xml
31 def new
31 def new
32 @announcement = Announcement.new
32 @announcement = Announcement.new
33
33
34 respond_to do |format|
34 respond_to do |format|
35 format.html # new.html.erb
35 format.html # new.html.erb
36 format.xml { render :xml => @announcement }
36 format.xml { render :xml => @announcement }
37 end
37 end
38 end
38 end
39
39
40 # GET /announcements/1/edit
40 # GET /announcements/1/edit
41 def edit
41 def edit
42 @announcement = Announcement.find(params[:id])
42 @announcement = Announcement.find(params[:id])
43 end
43 end
44
44
45 # POST /announcements
45 # POST /announcements
46 # POST /announcements.xml
46 # POST /announcements.xml
47 def create
47 def create
48 @announcement = Announcement.new(announcement_params)
48 @announcement = Announcement.new(announcement_params)
49
49
50 respond_to do |format|
50 respond_to do |format|
51 if @announcement.save
51 if @announcement.save
52 flash[:notice] = 'Announcement was successfully created.'
52 flash[:notice] = 'Announcement was successfully created.'
53 format.html { redirect_to(@announcement) }
53 format.html { redirect_to(@announcement) }
54 format.xml { render :xml => @announcement, :status => :created, :location => @announcement }
54 format.xml { render :xml => @announcement, :status => :created, :location => @announcement }
55 else
55 else
56 format.html { render :action => "new" }
56 format.html { render :action => "new" }
57 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
57 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
58 end
58 end
59 end
59 end
60 end
60 end
61
61
62 # PUT /announcements/1
62 # PUT /announcements/1
63 # PUT /announcements/1.xml
63 # PUT /announcements/1.xml
64 def update
64 def update
65 @announcement = Announcement.find(params[:id])
65 @announcement = Announcement.find(params[:id])
66
66
67 respond_to do |format|
67 respond_to do |format|
68 if @announcement.update_attributes(announcement_params)
68 if @announcement.update_attributes(announcement_params)
69 flash[:notice] = 'Announcement was successfully updated.'
69 flash[:notice] = 'Announcement was successfully updated.'
70 format.html { redirect_to(@announcement) }
70 format.html { redirect_to(@announcement) }
71 format.js {}
71 format.js {}
72 format.xml { head :ok }
72 format.xml { head :ok }
73 else
73 else
74 format.html { render :action => "edit" }
74 format.html { render :action => "edit" }
75 format.js {}
75 format.js {}
76 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
76 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
77 end
77 end
78 end
78 end
79 end
79 end
80
80
81 def toggle
81 def toggle
82 @announcement = Announcement.find(params[:id])
82 @announcement = Announcement.find(params[:id])
83 @announcement.update_attributes( published: !@announcement.published? )
83 @announcement.update_attributes( published: !@announcement.published? )
84 respond_to do |format|
84 respond_to do |format|
85 format.js { render partial: 'toggle_button',
85 format.js { render partial: 'toggle_button',
86 locals: {button_id: "#announcement_toggle_#{@announcement.id}",button_on: @announcement.published? } }
86 locals: {button_id: "#announcement_toggle_#{@announcement.id}",button_on: @announcement.published? } }
87 end
87 end
88 end
88 end
89
89
90 def toggle_front
90 def toggle_front
91 @announcement = Announcement.find(params[:id])
91 @announcement = Announcement.find(params[:id])
92 @announcement.update_attributes( frontpage: !@announcement.frontpage? )
92 @announcement.update_attributes( frontpage: !@announcement.frontpage? )
93 respond_to do |format|
93 respond_to do |format|
94 format.js { render partial: 'toggle_button',
94 format.js { render partial: 'toggle_button',
95 locals: {button_id: "#announcement_toggle_front_#{@announcement.id}",button_on: @announcement.frontpage? } }
95 locals: {button_id: "#announcement_toggle_front_#{@announcement.id}",button_on: @announcement.frontpage? } }
96 end
96 end
97 end
97 end
98
98
99 # DELETE /announcements/1
99 # DELETE /announcements/1
100 # DELETE /announcements/1.xml
100 # DELETE /announcements/1.xml
101 def destroy
101 def destroy
102 @announcement = Announcement.find(params[:id])
102 @announcement = Announcement.find(params[:id])
103 @announcement.destroy
103 @announcement.destroy
104
104
105 respond_to do |format|
105 respond_to do |format|
106 format.html { redirect_to(announcements_url) }
106 format.html { redirect_to(announcements_url) }
107 format.xml { head :ok }
107 format.xml { head :ok }
108 end
108 end
109 end
109 end
110
110
111 private
111 private
112
112
113 def announcement_params
113 def announcement_params
114 - params.require(:announcement).permit(:author, :body, :published, :frontpage, :contest_only, :title)
114 + params.require(:announcement).permit(:author, :body, :published, :frontpage, :contest_only, :title, :on_nav_bar)
115 end
115 end
116 end
116 end
@@ -1,120 +1,125
1 require 'ipaddr'
1 require 'ipaddr'
2
2
3 class ApplicationController < ActionController::Base
3 class ApplicationController < ActionController::Base
4 protect_from_forgery
4 protect_from_forgery
5
5
6 before_action :current_user
6 before_action :current_user
7 + before_action :nav_announcement
7
8
8 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
9 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
9 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
10 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
10 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
11 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
11 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
12 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
12
13
13 #report and redirect for unauthorized activities
14 #report and redirect for unauthorized activities
14 def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
15 def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
15 flash[:notice] = notice
16 flash[:notice] = notice
16 redirect_to login_main_path
17 redirect_to login_main_path
17 end
18 end
18
19
19 # Returns the current logged-in user (if any).
20 # Returns the current logged-in user (if any).
20 def current_user
21 def current_user
21 return nil unless session[:user_id]
22 return nil unless session[:user_id]
22 @current_user ||= User.find(session[:user_id])
23 @current_user ||= User.find(session[:user_id])
23 end
24 end
24
25
26 + def nav_announcement
27 + @nav_announcement = Announcement.where(on_nav_bar: true)
28 + end
29 +
25 def admin_authorization
30 def admin_authorization
26 return false unless check_valid_login
31 return false unless check_valid_login
27 user = User.includes(:roles).find(session[:user_id])
32 user = User.includes(:roles).find(session[:user_id])
28 unless user.admin?
33 unless user.admin?
29 unauthorized_redirect
34 unauthorized_redirect
30 return false
35 return false
31 end
36 end
32 return true
37 return true
33 end
38 end
34
39
35 def authorization_by_roles(allowed_roles)
40 def authorization_by_roles(allowed_roles)
36 return false unless check_valid_login
41 return false unless check_valid_login
37 unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
42 unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
38 unauthorized_redirect
43 unauthorized_redirect
39 return false
44 return false
40 end
45 end
41 end
46 end
42
47
43 def testcase_authorization
48 def testcase_authorization
44 #admin always has privileged
49 #admin always has privileged
45 if @current_user.admin?
50 if @current_user.admin?
46 return true
51 return true
47 end
52 end
48
53
49 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
54 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
50 end
55 end
51
56
52
57
53 protected
58 protected
54
59
55 #redirect to root (and also force logout)
60 #redirect to root (and also force logout)
56 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
61 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
57 def check_valid_login
62 def check_valid_login
58 #check if logged in
63 #check if logged in
59 unless session[:user_id]
64 unless session[:user_id]
60 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
65 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
61 unauthorized_redirect('You need to login but you cannot log in at this time')
66 unauthorized_redirect('You need to login but you cannot log in at this time')
62 else
67 else
63 unauthorized_redirect('You need to login')
68 unauthorized_redirect('You need to login')
64 end
69 end
65 return false
70 return false
66 end
71 end
67
72
68 # check if run in single user mode
73 # check if run in single user mode
69 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
74 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
70 if @current_user==nil || (!@current_user.admin?)
75 if @current_user==nil || (!@current_user.admin?)
71 unauthorized_redirect('You cannot log in at this time')
76 unauthorized_redirect('You cannot log in at this time')
72 return false
77 return false
73 end
78 end
74 end
79 end
75
80
76 # check if the user is enabled
81 # check if the user is enabled
77 unless @current_user.enabled? || @current_user.admin?
82 unless @current_user.enabled? || @current_user.admin?
78 unauthorized_redirect 'Your account is disabled'
83 unauthorized_redirect 'Your account is disabled'
79 return false
84 return false
80 end
85 end
81
86
82 # check if user ip is allowed
87 # check if user ip is allowed
83 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
88 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
84 unless is_request_ip_allowed?
89 unless is_request_ip_allowed?
85 unauthorized_redirect 'Your IP is not allowed to login at this time.'
90 unauthorized_redirect 'Your IP is not allowed to login at this time.'
86 return false
91 return false
87 end
92 end
88 end
93 end
89
94
90 if GraderConfiguration.multicontests?
95 if GraderConfiguration.multicontests?
91 return true if @current_user.admin?
96 return true if @current_user.admin?
92 begin
97 begin
93 if @current_user.contest_stat(true).forced_logout
98 if @current_user.contest_stat(true).forced_logout
94 flash[:notice] = 'You have been automatically logged out.'
99 flash[:notice] = 'You have been automatically logged out.'
95 redirect_to :controller => 'main', :action => 'index'
100 redirect_to :controller => 'main', :action => 'index'
96 end
101 end
97 rescue
102 rescue
98 end
103 end
99 end
104 end
100 return true
105 return true
101 end
106 end
102
107
103 #redirect to root (and also force logout)
108 #redirect to root (and also force logout)
104 #if the user use different ip from the previous connection
109 #if the user use different ip from the previous connection
105 # only applicable when MULTIPLE_IP_LOGIN options is false only
110 # only applicable when MULTIPLE_IP_LOGIN options is false only
106 def authenticate_by_ip_address
111 def authenticate_by_ip_address
107 #this assume that we have already authenticate normally
112 #this assume that we have already authenticate normally
108 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
113 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
109 user = User.find(session[:user_id])
114 user = User.find(session[:user_id])
110 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
115 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
111 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
116 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
112 redirect_to :controller => 'main', :action => 'login'
117 redirect_to :controller => 'main', :action => 'login'
113 return false
118 return false
114 end
119 end
115 unless user.last_ip
120 unless user.last_ip
116 user.last_ip = request.remote_ip
121 user.last_ip = request.remote_ip
117 user.save
122 user.save
118 end
123 end
119 end
124 end
120 return true
125 return true
@@ -1,34 +1,45
1 - .container-fluid
1 + %h1 Edit Announcement
2 - %h1 Editing announcement
2 +
3 - = error_messages_for :announcement
3 + -content_for(:form_buttons) do
4 - .row
4 + = link_to t(:back), announcements_path, class: 'card-link btn btn-secondary'
5 - .col-md-6
5 +
6 - = form_for(@announcement) do |f|
6 + = render 'form'
7 - .form-group
7 + -# old style
8 - %label Title
8 + .container-fluid
9 - = f.text_field :title, class: 'form-control'
9 + %h1 Editing announcement
10 - .form-group
10 + = error_messages_for :announcement
11 - %label Notes
11 + .row
12 - (shown internally, used to organize announcements)
12 + .col-md-6
13 - = f.text_field :notes, class: 'form-control'
13 + = form_for(@announcement) do |f|
14 - .form-group
14 + .form-group
15 - %label Body
15 + %label Title
16 - = f.text_area :body, class: 'form-control', style: 'height: 200px;'
16 + = f.text_field :title, class: 'form-control'
17 - .form-group
17 + .form-group
18 - %label Author
18 + %label Notes
19 - = f.text_field :author, class: 'form-control'
19 + (shown internally, used to organize announcements)
20 - .checkbox
20 + = f.text_field :notes, class: 'form-control'
21 - %label
21 + .form-group
22 - = f.check_box :published
22 + %label Body
23 - Published
23 + = f.text_area :body, class: 'form-control', style: 'height: 200px;'
24 - .checkbox
24 + .form-group
25 - %label
25 + %label Author
26 - = f.check_box :frontpage
26 + = f.text_field :author, class: 'form-control'
27 - Show on front page?
27 + .checkbox
28 - .checkbox
28 + %label
29 - %label
29 + = f.check_box :published
30 - = f.check_box :contest_only
30 + Published
31 - Show only in contest?
31 + .checkbox
32 - = f.submit "Update", class: 'btn btn-primary'
32 + %label
33 - = link_to 'Show', @announcement, class: 'btn btn-default'
33 + = f.check_box :frontpage
34 - = link_to 'Back', announcements_path, class: 'btn btn-default'
34 + Show on front page?
35 + .checkbox
36 + %label
37 + = f.check_box :on_nav_bar
38 + Show on top menu bar?
39 + .checkbox
40 + %label
41 + = f.check_box :contest_only
42 + Show only in contest?
43 + = f.submit "Update", class: 'btn btn-primary'
44 + = link_to 'Show', @announcement, class: 'btn btn-default'
45 + = link_to 'Back', announcements_path, class: 'btn btn-default'
@@ -1,14 +1,22
1 %h1 New announcement
1 %h1 New announcement
2 - = error_messages_for :announcement
2 +
3 - = simple_form_for(@announcement) do |f|
3 + -content_for(:form_buttons) do
4 - .row
4 + = link_to t(:back), announcements_path, class: 'card-link btn btn-secondary'
5 - .col-md-6
5 +
6 - = f.input :title
6 + = render 'form'
7 - = f.input :notes, label: 'Notes (shown internally, used to organize announcements)'
7 +
8 - = f.input :body
8 + -# old style
9 - = f.input :author
9 + = error_messages_for :announcement
10 - = f.input :published
10 + = simple_form_for(@announcement) do |f|
11 - = f.input :frontpage, label: 'Display in the front page only?'
11 + .row
12 - = f.input :contest_only, label: 'Display in contest only?'
12 + .col-md-6
13 - = f.button :submit, "Create", class: 'btn btn-primary'
13 + = f.input :title
14 - = link_to 'Back', announcements_path, class: 'btn btn-default'
14 + = f.input :notes, label: 'Notes (shown internally, used to organize announcements)'
15 + = f.input :body
16 + = f.input :author
17 + = f.input :published
18 + = f.input :frontpage, label: 'Display in the front page only?'
19 + = f.input :contest_only, label: 'Display in contest only?'
20 + = f.button :submit, "Create", class: 'btn btn-primary'
21 + = link_to 'Back', announcements_path, class: 'btn btn-default'
22 +
@@ -1,24 +1,27
1 %p
1 %p
2 %b Author:
2 %b Author:
3 = h @announcement.author
3 = h @announcement.author
4 %p
4 %p
5 %b Title:
5 %b Title:
6 = h @announcement.title
6 = h @announcement.title
7 %p
7 %p
8 %b Notes:
8 %b Notes:
9 = h @announcement.notes
9 = h @announcement.notes
10 %p
10 %p
11 %b Body:
11 %b Body:
12 = h markdown(@announcement.body)
12 = h markdown(@announcement.body)
13 %p
13 %p
14 %b Published:
14 %b Published:
15 = h @announcement.published
15 = h @announcement.published
16 %p
16 %p
17 %b Show on front page:
17 %b Show on front page:
18 = h @announcement.frontpage
18 = h @announcement.frontpage
19 %p
19 %p
20 + %b Show on top menu bar:
21 + = h @announcement.on_nav_bar
22 + %p
20 %b Show only in contest:
23 %b Show only in contest:
21 = h @announcement.contest_only
24 = h @announcement.contest_only
22 = link_to 'Edit', edit_announcement_path(@announcement)
25 = link_to 'Edit', edit_announcement_path(@announcement)
23 |
26 |
24 = link_to 'Back', announcements_path
27 = link_to 'Back', announcements_path
@@ -1,96 +1,102
1 %header.navbar.navbar-default.navbar-fixed-top
1 %header.navbar.navbar-default.navbar-fixed-top
2 %nav
2 %nav
3 .container-fluid
3 .container-fluid
4 .navbar-header
4 .navbar-header
5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
6 %span.sr-only Togggle Navigation
6 %span.sr-only Togggle Navigation
7 %span.icon-bar
7 %span.icon-bar
8 %span.icon-bar
8 %span.icon-bar
9 %span.icon-bar
9 %span.icon-bar
10 %a.navbar-brand{href: list_main_path}
10 %a.navbar-brand{href: list_main_path}
11 %span.glyphicon.glyphicon-home
11 %span.glyphicon.glyphicon-home
12 MAIN
12 MAIN
13 .collapse.navbar-collapse#navbar-collapse
13 .collapse.navbar-collapse#navbar-collapse
14 %ul.nav.navbar-nav
14 %ul.nav.navbar-nav
15 / submission
15 / submission
16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
17 %li.dropdown
17 %li.dropdown
18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
19 = "#{I18n.t 'menu.submissions'}"
19 = "#{I18n.t 'menu.submissions'}"
20 %span.caret
20 %span.caret
21 %ul.dropdown-menu
21 %ul.dropdown-menu
22 = add_menu("View", 'submissions', 'index')
22 = add_menu("View", 'submissions', 'index')
23 = add_menu("Self Test", 'test', 'index')
23 = add_menu("Self Test", 'test', 'index')
24 / hall of fame
24 / hall of fame
25 - if GraderConfiguration['right.user_hall_of_fame']
25 - if GraderConfiguration['right.user_hall_of_fame']
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
27 / display MODE button (with countdown in contest mode)
27 / display MODE button (with countdown in contest mode)
28 - if GraderConfiguration.analysis_mode?
28 - if GraderConfiguration.analysis_mode?
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
30 - elsif GraderConfiguration.time_limit_mode?
30 - elsif GraderConfiguration.time_limit_mode?
31 - if @current_user.contest_finished?
31 - if @current_user.contest_finished?
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
33 - elsif !@current_user.contest_started?
33 - elsif !@current_user.contest_started?
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
35 - else
35 - else
36 %div.navbar-btn.btn.btn-primary#countdown asdf
36 %div.navbar-btn.btn.btn-primary#countdown asdf
37 :javascript
37 :javascript
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
39 / admin section
39 / admin section
40 - if (@current_user!=nil) and (session[:admin])
40 - if (@current_user!=nil) and (session[:admin])
41 / management
41 / management
42 %li.dropdown
42 %li.dropdown
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
44 Manage
44 Manage
45 %span.caret
45 %span.caret
46 %ul.dropdown-menu
46 %ul.dropdown-menu
47 = add_menu( 'Announcements', 'announcements', 'index')
47 = add_menu( 'Announcements', 'announcements', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
49 = add_menu( 'Tags', 'tags', 'index')
49 = add_menu( 'Tags', 'tags', 'index')
50 = add_menu( 'Users', 'user_admin', 'index')
50 = add_menu( 'Users', 'user_admin', 'index')
51 = add_menu( 'User Groups', 'groups', 'index')
51 = add_menu( 'User Groups', 'groups', 'index')
52 = add_menu( 'Graders', 'graders', 'list')
52 = add_menu( 'Graders', 'graders', 'list')
53 = add_menu( 'Message ', 'messages', 'console')
53 = add_menu( 'Message ', 'messages', 'console')
54 %li.divider{role: 'separator'}
54 %li.divider{role: 'separator'}
55 = add_menu( 'System config', 'configurations', 'index')
55 = add_menu( 'System config', 'configurations', 'index')
56 %li.divider{role: 'separator'}
56 %li.divider{role: 'separator'}
57 = add_menu( 'Sites', 'sites', 'index')
57 = add_menu( 'Sites', 'sites', 'index')
58 = add_menu( 'Contests', 'contest_management', 'index')
58 = add_menu( 'Contests', 'contest_management', 'index')
59 / report
59 / report
60 %li.dropdown
60 %li.dropdown
61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
62 Report
62 Report
63 %span.caret
63 %span.caret
64 %ul.dropdown-menu
64 %ul.dropdown-menu
65 = add_menu( 'Current Score', 'report', 'current_score')
65 = add_menu( 'Current Score', 'report', 'current_score')
66 = add_menu( 'Score Report', 'report', 'max_score')
66 = add_menu( 'Score Report', 'report', 'max_score')
67 = add_menu( 'Submission Report', 'report', 'submission')
67 = add_menu( 'Submission Report', 'report', 'submission')
68 = add_menu( 'Login Report', 'report', 'login')
68 = add_menu( 'Login Report', 'report', 'login')
69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
70 =link_to "#{ungraded} backlogs!",
70 =link_to "#{ungraded} backlogs!",
71 graders_list_path,
71 graders_list_path,
72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
73 + / announcement
74 + - @nav_announcement.each do |ann|
75 + %p.navbar-text
76 + = ann.body.html_safe
77 +
78 +
73
79
74 %ul.nav.navbar-nav.navbar-right
80 %ul.nav.navbar-nav.navbar-right
75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
81 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
82 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
77 - if GraderConfiguration['system.user_setting_enabled']
83 - if GraderConfiguration['system.user_setting_enabled']
78 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog', id: 'user_profile')}".html_safe, 'users', 'profile', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
84 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog', id: 'user_profile')}".html_safe, 'users', 'profile', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
79 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
85 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
80
86
81 /
87 /
82 - if (@current_user!=nil) and (session[:admin])
88 - if (@current_user!=nil) and (session[:admin])
83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
89 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
84 .container-fluid
90 .container-fluid
85 .collapse.navbar-collapse
91 .collapse.navbar-collapse
86 %ul.nav.navbar-nav
92 %ul.nav.navbar-nav
87 = add_menu( '[Announcements]', 'announcements', 'index')
93 = add_menu( '[Announcements]', 'announcements', 'index')
88 = add_menu( '[Msg console]', 'messages', 'console')
94 = add_menu( '[Msg console]', 'messages', 'console')
89 = add_menu( '[Problems]', 'problems', 'index')
95 = add_menu( '[Problems]', 'problems', 'index')
90 = add_menu( '[Users]', 'user_admin', 'index')
96 = add_menu( '[Users]', 'user_admin', 'index')
91 = add_menu( '[Results]', 'user_admin', 'user_stat')
97 = add_menu( '[Results]', 'user_admin', 'user_stat')
92 = add_menu( '[Report]', 'report', 'multiple_login')
98 = add_menu( '[Report]', 'report', 'multiple_login')
93 = add_menu( '[Graders]', 'graders', 'list')
99 = add_menu( '[Graders]', 'graders', 'list')
94 = add_menu( '[Contests]', 'contest_management', 'index')
100 = add_menu( '[Contests]', 'contest_management', 'index')
95 = add_menu( '[Sites]', 'sites', 'index')
101 = add_menu( '[Sites]', 'sites', 'index')
96 = add_menu( '[System config]', 'configurations', 'index')
102 = add_menu( '[System config]', 'configurations', 'index')
@@ -1,120 +1,121
1 # This file is auto-generated from the current state of the database. Instead
1 # This file is auto-generated from the current state of the database. Instead
2 # of editing this file, please use the migrations feature of Active Record to
2 # of editing this file, please use the migrations feature of Active Record to
3 # incrementally modify your database, and then regenerate this schema definition.
3 # incrementally modify your database, and then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your
5 # Note that this schema.rb definition is the authoritative source for your
6 # database schema. If you need to create the application database on another
6 # database schema. If you need to create the application database on another
7 # system, you should be using db:schema:load, not running all the migrations
7 # system, you should be using db:schema:load, not running all the migrations
8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 #
10 #
11 # It's strongly recommended that you check this file into your version control system.
11 # It's strongly recommended that you check this file into your version control system.
12
12
13 - ActiveRecord::Schema.define(version: 2020_08_13_083020) do
13 + ActiveRecord::Schema.define(version: 2021_01_24_101028) do
14
14
15 create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
15 create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
16 t.string "author"
16 t.string "author"
17 t.text "body"
17 t.text "body"
18 t.boolean "published"
18 t.boolean "published"
19 t.datetime "created_at", null: false
19 t.datetime "created_at", null: false
20 t.datetime "updated_at", null: false
20 t.datetime "updated_at", null: false
21 t.boolean "frontpage", default: false
21 t.boolean "frontpage", default: false
22 t.boolean "contest_only", default: false
22 t.boolean "contest_only", default: false
23 t.string "title"
23 t.string "title"
24 t.string "notes"
24 t.string "notes"
25 + t.boolean "on_nav_bar", default: false
25 end
26 end
26
27
27 create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
28 create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
28 t.string "title"
29 t.string "title"
29 t.boolean "enabled"
30 t.boolean "enabled"
30 t.datetime "created_at", null: false
31 t.datetime "created_at", null: false
31 t.datetime "updated_at", null: false
32 t.datetime "updated_at", null: false
32 t.string "name"
33 t.string "name"
33 end
34 end
34
35
35 create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
36 create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
36 t.integer "contest_id"
37 t.integer "contest_id"
37 t.integer "problem_id"
38 t.integer "problem_id"
38 end
39 end
39
40
40 create_table "contests_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
41 create_table "contests_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
41 t.integer "contest_id"
42 t.integer "contest_id"
42 t.integer "user_id"
43 t.integer "user_id"
43 end
44 end
44
45
45 create_table "countries", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
46 create_table "countries", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
46 t.string "name"
47 t.string "name"
47 t.datetime "created_at", null: false
48 t.datetime "created_at", null: false
48 t.datetime "updated_at", null: false
49 t.datetime "updated_at", null: false
49 end
50 end
50
51
51 create_table "descriptions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
52 create_table "descriptions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
52 t.text "body"
53 t.text "body"
53 t.boolean "markdowned"
54 t.boolean "markdowned"
54 t.datetime "created_at", null: false
55 t.datetime "created_at", null: false
55 t.datetime "updated_at", null: false
56 t.datetime "updated_at", null: false
56 end
57 end
57
58
58 create_table "grader_configurations", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
59 create_table "grader_configurations", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
59 t.string "key"
60 t.string "key"
60 t.string "value_type"
61 t.string "value_type"
61 t.string "value"
62 t.string "value"
62 t.datetime "created_at", null: false
63 t.datetime "created_at", null: false
63 t.datetime "updated_at", null: false
64 t.datetime "updated_at", null: false
64 t.text "description"
65 t.text "description"
65 end
66 end
66
67
67 create_table "grader_processes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
68 create_table "grader_processes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
68 t.string "host"
69 t.string "host"
69 t.integer "pid"
70 t.integer "pid"
70 t.string "mode"
71 t.string "mode"
71 t.boolean "active"
72 t.boolean "active"
72 t.datetime "created_at", null: false
73 t.datetime "created_at", null: false
73 t.datetime "updated_at", null: false
74 t.datetime "updated_at", null: false
74 t.integer "task_id"
75 t.integer "task_id"
75 t.string "task_type"
76 t.string "task_type"
76 t.boolean "terminated"
77 t.boolean "terminated"
77 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
78 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
78 end
79 end
79
80
80 create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
81 create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
81 t.string "name"
82 t.string "name"
82 t.string "description"
83 t.string "description"
83 t.boolean "enabled", default: true
84 t.boolean "enabled", default: true
84 end
85 end
85
86
86 create_table "groups_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
87 create_table "groups_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
87 t.integer "problem_id", null: false
88 t.integer "problem_id", null: false
88 t.integer "group_id", null: false
89 t.integer "group_id", null: false
89 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
90 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
90 end
91 end
91
92
92 create_table "groups_users", options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
93 create_table "groups_users", options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
93 t.integer "group_id", null: false
94 t.integer "group_id", null: false
94 t.integer "user_id", null: false
95 t.integer "user_id", null: false
95 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
96 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
96 end
97 end
97
98
98 create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
99 create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
99 t.integer "user_id"
100 t.integer "user_id"
100 t.string "ip_address"
101 t.string "ip_address"
101 t.datetime "created_at", null: false
102 t.datetime "created_at", null: false
102 t.datetime "updated_at", null: false
103 t.datetime "updated_at", null: false
103 t.string "status"
104 t.string "status"
104 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
105 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
105 end
106 end
106
107
107 create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
108 create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
108 t.string "name", limit: 10
109 t.string "name", limit: 10
109 t.string "pretty_name"
110 t.string "pretty_name"
110 t.string "ext", limit: 10
111 t.string "ext", limit: 10
111 t.string "common_ext"
112 t.string "common_ext"
112 end
113 end
113
114
114 create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
115 create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
115 t.integer "user_id"
116 t.integer "user_id"
116 t.string "ip_address"
117 t.string "ip_address"
117 t.datetime "created_at", null: false
118 t.datetime "created_at", null: false
118 t.datetime "updated_at", null: false
119 t.datetime "updated_at", null: false
119 t.index ["user_id"], name: "index_logins_on_user_id"
120 t.index ["user_id"], name: "index_logins_on_user_id"
120 end
121 end
You need to be logged in to leave comments. Login now