@@ -23,6 +23,7 @@ defmodule Cadet.Assessments do
23
23
alias Cadet.ProgramAnalysis.Lexer
24
24
alias Ecto.Multi
25
25
alias Cadet.Incentives.Achievements
26
+ alias Timex.Duration
26
27
27
28
require Decimal
28
29
@@ -500,6 +501,35 @@ defmodule Cadet.Assessments do
500
501
Question . changeset ( % Question { } , params_with_assessment_id )
501
502
end
502
503
504
+ def update_final_contest_entries do
505
+ # 1435 = 1 day - 5 minutes
506
+ if Log . log_execution ( "update_final_contest_entries" , Duration . from_minutes ( 1435 ) ) do
507
+ Logger . info ( "Started update of contest entry pools" )
508
+ questions = fetch_unassigned_voting_questions ( )
509
+
510
+ for q <- questions do
511
+ insert_voting ( q . course_id , q . question [ "contest_number" ] , q . question_id )
512
+ end
513
+
514
+ Logger . info ( "Successfully update contest entry pools" )
515
+ end
516
+ end
517
+
518
+ # fetch voting questions where entries have not been assigned
519
+ def fetch_unassigned_voting_questions do
520
+ voting_assigned_question_ids =
521
+ SubmissionVotes
522
+ |> select ( [ v ] , v . question_id )
523
+ |> Repo . all ( )
524
+
525
+ Question
526
+ |> where ( type: :voting )
527
+ |> where ( [ q ] , q . id not in ^ voting_assigned_question_ids )
528
+ |> join ( :inner , [ q ] , asst in assoc ( q , :assessment ) )
529
+ |> select ( [ q , asst ] , % { course_id: asst . course_id , question: q . question , question_id: q . id } )
530
+ |> Repo . all ( )
531
+ end
532
+
503
533
@ doc """
504
534
Generates and assigns contest entries for users with given usernames.
505
535
"""
@@ -522,102 +552,119 @@ defmodule Cadet.Assessments do
522
552
523
553
{ :error , error_changeset }
524
554
else
525
- # Returns contest submission ids with answers that contain "return"
526
- contest_submission_ids =
527
- Submission
528
- |> join ( :inner , [ s ] , ans in assoc ( s , :answers ) )
529
- |> join ( :inner , [ s , ans ] , cr in assoc ( s , :student ) )
530
- |> where ( [ s , ans , cr ] , cr . role == "student" )
531
- |> where ( [ s , _ ] , s . assessment_id == ^ contest_assessment . id and s . status == "submitted" )
532
- |> where (
533
- [ _ , ans , cr ] ,
534
- fragment (
535
- "?->>'code' like ?" ,
536
- ans . answer ,
537
- "%return%"
538
- )
555
+ if Timex . compare ( contest_assessment . close_at , Timex . now ( ) ) < 0 do
556
+ compile_entries ( course_id , contest_assessment , question_id )
557
+ else
558
+ # contest has not closed, do nothing
559
+ { :ok , nil }
560
+ end
561
+ end
562
+ end
563
+
564
+ def compile_entries (
565
+ course_id ,
566
+ contest_assessment ,
567
+ question_id
568
+ ) do
569
+ # Returns contest submission ids with answers that contain "return"
570
+ contest_submission_ids =
571
+ Submission
572
+ |> join ( :inner , [ s ] , ans in assoc ( s , :answers ) )
573
+ |> join ( :inner , [ s , ans ] , cr in assoc ( s , :student ) )
574
+ |> where ( [ s , ans , cr ] , cr . role == "student" )
575
+ |> where ( [ s , _ ] , s . assessment_id == ^ contest_assessment . id and s . status == "submitted" )
576
+ |> where (
577
+ [ _ , ans , cr ] ,
578
+ fragment (
579
+ "?->>'code' like ?" ,
580
+ ans . answer ,
581
+ "%return%"
539
582
)
540
- |> select ( [ s , _ans ] , { s . student_id , s . id } )
541
- |> Repo . all ( )
542
- |> Enum . into ( % { } )
583
+ )
584
+ |> select ( [ s , _ans ] , { s . student_id , s . id } )
585
+ |> Repo . all ( )
586
+ |> Enum . into ( % { } )
543
587
544
- contest_submission_ids_length = Enum . count ( contest_submission_ids )
588
+ contest_submission_ids_length = Enum . count ( contest_submission_ids )
545
589
546
- voter_ids =
547
- CourseRegistration
548
- |> where ( role: "student" , course_id: ^ course_id )
549
- |> select ( [ cr ] , cr . id )
550
- |> Repo . all ( )
590
+ voter_ids =
591
+ CourseRegistration
592
+ |> where ( role: "student" , course_id: ^ course_id )
593
+ |> select ( [ cr ] , cr . id )
594
+ |> Repo . all ( )
551
595
552
- votes_per_user = min ( contest_submission_ids_length , 10 )
596
+ votes_per_user = min ( contest_submission_ids_length , 10 )
553
597
554
- votes_per_submission =
555
- if Enum . empty? ( contest_submission_ids ) do
556
- 0
557
- else
558
- trunc ( Float . ceil ( votes_per_user * length ( voter_ids ) / contest_submission_ids_length ) )
559
- end
598
+ votes_per_submission =
599
+ if Enum . empty? ( contest_submission_ids ) do
600
+ 0
601
+ else
602
+ trunc ( Float . ceil ( votes_per_user * length ( voter_ids ) / contest_submission_ids_length ) )
603
+ end
560
604
561
- submission_id_list =
562
- contest_submission_ids
563
- |> Enum . map ( fn { _ , s_id } -> s_id end )
564
- |> Enum . shuffle ( )
565
- |> List . duplicate ( votes_per_submission )
566
- |> List . flatten ( )
567
-
568
- { _submission_map , submission_votes_changesets } =
569
- voter_ids
570
- |> Enum . reduce ( { submission_id_list , [ ] } , fn voter_id , acc ->
571
- { submission_list , submission_votes } = acc
572
-
573
- user_contest_submission_id = Map . get ( contest_submission_ids , voter_id )
574
-
575
- { votes , rest } =
576
- submission_list
577
- |> Enum . reduce_while ( { MapSet . new ( ) , submission_list } , fn s_id , acc ->
578
- { user_votes , submissions } = acc
579
-
580
- max_votes =
581
- if votes_per_user == contest_submission_ids_length and
582
- not is_nil ( user_contest_submission_id ) do
583
- # no. of submssions is less than 10. Unable to find
584
- votes_per_user - 1
585
- else
586
- votes_per_user
587
- end
588
-
589
- if MapSet . size ( user_votes ) < max_votes do
590
- if s_id != user_contest_submission_id and not MapSet . member? ( user_votes , s_id ) do
591
- new_user_votes = MapSet . put ( user_votes , s_id )
592
- new_submissions = List . delete ( submissions , s_id )
593
- { :cont , { new_user_votes , new_submissions } }
594
- else
595
- { :cont , { user_votes , submissions } }
596
- end
605
+ submission_id_list =
606
+ contest_submission_ids
607
+ |> Enum . map ( fn { _ , s_id } -> s_id end )
608
+ |> Enum . shuffle ( )
609
+ |> List . duplicate ( votes_per_submission )
610
+ |> List . flatten ( )
611
+
612
+ { _submission_map , submission_votes_changesets } =
613
+ voter_ids
614
+ |> Enum . reduce ( { submission_id_list , [ ] } , fn voter_id , acc ->
615
+ { submission_list , submission_votes } = acc
616
+
617
+ user_contest_submission_id = Map . get ( contest_submission_ids , voter_id )
618
+
619
+ { votes , rest } =
620
+ submission_list
621
+ |> Enum . reduce_while ( { MapSet . new ( ) , submission_list } , fn s_id , acc ->
622
+ { user_votes , submissions } = acc
623
+
624
+ max_votes =
625
+ if votes_per_user == contest_submission_ids_length and
626
+ not is_nil ( user_contest_submission_id ) do
627
+ # no. of submssions is less than 10. Unable to find
628
+ votes_per_user - 1
597
629
else
598
- { :halt , acc }
630
+ votes_per_user
599
631
end
600
- end )
601
632
602
- votes = MapSet . to_list ( votes )
603
-
604
- new_submission_votes =
605
- votes
606
- |> Enum . map ( fn s_id ->
607
- % SubmissionVotes { voter_id: voter_id , submission_id: s_id , question_id: question_id }
608
- end )
609
- |> Enum . concat ( submission_votes )
610
-
611
- { rest , new_submission_votes }
612
- end )
613
-
614
- submission_votes_changesets
615
- |> Enum . with_index ( )
616
- |> Enum . reduce ( Multi . new ( ) , fn { changeset , index } , multi ->
617
- Multi . insert ( multi , Integer . to_string ( index ) , changeset )
633
+ if MapSet . size ( user_votes ) < max_votes do
634
+ if s_id != user_contest_submission_id and not MapSet . member? ( user_votes , s_id ) do
635
+ new_user_votes = MapSet . put ( user_votes , s_id )
636
+ new_submissions = List . delete ( submissions , s_id )
637
+ { :cont , { new_user_votes , new_submissions } }
638
+ else
639
+ { :cont , { user_votes , submissions } }
640
+ end
641
+ else
642
+ { :halt , acc }
643
+ end
644
+ end )
645
+
646
+ votes = MapSet . to_list ( votes )
647
+
648
+ new_submission_votes =
649
+ votes
650
+ |> Enum . map ( fn s_id ->
651
+ % SubmissionVotes {
652
+ voter_id: voter_id ,
653
+ submission_id: s_id ,
654
+ question_id: question_id
655
+ }
656
+ end )
657
+ |> Enum . concat ( submission_votes )
658
+
659
+ { rest , new_submission_votes }
618
660
end )
619
- |> Repo . transaction ( )
620
- end
661
+
662
+ submission_votes_changesets
663
+ |> Enum . with_index ( )
664
+ |> Enum . reduce ( Multi . new ( ) , fn { changeset , index } , multi ->
665
+ Multi . insert ( multi , Integer . to_string ( index ) , changeset )
666
+ end )
667
+ |> Repo . transaction ( )
621
668
end
622
669
623
670
def update_assessment ( id , params ) when is_ecto_id ( id ) do
@@ -1026,7 +1073,7 @@ defmodule Cadet.Assessments do
1026
1073
"""
1027
1074
def update_rolling_contest_leaderboards do
1028
1075
# 115 = 2 hours - 5 minutes is default.
1029
- if Log . log_execution ( "update_rolling_contest_leaderboards" , Timex. Duration. from_minutes ( 115 ) ) do
1076
+ if Log . log_execution ( "update_rolling_contest_leaderboards" , Duration . from_minutes ( 115 ) ) do
1030
1077
Logger . info ( "Started update_rolling_contest_leaderboards" )
1031
1078
1032
1079
voting_questions_to_update = fetch_active_voting_questions ( )
@@ -1053,7 +1100,7 @@ defmodule Cadet.Assessments do
1053
1100
"""
1054
1101
def update_final_contest_leaderboards do
1055
1102
# 1435 = 24 hours - 5 minutes
1056
- if Log . log_execution ( "update_final_contest_leaderboards" , Timex. Duration. from_minutes ( 1435 ) ) do
1103
+ if Log . log_execution ( "update_final_contest_leaderboards" , Duration . from_minutes ( 1435 ) ) do
1057
1104
Logger . info ( "Started update_final_contest_leaderboards" )
1058
1105
1059
1106
voting_questions_to_update = fetch_voting_questions_due_yesterday ( )
0 commit comments