diff --git a/Gemfile.lock b/Gemfile.lock --- a/Gemfile.lock +++ b/Gemfile.lock @@ -78,7 +78,7 @@ treetop (~> 1.4.8) mime-types (1.25.1) multi_json (1.10.1) - mysql2 (0.3.19) + mysql2 (0.3.20) polyglot (0.3.5) power_assert (0.2.2) prototype-rails (3.2.1) diff --git a/app/controllers/configurations_controller.rb b/app/controllers/configurations_controller.rb --- a/app/controllers/configurations_controller.rb +++ b/app/controllers/configurations_controller.rb @@ -16,7 +16,7 @@ def update @config = GraderConfiguration.find(params[:id]) - User.clear_last_login if @config.key = 'multiple_ip_login' and @config.value == 'true' and params[:grader_configuration][:value] == 'false' + User.clear_last_login if @config.key == GraderConfiguration::MULTIPLE_IP_LOGIN_KEY and @config.value == 'true' and params[:grader_configuration][:value] == 'false' respond_to do |format| if @config.update_attributes(params[:grader_configuration]) format.json { head :ok } diff --git a/app/controllers/graders_controller.rb b/app/controllers/graders_controller.rb --- a/app/controllers/graders_controller.rb +++ b/app/controllers/graders_controller.rb @@ -86,6 +86,9 @@ @formatted_code = formatter.format(lexer.lex(@submission.source)) @css_style = Rouge::Themes::ThankfulEyes.render(scope: '.highlight') + user = User.find(session[:user_id]) + SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin? + end # various grader controls diff --git a/app/controllers/problems_controller.rb b/app/controllers/problems_controller.rb --- a/app/controllers/problems_controller.rb +++ b/app/controllers/problems_controller.rb @@ -163,7 +163,7 @@ @submissions.find_each do |sub| d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 @histogram[:data][d.to_i] += 1 if d < range - user[sub.user_id] = [user[sub.user_id], (sub.try(:points) >= @problem.full_score) ? 1 : 0].max + user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max end @histogram[:summary][:max] = [@histogram[:data].max,1].max diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -125,7 +125,7 @@ @summary[:count] += 1 next unless sub.problem - problem[sub.problem] = [problem[sub.problem], (sub.points >= sub.problem.full_score) ? 1 : 0].max + problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max end @histogram[:summary][:max] = [@histogram[:data].max,1].max diff --git a/app/models/grader_configuration.rb b/app/models/grader_configuration.rb --- a/app/models/grader_configuration.rb +++ b/app/models/grader_configuration.rb @@ -9,6 +9,7 @@ TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout' MULTICONTESTS_KEY = 'system.multicontests' CONTEST_TIME_LIMIT_KEY = 'contest.time_limit' + MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login' cattr_accessor :config_cache cattr_accessor :task_grading_info_cache diff --git a/app/models/submission_view_log.rb b/app/models/submission_view_log.rb new file mode 100644 --- /dev/null +++ b/app/models/submission_view_log.rb @@ -0,0 +1,3 @@ +class SubmissionViewLog < ActiveRecord::Base + attr_accessible :submission_id, :user_id +end diff --git a/app/views/report/cheat_scruntinize.html.haml b/app/views/report/cheat_scruntinize.html.haml new file mode 100644 --- /dev/null +++ b/app/views/report/cheat_scruntinize.html.haml @@ -0,0 +1,82 @@ +- content_for :header do + = stylesheet_link_tag 'tablesorter-theme.cafe' + = javascript_include_tag 'local_jquery' + +%script{:type=>"text/javascript"} + $(function () { + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} ); + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} ); + $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']}); + $('#my_table2').tablesorter({widthFixed: true, widgets: ['zebra']}); + $('#sub_table').tablesorter({widthFixed: true, widgets: ['zebra']}); + }); + +%h1 Login status + +=render partial: 'report_menu' + + += form_tag({session: :url }) do + .submitbox + %table + %tr + %td{colspan: 6, style: 'font-weight: bold'}= 'Query login & submit in the range' + %tr + %td{style: 'width: 120px; font-weight: bold'}= 'Login date range' + %td{align: 'right'} since: + %td= text_field_tag 'since_datetime', @since_time + %tr + %td + %td{align: 'right'} until: + %td= text_field_tag 'until_datetime', @until_time + %tr + %td + %td + %td Blank mean no condition + %tr + %td{style: 'width: 120px; font-weight: bold'}= "ID" + %td{colspan: 2}= text_field_tag 'SID', @sid, size: 40 + %tr + %td + %td + %td= submit_tag 'query' + + +%h2 Logs + +- if @sid + %table + %tbody + - @sid.each do |id| + - user = User.where("login = ?",id).first + %tr + //%td= link_to id, controller: :user, action: :profile, id: id + %td= link_to id, "https://www.nattee.net/java/users/profile/#{user.id}" + %td= user.full_name + +//%table.tablesorter-cafe#my_table +%table.info + %thead + %tr.info-head + %th Time + %th Action + %th IP + %th login + %th name + %th problem + %th score + %tbody + - if @logs + - @logs.each do |l| + %tr{class: cycle('info-even','info-odd')} + %td= l[:submitted_at].strftime "%Y.%b.%d %H:%M:%S" + //%td= l[:id] == -1 ? "LOGIN" : link_to("submit #{l[:id]}", controller: 'graders' , action: 'submission', id: l[:id]) + %td= l[:id] == -1 ? "LOGIN" : link_to( "submit #{l[:id]}", "https://www.nattee.net/java/graders/submission/#{l[:id]}") + %td= l[:ip_address] + //%td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id] + %td= link_to( l[:login], "https://www.nattee.net/java/users/profile/#{l.user_id}") + %td= l[:full_name] + %td= l[:id] == -1 ? "" : l.problem.name + %td= l[:id] == -1 ? "" : l.points * 100/ l.problem.full_score + + diff --git a/app/views/users/profile.html.haml b/app/views/users/profile.html.haml --- a/app/views/users/profile.html.haml +++ b/app/views/users/profile.html.haml @@ -58,7 +58,7 @@ %td= s.language.pretty_name %td #{s.submitted_at.strftime('%Y-%m-%d %H:%M')} (#{time_ago_in_words(s.submitted_at)} ago) %td.fix-width= s.grader_comment - %td= (s.points*100)/s.problem.full_score + %td= ( s.try(:points) ? (s.points*100/s.problem.full_score) : '' ) - if session[:admin] %td= s.ip_address diff --git a/db/migrate/20150827131927_create_submission_view_logs.rb b/db/migrate/20150827131927_create_submission_view_logs.rb new file mode 100644 --- /dev/null +++ b/db/migrate/20150827131927_create_submission_view_logs.rb @@ -0,0 +1,10 @@ +class CreateSubmissionViewLogs < ActiveRecord::Migration + def change + create_table :submission_view_logs do |t| + t.integer :user_id + t.integer :submission_id + + t.timestamps + end + end +end diff --git a/db/migrate/20150827133841_add_last_ip_to_user.rb b/db/migrate/20150827133841_add_last_ip_to_user.rb new file mode 100644 --- /dev/null +++ b/db/migrate/20150827133841_add_last_ip_to_user.rb @@ -0,0 +1,5 @@ +class AddLastIpToUser < ActiveRecord::Migration + def change + add_column :users, :last_ip, :string + end +end diff --git a/db/schema.rb b/db/schema.rb --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20150618085823) do +ActiveRecord::Schema.define(:version => 20150827133841) do create_table "announcements", :force => true do |t| t.string "author" @@ -159,6 +159,13 @@ t.string "password" end + create_table "submission_view_logs", :force => true do |t| + t.integer "user_id" + t.integer "submission_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "submissions", :force => true do |t| t.integer "user_id" t.integer "problem_id" diff --git a/spec/models/submission_view_logs_spec.rb b/spec/models/submission_view_logs_spec.rb new file mode 100644 --- /dev/null +++ b/spec/models/submission_view_logs_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe SubmissionViewLogs do + pending "add some examples to (or delete) #{__FILE__}" +end