%PDF- %PDF-
| Direktori : /proc/self/root/home/nginx/.vscode-server/data/User/History/-5b5ca2a2/ |
| Current File : //proc/self/root/home/nginx/.vscode-server/data/User/History/-5b5ca2a2/J2WV.php |
<?php
namespace App\Workers;
use App\Models\Contest;
use App\Models\ContestDivision;
use App\Models\Registration;
use App\Models\ShooterStage;
use App\Models\ShooterStageTarget;
use App\Models\ShooterStageTime;
use App\Models\Stage;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use Ramsey\Uuid\Uuid;
use stdClass;
use ZipArchive;
class ContestImporter
{
public array $errors = array();
public array $warnings = array();
function __construct(Contest $contest, string $filename, string $extension)
{
switch ($extension){
case 'xls':
$this->importExcel($contest, $filename);
break;
case 'xlsx':
$this->importExcel($contest, $filename, true);
break;
case 'psc':
$this->importPractiScore($contest, $filename);
break;
}
}
protected function importExcel(Contest $contest, string $filename, bool $isXlsx = false)
{
$numStages = $contest->stages;
$tmpName = tempnam(sys_get_temp_dir(), 'practiscore.xls');
file_put_contents($tmpName, Storage::disk('contests')->get($filename));
$reader = $isXlsx ? new Xlsx() : new Xls();
$spreadsheet = $reader->load($tmpName);
$ss = $spreadsheet->setActiveSheetIndex(0);
// Delete old data before import
DB::statement("DELETE FROM shooter_stage_times WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]);
DB::statement("DELETE FROM shooter_stage_targets WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]);
DB::statement("DELETE FROM shooter_stages WHERE stage_id in (SELECT id FROM stages WHERE contest_id = ?)", [$contest->id]);
DB::statement("DELETE FROM stages WHERE contest_id = ?", [$contest->id]);
// Create stages
$stageIds = array();
for($i = 0; $i < $numStages; $i++)
{
$st = new Stage([
'contest_id' => $contest->id,
'name' => "Stage " . ($i + 1),
'order' => $i + 1,
'strings' => 1
]);
$st->save();
$stageIds[$i] = $st->id;
}
foreach (ExcelHelper::$divisionDefaultStartPosition as $division => $position)
{
// Prepare division ID
$divisionId = ContestDivision::where(DB::raw('UPPER(bgdivision)'), $division)->first()->id;
// Get mail and alias, if empty, go to another division
while($mailalias = trim($ss->getCell("B" . $position)->getValue())) {
list($email, $alias) = explode("/", $mailalias);
$alias = strtoupper($alias);
$notCompeting = strtoupper(rim($ss->getCell("B" . $position)->getValue())) == "MZ";
list($firstName, $lastName) = explode(" ", $ss->getCell("C" . $position)->getValue());
$user = $this->getOrCreateUserByAlias($alias, $email, $firstName, $lastName);
$registration = new Registration([
'contest_id' => $contest->id,
'user_id' => $user->id,
'contest_division_id' => $divisionId,
'squad' => 1,
'notcomp' => $notCompeting ? 1 : 0
]);
$registration->canceltoken = Str::orderedUuid();
$registration->save();
// Get stage data
$col = 4;
for ($i = 0; $i < $numStages; $i++) {
$shooterStage = new ShooterStage([
'registration_id' => $registration->id,
'stage_id' => $stageIds[$i],
'proc' => $ss->getCell([$col + 8, $position])->getValue() ?? 0,
'noshoot' => $ss->getCell([$col + 7, $position])->getValue() ?? 0
]);
$shooterStage->save();
$shooterStageTime = new ShooterStageTime([
'shooter_stage_id' => $shooterStage->id,
'time' => $ss->getCell([$col, $position])->getValue(),
'order' => 1
]);
$shooterStageTime->save();
$shooterStageTarget = new ShooterStageTarget([
'shooter_stage_id' => $shooterStage->id,
'order' => 1,
'popper' => $ss->getCell([$col + 1, $position])->getValue() ?? 0,
'alpha' => $ss->getCell([$col + 2, $position])->getValue() ?? 0,
'charlie' => $ss->getCell([$col + 3, $position])->getValue() ?? 0,
'delta' => $ss->getCell([$col + 4, $position])->getValue() ?? 0,
'miss' => $ss->getCell([$col + 5, $position])->getValue() ?? 0,
'misspopper' => $ss->getCell([$col + 6, $position])->getValue() ?? 0,
]);
$shooterStageTarget->save();
$col += 10;
}
$position++;
}
}
}
protected function importPractiScore(Contest $contest, string $filename)
{
$tmpName = tempnam(sys_get_temp_dir(), 'practiscore.zip');
file_put_contents($tmpName, Storage::disk('contests')->get($filename));
$zip = new ZipArchive;
$res = $zip->open($tmpName);
$txt = $zip->getFromName('match_def.json');
$matchDef = json_decode($txt);
$txt = $zip->getFromName('match_scores.json');
$scores = json_decode($txt);
unset($txt);
$zip->close();
unlink($tmpName);
// Prepare stages
$stages = array();
$numStages = 0;
foreach ($matchDef->match_stages as $match_stage)
{
$stage = new stdClass();
$stage->guid = $match_stage->stage_uuid;
$stage->order = $match_stage->stage_number;
$stage->name = $match_stage->stage_name;
$stage->deleted = $match_stage->stage_deleted ?? false;
$stage->strings = $match_stage->stage_strings;
$stages[$stage->guid] = $stage;
if(!$stage->deleted) $numStages++;
}
if($contest->stages != $numStages)
{
$this->errors[] = __('Contest has :cStages but imported PractiScore file contains :psStages stages', ['cStages' => $contest->stages, 'psStages' => $numStages]);
return;
}
$shooters = $this->psProcessShooters($matchDef, $contest);
DB::statement("DELETE FROM shooter_stage_times WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]);
DB::statement("DELETE FROM shooter_stage_targets WHERE shooter_stage_id in (SELECT id FROM shooter_stages where stage_id in (SELECT id FROM stages WHERE contest_id = ?))", [$contest->id]);
DB::statement("DELETE FROM shooter_stages WHERE stage_id in (SELECT id FROM stages WHERE contest_id = ?)", [$contest->id]);
DB::statement("DELETE FROM stages WHERE contest_id = ?", [$contest->id]);
// Process scores
foreach ($scores->match_scores as $stage)
{
$defStage = $stages[$stage->stage_uuid];
if($defStage->deleted) continue;
$st = new Stage([
'contest_id' => $contest->id,
'name' => $defStage->name,
'order' => $defStage->order,
'strings' => $defStage->strings
]);
$st->save();
$stageId = $st->id;
foreach ($stage->stage_stagescores as $score)
{
if(!isset($shooters[$score->shtr])) continue;
$shooterStage = new ShooterStage([
'stage_id' => $stageId,
'registration_id' => $shooters[$score->shtr]->id,
'proc' => $score->proc ?? 0,
'noshoot' => 0
]);
$shooterStage->save();
$stageNo = $shooterStage->id;
$noshoots = $score->popns ?? 0;
// Proces times
$order = 1;
foreach ($score->str as $time)
{
$strings = null;
// parse string splits
if(isset($score->meta))
{
foreach ($score->meta as $meta)
{
if(strstr($meta->k, "string" . ($order-1)))
{
$strings = array();
$times = explode(",", $meta->v);
$curr = 0.0;
foreach ($times as $t)
{
$strings[] = number_format((double)$t - $curr, 2, '.', '');
$curr = (double)$t;
}
}
}
}
$shooterStageTime = new ShooterStageTime([
'shooter_stage_id' => $stageNo,
'time' => $time,
'order' => $order++,
'string' => $strings != null ? implode(",", $strings) : null
]);
$shooterStageTime->save();
}
$dataTpl = array(
"shooter_stage_id" => $stageNo,
"alpha" => 0,
"charlie" => 0,
"delta" => 0,
"miss" => 0,
"popper" => 0,
"misspopper" => 0
);
$order = 1;
$data = $this->arrayCopy($dataTpl);
if($score->popm > 0 || $score->poph > 0)
{
$data["order"] = $order++;
$data["popper"] = $score->poph;
$data["misspopper"] = $score->popm;
$target = new ShooterStageTarget($data);
$target->save();
$data = $this->arrayCopy($dataTpl);
}
if(isset($score->ts)) {
foreach ($score->ts as $t) {
$data["order"] = $order++;
$data["alpha"] = ($t & 0xF);
$data["charlie"] = ($t & 0xF00) >> 8;
$data["delta"] = ($t & 0xF000) >> 12;
$data["miss"] = ($t & 0xF00000) >> 20;
$noshoots += ($t & 0xF0000) >> 16;
$target = new ShooterStageTarget($data);
$target->save();
$data = $this->arrayCopy($dataTpl);
}
}
$shooterStage->noshoot = $noshoots;
$shooterStage->save();
}
}
}
private function getUserByAlias(string $alias)
{
return User::where(DB::raw('UPPER(username)'), strtoupper($alias))->first();
}
private function getUserByEmail(string $email)
{
return User::where(DB::raw('UPPER(email)'), strtoupper($email))->first();
}
/**
* @param mixed $matchDef
* @param Contest $contest
* @return void
*/
public function psProcessShooters(mixed $matchDef, Contest $contest): array
{
$shooters = array();
foreach ($matchDef->match_shooters as $match_shooter) {
if ($match_shooter->sh_del || $match_shooter->sh_dq) continue;
$shooter = new stdClass();
$shooter->id = null;
$shooter->firstName = $match_shooter->sh_fn;
$shooter->lastName = $match_shooter->sh_ln;
$shooter->mail = (isset($match_shooter->sh_eml) && $match_shooter->sh_eml) ? $match_shooter->sh_eml : Uuid::uuid4() . "@test.com";
$shooter->uid = $match_shooter->sh_uid;
$shooter->division = strtoupper($match_shooter->sh_dvp);
$shooter->squad = $match_shooter->sh_sqd;
$shooter->alias = (isset($match_shooter->sh_id) && $match_shooter->sh_id) ? strtoupper($match_shooter->sh_id) : (string)(Uuid::uuid4());
$shooter->notCompeting = isset($match_shooter->sh_chkins) && in_array("NotCompeting", $match_shooter->sh_chkins);
$registration = $contest->registrations()->where('canceltoken', $shooter->uid)->first();
if (!$registration) {
// try to create registration
$user = $this->getOrCreateUserByAlias($shooter->alias, $shooter->mail, $shooter->firstName, $shooter->lastName);
$registration = new Registration([
'contest_id' => $contest->id,
'user_id' => $user->id,
'contest_division_id' => 1,
'squad' => $shooter->squad,
'notcomp' => $shooter->notCompeting ? 1 : 0
]);
$registration->canceltoken = $shooter->uid;
$registration->save();
}
if (strtoupper($registration->division->bgdivision) != $shooter->division) {
// update division
$registration->contest_division_id = ContestDivision::where(DB::raw('UPPER(bgdivision)'), $shooter->division)->first()->id;
$registration->save();
}
$shooter->id = $registration->id;
$shooters[$shooter->uid] = $shooter;
}
return $shooters;
}
public function hasMessages()
{
return count($this->errors) > 0 || count($this->warnings) > 0;
}
private function arrayCopy($arr) {
$newArray = array();
foreach($arr as $key => $value) {
if(is_array($value)) $newArray[$key] = $this->arrayCopy($value);
else if(is_object($value)) $newArray[$key] = clone $value;
else $newArray[$key] = $value;
}
return $newArray;
}
/**
* @param stdClass $shooter
* @return User
*/
public function getOrCreateUserByAlias($alias, $email, $firstName, $lastName): User
{
$user = $this->getUserByAlias($alias);
if(!$user)
{
$user = $this->getUserByEmail($email);
}
if (!$user) {
// Create new user
$this->warnings[] = __('User with name :name and alias :alias does not exist, creating new one', ['name' => $firstName . " " . $lastName, 'alias' => $alias]);
$user = new User([
'username' => $alias,
'firstname' => $firstName,
'lastname' => $lastName,
'email' => $email,
'password' => ""
]);
$user->personaltoken = Str::orderedUuid();
$user->save();
}
return $user;
}
}