Skip to main content

Overview

The submission_controller manages all operations related to code submissions including creating submissions, viewing submission code and results, rejudging, and selecting final submissions.

Constructor

public function __construct()
Applies the following middleware:
  • auth - Requires user authentication
  • read_only_archive - Makes controller read-only when app is in archived mode
  • ip_white_listing - IP whitelist validation
Storage: Uses assignment_root disk for file operations

Listing Methods

index()

public function index($assignment_id = NULL, $user_id = 'all', $problem_id = 'all', $choose = 'all')
Displays a paginated listing of submissions with filtering capabilities.
assignment_id
integer
required
Assignment ID to filter submissions
user_id
integer|string
User ID to filter, or “all” for all users
problem_id
integer|string
Problem ID to filter, or “all” for all problems
choose
string
Filter type: “all” for all submissions, “final” for final submissions only
Access Control:
  • Admin: Can view all submissions
  • Head Instructor/Instructor: Can view submissions for their assignments and classes
  • Student: Can only view their own submissions
  • Practice submissions (assignment_id = 0): Instructors can view their own only
Returns: Paginated view with:
  • Submission list with language and user data
  • Submission delay relative to assignment finish time
  • Submission status and score
  • All problems in the assignment
Route: /submissions/assignment/{assignment_id}/user/{user_id}/problem/{problem_id}/view/{choose} Example from controller:
$submissions = $assignment->submissions();

if (in_array(Auth::user()->role->name, ['student', 'guest']) 
    || ($assignment->id == 0 && !in_array(Auth::user()->role->name, ['admin']))) {
    $submissions = $submissions->where('user_id', Auth::user()->id);
} else if ($user_id != 'all') {
    $submissions = $submissions->where('user_id', intval($user_id));
}

if ($choose == 'final') {
    $submissions = $submissions->where('is_final', 1);
}
if ($problem_id != 'all') {
    $submissions = $submissions->where('problem_id', intval($problem_id));
}

$submissions = $submissions->with(['language','user'])->latest()->paginate();

Submission Creation

create()

public function create($assignment_id, $problem_id, $old_sub = -1)
Shows the form for creating a new submission.
assignment_id
integer
required
Assignment ID
problem_id
integer
required
Problem ID to submit to
old_sub
integer
Optional previous submission ID to load code from
Access Control:
  • Calls _creation_guard_check() to verify:
    • Assignment contains the problem
    • User can submit to the assignment
    • Assignment has started and is open (for students)
    • User is a participant
Returns: View with:
  • Assignment and problem data
  • Last submission code (if exists)
Route: /submissions/create/assignment/{assignment}/problem/{problem}/{oldsub?} Example from controller:
$last = Submission::where([
    'assignment_id' => $assignment_id, 
    'problem_id' => $problem_id, 
    'user_id' => Auth::user()->id
]);
if ($old_sub != -1) $last = $last->where(['id'=> $old_sub]);
$last = $last->get()->last();

if ($last != null) {
    $submit_path = Submission::get_path($last->user->username, $last->assignment_id, $last->problem_id);
    $file_extension = $last->language->extension;
    $file_path = $submit_path . "/{$last->file_name}." . $file_extension;
    $last_code = file_exists($file_path) ? file_get_contents($file_path) : null;
}

store()

public function store(Request $request)
Stores a newly created submission and adds it to the judging queue.
assignment
integer
required
Assignment ID (must be >= 0)
problem
integer
required
Problem ID (must be > 0)
language
integer
required
Language ID to use for submission
code
text
Source code text (if submitting via text editor)
userfile
file
Source code file (if submitting via file upload)
Validation Rules:
  • assignment: integer, greater than -1
  • problem: integer, greater than 0
Validation Checks:
  • File/code size must be under file_size_limit setting
  • User cannot have another submission in queue for same problem
  • Language must be enabled for the problem
  • User must be able to submit to the assignment
Process:
  1. Creates submission record with PENDING status
  2. Saves code to file system
  3. Increments assignment’s total_submits counter
  4. Adds submission to queue for judging
  5. Triggers queue processing
Returns: Redirect to submissions index for the assignment Route: /submissions/store/ (POST) Example from controller:
$submission = new Submission([
    'assignment_id' => $assignment->id,
    'problem_id' => $problem->id,
    'user_id' => Auth::user()->id,
    'is_final' => 0,
    'status' => 'pending',
    'pre_score' => 0,
    'coefficient' => $coefficient,
    'file_name' => null,
    'language_id' => $language->id,
]);

