iclop_v2/app/Models/NodeJS/Submission.php
2024-12-24 23:40:12 +00:00

313 lines
9.7 KiB
PHP

<?php
namespace App\Models\NodeJS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Submission extends Model implements HasMedia
{
use HasFactory, InteractsWithMedia;
protected $connection = 'nodejsDB';
static $types = ['file', 'url'];
static $statues = ['pending', 'processing', 'completed', 'failed'];
static $FILE = 'file';
static $URL = 'url';
static $PENDING = 'pending';
static $PROCESSING = 'processing';
static $COMPLETED = 'completed';
static $FAILED = 'failed';
protected $fillable = [
'user_id',
'project_id',
'type',
'path',
'status',
'results',
'attempts',
'port',
'start',
'end',
];
protected $casts = [
'results' => 'array',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function project()
{
return $this->belongsTo(Project::class);
}
public function getResultsAttribute($value)
{
return json_decode($value);
}
public function setResultsAttribute($value)
{
$this->attributes['results'] = json_encode($value);
}
public function getFileAttribute()
{
return $this->getFirstMediaUrl('public_submissions_files');
}
public function isGithubUrl()
{
return $this->type == self::$URL;
}
public function history()
{
return $this->hasMany(SubmissionHistory::class);
}
public function getExecutionSteps()
{
if ($this->isGithubUrl()) {
$steps = $this->project->projectExecutionSteps->filter(function ($step) {
return $step->executionStep->name != 'Unzip ZIP Files' && $step->executionStep->name != 'Remove ZIP Files';
});
} else {
$steps = $this->project->projectExecutionSteps->filter(function ($step) {
return $step->executionStep->name != 'Clone Repository';
});
}
// order the steps by their order
$steps = $steps->sortBy('order');
return $steps;
}
public function initializeResults()
{
$results = [];
$steps = $this->getExecutionSteps();
foreach ($steps as $step) {
if ($step->executionStep->name == ExecutionStep::$NPM_RUN_TESTS) {
$tests = $this->project->projectExecutionSteps->where('execution_step_id', $step->executionStep->id)->first()->variables;
$testResults = [];
$order = 0;
foreach ($tests as $testCommandValue) {
$order = $order + 1;
$command = implode(" ", $step->executionStep->commands);
$key = explode("=", $testCommandValue)[0];
$value = explode("=", $testCommandValue)[1];
$testName = str_replace($key, $value, $command);
$testResults[$testName] = [
'status' => self::$PENDING,
'output' => '',
'order' => $order,
];
}
$results[$step->executionStep->name] = [
'stepID' => $step->id,
'status' => self::$PENDING,
'order' => $step->order,
'output' => '',
'testResults' => $testResults,
];
} else {
$results[$step->executionStep->name] = [
'stepID' => $step->id,
'status' => self::$PENDING,
'order' => $step->order,
'output' => '',
];
}
}
$this->updateResults($results);
}
public function increaseAttempts()
{
$this->attempts = $this->attempts + 1;
$this->save();
}
public function updateStatus($status)
{
$this->status = $status;
if ($status == self::$FAILED || self::$COMPLETED) $this->end = now();
$this->save();
}
public function restartTime()
{
$this->start = now();
$this->end = null;
$this->save();
}
public function updateOneResult($step_name, $status, $output)
{
$results = $this->results;
$results->$step_name->status = $status;
$results->$step_name->output = $output;
$this->updateResults($results);
}
public function updateOneTestResult($step_name, $test_name, $status, $output)
{
$results = $this->results;
$results->$step_name->testResults->$test_name->status = $status;
$results->$step_name->testResults->$test_name->output = $output;
$this->updateResults($results);
}
public function updateResults($results)
{
$this->results = $results;
$this->save();
}
public function updatePort($port)
{
$this->port = $port;
$this->save();
}
public function getCurrentExecutionStep($step_id = null)
{
$steps = $this->getExecutionSteps();
if ($step_id) {
$current_step = $steps->first(function ($step) use ($step_id) {
return $step->id == $step_id;
});
return $current_step;
} else {
$results = $this->results;
$current_step = null;
if (!$results) {
return $current_step;
}
foreach ($steps as $step) {
if ($results->{$step->executionStep->name}?->status == self::$PROCESSING || $results->{$step->executionStep->name}?->status == self::$PENDING) {
$current_step = $step;
break;
}
}
if (!$current_step) {
$have_failed_steps = false;
foreach ($steps as $step) {
if ($results->{$step->executionStep->name}?->status == self::$FAILED) {
$have_failed_steps = true;
break;
}
}
if ($have_failed_steps) {
$this->updateStatus(self::$FAILED);
} else {
$this->updateStatus(self::$COMPLETED);
}
}
return $current_step;
}
}
public function getNextExecutionStep($step_id = null)
{
if ($step_id == null) return null;
$next_step = null;
$steps = $this->getExecutionSteps();
$current_step = $this->getCurrentExecutionStep($step_id);
if ($current_step) {
$current_step_index = $steps->search(function ($step) use ($current_step) {
return $step->id == $current_step->id;
});
if ($current_step_index < $steps->count()) {
$next_step = $steps[$current_step_index + 1];
}
}
return $next_step;
}
public function getTotalSteps()
{
return $this->getExecutionSteps()->count();
}
public function getTotalCompletedSteps()
{
$results = $this->results;
$completed_steps = 0;
if ($results != null) {
foreach ($results as $result) {
if ($result->status == self::$COMPLETED || $result->status == self::$FAILED) {
$completed_steps++;
}
}
}
return $completed_steps;
}
public function restartAfterNpmInstall()
{
$step = ProjectExecutionStep::where('project_id', $this->project_id)->where('execution_step_id', ExecutionStep::where('name', ExecutionStep::$NPM_INSTALL)->first()->id)->first();
$next_step = $this->getNextExecutionStep($step->id ?? null);
// update results to pending
while ($next_step) {
if ($next_step->executionStep->name == ExecutionStep::$NPM_RUN_TESTS) {
$tests = $this->project->projectExecutionSteps->where('execution_step_id', $next_step->executionStep->id)->first()->variables;
foreach ($tests as $testCommandValue) {
$command = implode(" ", $next_step->executionStep->commands);
$key = explode("=", $testCommandValue)[0];
$value = explode("=", $testCommandValue)[1];
$testName = str_replace($key, $value, $command);
$this->updateOneTestResult($next_step->executionStep->name, $testName, Submission::$PENDING, " ");
}
}
$this->updateOneResult($next_step->executionStep->name, Submission::$PENDING, " ");
$next_step = $this->getNextExecutionStep($next_step->id ?? null);
}
$this->updateStatus(Submission::$PROCESSING);
}
public function getTotalAttemptsCount()
{
return $this->history->count() + 1;
}
public function restart()
{
$this->updateStatus(Submission::$PENDING);
$this->increaseAttempts();
$this->updatePort(null);
$this->restartTime();
$this->initializeResults();
}
public function createHistory($description)
{
// use the method attach to attach the history to the submission
$history = $this->history()->create([
'user_id' => $this->user_id,
'project_id' => $this->project_id,
'type' => $this->type,
'path' => $this->path,
'status' => $this->status,
'results' => $this->results,
'attempts' => $this->attempts,
'port' => $this->port,
'start' => $this->start,
'end' => $this->end,
'description' => $description,
]);
return $history;
}
}