$user_dir = Submission::get_relative_path(Auth::user()->username, $assignment->id, $problem->id);
$this->storage->makeDirectory($user_dir);

if ($code != NULL)
    return $this->upload_post_code($code, $user_dir, $submission);
else if ($request->hasFile('userfile'))
    return $this->upload_file_code($request, $user_dir, $submission);

Rejudging Methods

rejudge()

public function rejudge(Request $request)
Rejudges a single submission.
submission_id
integer
required
Submission ID to rejudge
Access Control:
  • Not available to students and guests
Validation Rules:
  • submission_id: integer
Process:
  1. Checks if submission already in queue
  2. Sets submission status to PENDING
  3. Adds to queue with type ‘rejudge’
  4. Triggers queue processing
Returns: JSON response:
{
  "done": 1,
  "message": "Optional error message"
}
Route: /submissions/rejudge/ (POST)

rejudge_all_problems_assignment()

public function rejudge_all_problems_assignment(Request $request)
Rejudges all submissions for an assignment or specific problem in an assignment.
assignment_id
integer
required
Assignment ID
problem_id
integer|string
required
Problem ID to rejudge, or “all” for all problems
Access Control:
  • Admin, head_instructor, and instructor only
Process:
  1. Fetches all matching submissions
  2. Sets all submissions to PENDING status
  3. Adds all to queue with type ‘rejudge’
  4. Starts concurrent queue processing
Returns: Redirect back with status message Route: /submissions/rejudge_all_problems_assignment/ (POST) Example from controller:
if ($request->problem_id == 'all')
    $submissions = Submission::where('assignment_id', $assignment->id)->get();
else
    $submissions = Submission::where('assignment_id', $assignment->id)
                            ->where('problem_id', $request->problem_id)->get();

foreach ($submissions as $submission) {
    Queue_item::add_not_process($submission->id, 'rejudge');
    $submission->status = 'PENDING';
    $submission->save();
}

for ($i = 0; $i < Setting::get('concurent_queue_process', 2); $i++) {
    Queue_item::work();
}

Viewing Methods

view_code()

public function view_code()
Returns the source code, log, or result file for a submission.
submit_id
integer
required
Submission ID (via POST)
type
string
required
Type of file to view: “code”, “log”, or “result” (via POST)
Access Control:
  • Students/guests can only view their own submissions
  • Assignment must be open for students
File Types:
  • code: Source code file with language extension
  • log: Judge log file (log-)
  • result: HTML result file (result-.html)
Returns: JSON response:
{
  "file_name": "solution.cpp",
  "text": "source code content",
  "lang": "cpp"
}
Route: /submissions/view_code/ (POST) Example from controller:
$submit_id = $_POST['submit_id'];
$type = $_POST['type'];

$submission = Submission::with('assignment')->find($submit_id);
$this->_do_access_check($submission);

$submit_path = Submission::get_relative_path($submission->user->username, 
    $submission->assignment_id, $submission->problem_id);
$file_extension = $submission->language->extension;

if ($type == "code")
    $file_path = $submit_path . "/{$submission->file_name}." . $file_extension;
elseif ($type == "log")
    $file_path = $submit_path . "/log-{$submission->id}";
elseif ($type == "result")
    $file_path = $submit_path . "/result-{$submission->id}.html";

$file_content = $this->storage->exists($file_path) 
    ? $this->storage->get($file_path) 
    : "File not found";

view_status()

public function view_status()
Returns the current status and score of a submission.
submit_id
integer
required
Submission ID (via POST)
Access Control:
  • Students/guests can only view their own submissions
  • Assignment must be open for students
Returns: JSON response with submission data including:
  • Status and verdict
  • Pre-score and final score
  • Coefficient applied
  • Rendered verdict component
Route: /submissions/view_status/ (POST) Example from controller:
$submit_id = $_POST['submit_id'];
$submission = Submission::with('assignment')->find($submit_id);
$this->_do_access_check($submission);

$score = ($submission->pre_score * 
    ($all_problems[$submission->problem_id]->pivot->score ?? 100) / 10000);

if ($submission->coefficient == 'error')
    $submission->final_score = $score;
else
    $submission->final_score = round($score * $submission->coefficient / 100, 0);

$a = new verdict($submission);
$submission->rendered_verdict = $a->resolveView()->with($a->data())->render();
echo json_encode($submission);

Selection Methods

select_final()

public function select_final(Request $request)
Marks a submission as the final submission for scoring.
submission
integer
required
Submission ID to mark as final
Access Control:
  • Students/guests can only select their own submissions
  • Assignment must be open for students
Process:
  1. Unmarks any existing final submission for the same user/assignment/problem
  2. Marks selected submission as final
  3. Updates assignment scoreboard
Returns: JSON response:
{
  "done": 1
}
Route: /submissions/select/ (POST) Example from controller:
$submission_curr = Submission::find($request->submission);
$this->_do_access_check($submission_curr);

$submission_final = Submission::where([
    'user_id' => $submission_curr->user_id,
    'assignment_id' => $submission_curr->assignment_id,
    'problem_id' => $submission_curr->problem_id,
    'is_final' => 1
])->update(['is_final' => 0]);

$submission_curr->is_final = 1;
$submission_curr->save();

Scoreboard::update_scoreboard($submission_curr->assignment_id);

Template Methods

get_template()

public function get_template(Request $request)
Returns the code template for a problem and language.
assignment_id
integer
required
Assignment ID
problem_id
integer
required
Problem ID
language_id
integer
required
Language ID
Validation Rules:
  • assignment_id: integer
  • problem_id: integer
  • language_id: integer
Template Format: Templates are parsed for three sections:
  1. Banned keywords - Between /*###Begin banned and ###End banned keyword*/
  2. Before code - Between banned section and //###INSERT CODE HERE
  3. After code - After //###INSERT CODE HERE
Returns: JSON response:
{
  "banned": "banned keywords text",
  "before": "code before insertion point",
  "after": "code after insertion point",
  "full": "full template"
}
If no template exists, all fields return empty strings. Route: /submissions/get_template/ (POST) Example from controller:
$problem = $this->_creation_guard_check($request->input('assignment_id'), 
    $request->input('problem_id'));
$template = $problem->template_content($request->input('language_id'));

if ($template === NULL) {
    $result = array('banned' => '', 'before' => '', 'after' => '', 'full' => '');
} else {
    preg_match(
        "/(\/\*###Begin banned.*\n)((.*\n)*)(###End banned keyword\*\/)/",
        $template, $matches
    );
    $banned = $matches[2] ?? "";
    
    preg_match(
        "/(###End banned keyword\*\/\n)((.*\n)*)\/\/###INSERT CODE HERE -\n?((.*\n?)*)/",
        $template, $matches
    );
    $before = $matches[2] ?? "";
    $after = $matches[4] ?? "";
    
    $result = array(
        'banned' => $banned, 
        'before' => $before, 
        'after' => $after, 
        'full' => $template
    );
}

File Storage

Submission Path Structure

assignments_root/
└── assignment_{assignment_id}/
    └── problem_{problem_id}/
        └── {username}/
            ├── solution-upload-count{N}.{ext}
            ├── solution-editcode-count{N}.{ext}
            ├── log-{submission_id}
            └── result-{submission_id}.html

File Naming

  • Upload submissions: solution-upload-count{N}.{ext} where N is assignment’s total_submits
  • Code editor submissions: solution-editcode-count{N}.{ext}
  • Log files: log-{submission_id}
  • Result files: result-{submission_id}.html

Submission Lifecycle

  1. Creation - User submits code via file or text editor
  2. Validation - System checks permissions, size limits, queue status
  3. Storage - Code saved to filesystem with unique filename
  4. Queuing - Submission added to queue with type ‘judge’
  5. Processing - Queue worker picks up submission and runs tests
  6. Scoring - Results written to log and result files, score calculated
  7. Selection - User can select which submission counts as final

Score Calculation

$score = ($submission->pre_score * $problem->pivot->score) / 10000;
$submission->final_score = round($score * $submission->coefficient / 100, 0);
Where:
  • pre_score: Raw score from judge (0-10000 scale)
  • pivot->score: Problem’s weight in assignment
  • coefficient: Time-based penalty coefficient (0-100)
  • final_score: Final score for scoreboard

  • Submission: Main model for submissions
  • Assignment: Assignment being submitted to
  • Problem: Problem being solved
  • Language: Programming language used
  • Queue_item: Queue management for judging
  • Scoreboard: Assignment scoreboard data
  • User: Submission author

Build docs developers (and LLMs) love