From ca4b53836f1566d4dfbc7b2ec9ba71639872582f Mon Sep 17 00:00:00 2001 From: Crypta Eve Date: Mon, 23 Feb 2026 22:10:43 +1030 Subject: [PATCH 1/4] feat: corp projects --- src/Bus/Corporation.php | 4 + src/Config/eveapi.scopes.php | 1 + src/Jobs/CorporationProjects/Contributors.php | 151 +++++++++++++++++ src/Jobs/CorporationProjects/Details.php | 148 +++++++++++++++++ src/Jobs/CorporationProjects/Projects.php | 154 ++++++++++++++++++ .../CorporationProjects/ProjectsMapping.php | 59 +++++++ .../CorporationProject.php | 61 +++++++ .../CorporationProjectContributor.php | 56 +++++++ ...1928_create_corporation_projects_table.php | 78 +++++++++ ...corporation_project_contributors_table.php | 57 +++++++ 10 files changed, 769 insertions(+) create mode 100644 src/Jobs/CorporationProjects/Contributors.php create mode 100644 src/Jobs/CorporationProjects/Details.php create mode 100644 src/Jobs/CorporationProjects/Projects.php create mode 100644 src/Mapping/CorporationProjects/ProjectsMapping.php create mode 100644 src/Models/CorporationProjects/CorporationProject.php create mode 100644 src/Models/CorporationProjects/CorporationProjectContributor.php create mode 100644 src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php create mode 100644 src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php diff --git a/src/Bus/Corporation.php b/src/Bus/Corporation.php index 8a9f3c4f..687da690 100644 --- a/src/Bus/Corporation.php +++ b/src/Bus/Corporation.php @@ -40,6 +40,7 @@ use Seat\Eveapi\Jobs\Corporation\MembersLimit; use Seat\Eveapi\Jobs\Corporation\MembersTitles; use Seat\Eveapi\Jobs\Corporation\MemberTracking; +use Seat\Eveapi\Jobs\CorporationProjects\Projects; use Seat\Eveapi\Jobs\Corporation\RoleHistories; use Seat\Eveapi\Jobs\Corporation\Roles; use Seat\Eveapi\Jobs\Corporation\Shareholders; @@ -205,5 +206,8 @@ protected function addAuthenticatedJobs() $this->addAuthenticatedJob(new ContainerLogs($this->corporation_id, $this->token)); $this->addAuthenticatedJob(new Locations($this->corporation_id, $this->token)); $this->addAuthenticatedJob(new Names($this->corporation_id, $this->token)); + + // projects + $this->addAuthenticatedJob(new Projects($this->corporation_id, $this->token)); } } diff --git a/src/Config/eveapi.scopes.php b/src/Config/eveapi.scopes.php index ba59775e..f7b2f637 100644 --- a/src/Config/eveapi.scopes.php +++ b/src/Config/eveapi.scopes.php @@ -86,4 +86,5 @@ 'esi-universe.read_structures.v1', 'esi-wallet.read_character_wallet.v1', 'esi-wallet.read_corporation_wallets.v1', + 'esi-corporations.read_projects.v1', ]; diff --git a/src/Jobs/CorporationProjects/Contributors.php b/src/Jobs/CorporationProjects/Contributors.php new file mode 100644 index 00000000..593cae3a --- /dev/null +++ b/src/Jobs/CorporationProjects/Contributors.php @@ -0,0 +1,151 @@ +project_id = $project_id; + + parent::__construct($corporation_id, $token); + } + + /** + * Execute the job. + * + * @return void + * + * @throws \Throwable + */ + public function handle() + { + parent::handle(); + + $this->query_string["limit"] = "100"; + + $before = "0"; + + $proj = CorporationProject::findOrFail($this->project_id); + + $contriblist = collect(); + + while (true) { + + $this->query_string["before"] = $before; + + $response = $this->retrieve([ + 'corporation_id' => $this->getCorporationId(), + 'project_id' => $this->project_id, + ]); + + $contribs = $response->getBody(); + if (isset($contribs->cursor) && isset($contribs->cursor->before)) { + $before = $contribs->cursor->before; + } else { + break; // empty cursor + } + if (isset($contribs->contributors)) { + $contriblist = $contriblist->concat($contribs->contributors); + } else { + // We have reached the end of the dataset + break; + } + } + + // Clear out list if necessary. Disabled under assumption contributors cant leave list + // CorporationProjectContributor::where('project_id', $this->project_id)->delete(); + + $rows = $contriblist->map(function ($item) use ($proj) { + // handle object or array item + $id = is_object($item) ? ($item->id ?? null) : ($item['id'] ?? null); + $contributed = is_object($item) ? ($item->contributed ?? 0) : ($item['contributed'] ?? 0); + return [ + 'project_id' => $proj->id, + 'character_id' => $id, + 'contributed' => $contributed, + ]; + })->toArray(); + + // Perform upsert: unique by project_id + character_id, update contributed on conflict + // Timestamps are auto updated + CorporationProjectContributor::upsert( + $rows, + uniqueBy: ['project_id', 'character_id'], + update: ['contributed'] + ); + + } +} diff --git a/src/Jobs/CorporationProjects/Details.php b/src/Jobs/CorporationProjects/Details.php new file mode 100644 index 00000000..40453a54 --- /dev/null +++ b/src/Jobs/CorporationProjects/Details.php @@ -0,0 +1,148 @@ +project_id = $project_id; + + parent::__construct($corporation_id, $token); + } + + /** + * Execute the job. + * + * @return void + * + * @throws \Throwable + */ + public function handle() + { + parent::handle(); + + $cid = $this->getCorporationId(); // Extract it here early as we use it a log + + $response = $this->retrieve([ + 'project_id' => $this->project_id, + 'corporation_id' => $cid, + ]); + + $details = $response->getBody(); + + $lm = Carbon::parse($details->last_modified); + + // Weird early projects, bad data + $thresholdDate = Carbon::parse('2025-01-01'); + if ($lm->isBefore($thresholdDate)){ + logger()->warning('early project detected', ['body' => $details]); // TODO investigate + return; + } + + $proj = CorporationProject::firstOrNew([ + 'id' => $this->project_id, + 'corporation_id' => $cid, + ]); + + ProjectsMapping::make($proj, $details, [ + 'last_modified' => function() use ($lm) { + return $lm->format('Y-m-d H:i:s'); + }, + 'corporation_id' => function() use ($cid) { + return $cid; + }, + 'created' => function() use ($details) { + return Carbon::parse($details->details->created)->format('Y-m-d H:i:s'); + }, + 'finished' => function() use ($details) { + if (!isset($details->details->finished)){ + return; + } + return Carbon::parse($details->details->finished)->format('Y-m-d H:i:s'); + }, + 'expires' => function() use ($details) { + if (!isset($details->details->expires)){ + return; + } + return Carbon::parse($details->details->expires)->format('Y-m-d H:i:s'); + }, + 'configuration' => function() use ($details) { + return json_encode($details->configuration); + }, + ])->save(); + + + } +} diff --git a/src/Jobs/CorporationProjects/Projects.php b/src/Jobs/CorporationProjects/Projects.php new file mode 100644 index 00000000..ec3c3215 --- /dev/null +++ b/src/Jobs/CorporationProjects/Projects.php @@ -0,0 +1,154 @@ +query_string["limit"] = "100"; + $this->query_string["state"] = "All"; + + $before = "0"; + + $this->project_jobs = collect(); + + while (true) { + + // TODO - proper cursor based caching, not just grab it all every time. + $this->query_string["before"] = $before; + + $response = $this->retrieve([ + 'corporation_id' => $this->getCorporationId(), + ]); + + $projects = $response->getBody(); + if (isset($projects->cursor) && isset($projects->cursor->before)) { + $before = $projects->cursor->before; + } else { + break; // empty cursor + } + if (isset($projects->projects)) { + foreach ($projects->projects as $project) { + $lm = Carbon::parse($project->last_modified); + // Weird early projects + $thresholdDate = Carbon::parse('2025-01-01'); + if ($lm->isBefore($thresholdDate)){ + logger()->warning('early project detected', ['project' => $project]); // TODO investigate + continue; + } + + $proj = CorporationProject::firstOrNew([ + 'id' => $project->id, + ]); + // dd($project->last_modified, gettype(Carbon($project->last_modified)->format('Y-m-d H:i:s')), Carbon($project->last_modified)->format('Y-m-d H:i:s')); + ProjectsMapping::make($proj, $project, [ + 'last_modified' => function() use ($lm) { + return $lm->format('Y-m-d H:i:s'); + }, + 'corporation_id' => function () { + return $this->getCorporationId(); + }, + ])->save(); + + $this->project_jobs->add(new Details($this->getCorporationId(), $this->getToken(), $proj->id)); + $this->project_jobs->add(new Contributors($this->getCorporationId(), $this->getToken(), $proj->id)); + } + } else { + // We have reached the end of the dataset + break; + } + } + + if ($this->project_jobs->isNotEmpty()) { + if($this->batchId) { + $this->batch()->add($this->project_jobs->toArray()); + } else { + Bus::batch($this->project_jobs->toArray()) + ->name(sprintf('Projects: %s', $this->token->character->name ?? $this->token->character_id)) + ->onQueue($this->job->getQueue()) + ->dispatch(); + } + } + + } +} diff --git a/src/Mapping/CorporationProjects/ProjectsMapping.php b/src/Mapping/CorporationProjects/ProjectsMapping.php new file mode 100644 index 00000000..11409aef --- /dev/null +++ b/src/Mapping/CorporationProjects/ProjectsMapping.php @@ -0,0 +1,59 @@ + 'id', + 'corporation_id' => 'corporation_id', + 'last_modified' => 'last_modified', + 'name' => 'name', + 'progress_current' => 'progress.current', + 'progress_desired' => 'progress.desired', + 'reward_initial' => 'reward.initial', + 'reward_remaining' => 'reward.remaining', + 'state' => 'state', + 'configuration' => 'configuration', + 'contribution_participation_limit' => 'contribution.participation_limit', + 'contribution_reward' => 'contribution.reward_per_contribution', + 'contribution_submission_limit' => 'contribution.submission_limit', + 'contribution_submission_multiplier' => 'contribution.submission_multiplier', + 'creator_id' => 'creator.id', + 'career' => 'details.career', + 'created' => 'details.created', + 'description' => 'details.description', + 'expires' => 'details.expires', + 'finished' => 'details.finished' + ]; +} diff --git a/src/Models/CorporationProjects/CorporationProject.php b/src/Models/CorporationProjects/CorporationProject.php new file mode 100644 index 00000000..907705f2 --- /dev/null +++ b/src/Models/CorporationProjects/CorporationProject.php @@ -0,0 +1,61 @@ +hasMany(CorporationProjectContributor::class, 'project_id', 'id'); + } + + public function creator() + { + return $this->hasOne(UniverseName::class, 'entity_id', 'creator_id') + ->withDefault([ + 'category' => 'character', + 'name' => trans('web::seat.unknown'), + ]); + } + +} diff --git a/src/Models/CorporationProjects/CorporationProjectContributor.php b/src/Models/CorporationProjects/CorporationProjectContributor.php new file mode 100644 index 00000000..f7442d7a --- /dev/null +++ b/src/Models/CorporationProjects/CorporationProjectContributor.php @@ -0,0 +1,56 @@ + 'integer' + ]; + + public function project() + { + return $this->belongsTo(CorporationProject::class, 'project_id', 'id'); + } + + public function character() + { + return $this->belongsTo(CharacterInfo::class, 'character_id', 'character_id'); + } +} diff --git a/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php b/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php new file mode 100644 index 00000000..1cbb0d6b --- /dev/null +++ b/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php @@ -0,0 +1,78 @@ +uuid('id')->primary(); + $table->bigInteger('corporation_id')->index(); // Index because the datatable will filter on it. + $table->dateTime('last_modified'); + $table->string('name', length:61); + $table->bigInteger('progress_current'); + $table->bigInteger('progress_desired'); + $table->double('reward_initial')->nullable(); + $table->double('reward_remaining')->nullable(); + $table->enum('state', ['Unspecified', 'Active', 'Closed', 'Completed', 'Expired', 'Deleted']); + + // The below only come from the details endpoint (which can also update some of the above) + $table->enum('career', ['Unspecified', 'Explorer', 'Industrialist', 'Enforcer', 'Soldier of Fortune'])->nullable(); + $table->dateTime('created')->nullable(); + $table->string('description', length:1001)->nullable(); + $table->dateTime('expires')->nullable(); + $table->dateTime('finished')->nullable(); + $table->bigInteger('creator_id')->nullable(); + + $table->bigInteger('contribution_participation_limit')->nullable(); + $table->double('contribution_reward')->nullable(); + $table->bigInteger('contribution_submission_limit')->nullable(); + $table->double('contribution_submission_multiplier')->nullable(); + + $table->json('configuration')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_projects'); + } +} diff --git a/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php b/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php new file mode 100644 index 00000000..d2496469 --- /dev/null +++ b/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php @@ -0,0 +1,57 @@ +bigIncrements('id'); + $table->foreignUuid('project_id')->constrained(table: 'corporation_projects')->cascadeOnDelete()->index(); + $table->unsignedBigInteger('character_id')->index(); + $table->bigInteger('contributed'); + + $table->unique(['project_id', 'character_id']); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('corporation_project_contributors'); + } +} From f4c25da9c98b8c903dd0a114c91155fad316e672 Mon Sep 17 00:00:00 2001 From: Crypta Eve Date: Mon, 23 Feb 2026 22:17:23 +1030 Subject: [PATCH 2/4] style: styleci --- src/Bus/Corporation.php | 2 +- src/Jobs/CorporationProjects/Contributors.php | 22 +++++++------- src/Jobs/CorporationProjects/Details.php | 29 +++++++++---------- src/Jobs/CorporationProjects/Projects.php | 18 +++++------- .../CorporationProjects/ProjectsMapping.php | 6 ++-- .../CorporationProject.php | 5 +--- .../CorporationProjectContributor.php | 13 ++++----- ...1928_create_corporation_projects_table.php | 4 +-- ...corporation_project_contributors_table.php | 2 +- 9 files changed, 46 insertions(+), 55 deletions(-) diff --git a/src/Bus/Corporation.php b/src/Bus/Corporation.php index 687da690..2cecd8a1 100644 --- a/src/Bus/Corporation.php +++ b/src/Bus/Corporation.php @@ -40,7 +40,6 @@ use Seat\Eveapi\Jobs\Corporation\MembersLimit; use Seat\Eveapi\Jobs\Corporation\MembersTitles; use Seat\Eveapi\Jobs\Corporation\MemberTracking; -use Seat\Eveapi\Jobs\CorporationProjects\Projects; use Seat\Eveapi\Jobs\Corporation\RoleHistories; use Seat\Eveapi\Jobs\Corporation\Roles; use Seat\Eveapi\Jobs\Corporation\Shareholders; @@ -49,6 +48,7 @@ use Seat\Eveapi\Jobs\Corporation\Starbases; use Seat\Eveapi\Jobs\Corporation\Structures; use Seat\Eveapi\Jobs\Corporation\Titles; +use Seat\Eveapi\Jobs\CorporationProjects\Projects; use Seat\Eveapi\Jobs\Industry\Corporation\Jobs; use Seat\Eveapi\Jobs\Industry\Corporation\Mining\Extractions; use Seat\Eveapi\Jobs\Industry\Corporation\Mining\ObserverDetails; diff --git a/src/Jobs/CorporationProjects/Contributors.php b/src/Jobs/CorporationProjects/Contributors.php index 593cae3a..0c9a8a18 100644 --- a/src/Jobs/CorporationProjects/Contributors.php +++ b/src/Jobs/CorporationProjects/Contributors.php @@ -22,13 +22,11 @@ namespace Seat\Eveapi\Jobs\CorporationProjects; -use Illuminate\Support\Facades\Log; use Seat\Eveapi\Jobs\AbstractAuthCorporationJob; use Seat\Eveapi\Models\CorporationProjects\CorporationProject; use Seat\Eveapi\Models\CorporationProjects\CorporationProjectContributor; use Seat\Eveapi\Models\RefreshToken; - /** * Class Projects. * @@ -46,7 +44,6 @@ class Contributors extends AbstractAuthCorporationJob */ protected $endpoint = '/corporations/{corporation_id}/projects/{project_id}/contributors'; - /** * @var string */ @@ -94,9 +91,9 @@ public function handle() { parent::handle(); - $this->query_string["limit"] = "100"; + $this->query_string['limit'] = '100'; - $before = "0"; + $before = '0'; $proj = CorporationProject::findOrFail($this->project_id); @@ -104,7 +101,7 @@ public function handle() while (true) { - $this->query_string["before"] = $before; + $this->query_string['before'] = $before; $response = $this->retrieve([ 'corporation_id' => $this->getCorporationId(), @@ -128,24 +125,25 @@ public function handle() // Clear out list if necessary. Disabled under assumption contributors cant leave list // CorporationProjectContributor::where('project_id', $this->project_id)->delete(); - $rows = $contriblist->map(function ($item) use ($proj) { - // handle object or array item + $rows = $contriblist->map(function ($item) use ($proj) { + // handle object or array item $id = is_object($item) ? ($item->id ?? null) : ($item['id'] ?? null); $contributed = is_object($item) ? ($item->contributed ?? 0) : ($item['contributed'] ?? 0); - return [ + + return [ 'project_id' => $proj->id, 'character_id' => $id, 'contributed' => $contributed, - ]; + ]; })->toArray(); // Perform upsert: unique by project_id + character_id, update contributed on conflict // Timestamps are auto updated - CorporationProjectContributor::upsert( + CorporationProjectContributor::upsert( $rows, uniqueBy: ['project_id', 'character_id'], update: ['contributed'] ); - + } } diff --git a/src/Jobs/CorporationProjects/Details.php b/src/Jobs/CorporationProjects/Details.php index 40453a54..115542a6 100644 --- a/src/Jobs/CorporationProjects/Details.php +++ b/src/Jobs/CorporationProjects/Details.php @@ -3,7 +3,7 @@ /* * This file is part of SeAT * - * Copyright (C) 2026 to present Leon Jacobs + * Copyright (C) 2015 to present Leon Jacobs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,13 +22,12 @@ namespace Seat\Eveapi\Jobs\CorporationProjects; +use Carbon\Carbon; use Seat\Eveapi\Jobs\AbstractAuthCorporationJob; use Seat\Eveapi\Mapping\CorporationProjects\ProjectsMapping; use Seat\Eveapi\Models\CorporationProjects\CorporationProject; use Seat\Eveapi\Models\RefreshToken; -use Carbon\Carbon; - /** * Class Projects. * @@ -46,13 +45,11 @@ class Details extends AbstractAuthCorporationJob */ protected $endpoint = '/corporations/{corporation_id}/projects/{project_id}'; - /** * @var string */ protected $scope = 'esi-corporations.read_projects.v1'; - /** * When this job was written, so ESI can try to serve a response compatible with the behaviour of the endpoint at that time. * @@ -103,11 +100,12 @@ public function handle() $details = $response->getBody(); $lm = Carbon::parse($details->last_modified); - + // Weird early projects, bad data $thresholdDate = Carbon::parse('2025-01-01'); if ($lm->isBefore($thresholdDate)){ logger()->warning('early project detected', ['body' => $details]); // TODO investigate + return; } @@ -117,32 +115,33 @@ public function handle() ]); ProjectsMapping::make($proj, $details, [ - 'last_modified' => function() use ($lm) { + 'last_modified' => function () use ($lm) { return $lm->format('Y-m-d H:i:s'); }, - 'corporation_id' => function() use ($cid) { + 'corporation_id' => function () use ($cid) { return $cid; }, - 'created' => function() use ($details) { + 'created' => function () use ($details) { return Carbon::parse($details->details->created)->format('Y-m-d H:i:s'); }, - 'finished' => function() use ($details) { - if (!isset($details->details->finished)){ + 'finished' => function () use ($details) { + if (! isset($details->details->finished)){ return; } + return Carbon::parse($details->details->finished)->format('Y-m-d H:i:s'); }, - 'expires' => function() use ($details) { - if (!isset($details->details->expires)){ + 'expires' => function () use ($details) { + if (! isset($details->details->expires)){ return; } + return Carbon::parse($details->details->expires)->format('Y-m-d H:i:s'); }, - 'configuration' => function() use ($details) { + 'configuration' => function () use ($details) { return json_encode($details->configuration); }, ])->save(); - } } diff --git a/src/Jobs/CorporationProjects/Projects.php b/src/Jobs/CorporationProjects/Projects.php index ec3c3215..9367f9ce 100644 --- a/src/Jobs/CorporationProjects/Projects.php +++ b/src/Jobs/CorporationProjects/Projects.php @@ -22,13 +22,12 @@ namespace Seat\Eveapi\Jobs\CorporationProjects; +use Carbon\Carbon; use Illuminate\Support\Facades\Bus; use Seat\Eveapi\Jobs\AbstractAuthCorporationJob; use Seat\Eveapi\Mapping\CorporationProjects\ProjectsMapping; use Seat\Eveapi\Models\CorporationProjects\CorporationProject; -use Carbon\Carbon; - /** * Class Projects. * @@ -46,7 +45,6 @@ class Projects extends AbstractAuthCorporationJob */ protected $endpoint = '/corporations/{corporation_id}/projects'; - /** * @var string */ @@ -85,17 +83,17 @@ public function handle() { parent::handle(); - $this->query_string["limit"] = "100"; - $this->query_string["state"] = "All"; + $this->query_string['limit'] = '100'; + $this->query_string['state'] = 'All'; - $before = "0"; + $before = '0'; $this->project_jobs = collect(); while (true) { // TODO - proper cursor based caching, not just grab it all every time. - $this->query_string["before"] = $before; + $this->query_string['before'] = $before; $response = $this->retrieve([ 'corporation_id' => $this->getCorporationId(), @@ -116,13 +114,13 @@ public function handle() logger()->warning('early project detected', ['project' => $project]); // TODO investigate continue; } - + $proj = CorporationProject::firstOrNew([ 'id' => $project->id, ]); // dd($project->last_modified, gettype(Carbon($project->last_modified)->format('Y-m-d H:i:s')), Carbon($project->last_modified)->format('Y-m-d H:i:s')); ProjectsMapping::make($proj, $project, [ - 'last_modified' => function() use ($lm) { + 'last_modified' => function () use ($lm) { return $lm->format('Y-m-d H:i:s'); }, 'corporation_id' => function () { @@ -138,7 +136,7 @@ public function handle() break; } } - + if ($this->project_jobs->isNotEmpty()) { if($this->batchId) { $this->batch()->add($this->project_jobs->toArray()); diff --git a/src/Mapping/CorporationProjects/ProjectsMapping.php b/src/Mapping/CorporationProjects/ProjectsMapping.php index 11409aef..6d916eca 100644 --- a/src/Mapping/CorporationProjects/ProjectsMapping.php +++ b/src/Mapping/CorporationProjects/ProjectsMapping.php @@ -3,7 +3,7 @@ /* * This file is part of SeAT * - * Copyright (C) 2026 to present Leon Jacobs + * Copyright (C) 2015 to present Leon Jacobs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,6 +54,6 @@ class ProjectsMapping extends DataMapping 'created' => 'details.created', 'description' => 'details.description', 'expires' => 'details.expires', - 'finished' => 'details.finished' - ]; + 'finished' => 'details.finished', + ]; } diff --git a/src/Models/CorporationProjects/CorporationProject.php b/src/Models/CorporationProjects/CorporationProject.php index 907705f2..7a22a0c2 100644 --- a/src/Models/CorporationProjects/CorporationProject.php +++ b/src/Models/CorporationProjects/CorporationProject.php @@ -3,7 +3,7 @@ /* * This file is part of SeAT * - * Copyright (C) 2026 to present Leon Jacobs + * Copyright (C) 2015 to present Leon Jacobs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,8 +22,6 @@ namespace Seat\Eveapi\Models\CorporationProjects; -use Seat\Eveapi\Models\Character\CharacterInfo; -use Seat\Eveapi\Models\CorporationProjects\CorporationProjectContributor; use Seat\Eveapi\Models\Universe\UniverseName; use Seat\Services\Models\ExtensibleModel; @@ -57,5 +55,4 @@ public function creator() 'name' => trans('web::seat.unknown'), ]); } - } diff --git a/src/Models/CorporationProjects/CorporationProjectContributor.php b/src/Models/CorporationProjects/CorporationProjectContributor.php index f7442d7a..28424a36 100644 --- a/src/Models/CorporationProjects/CorporationProjectContributor.php +++ b/src/Models/CorporationProjects/CorporationProjectContributor.php @@ -3,7 +3,7 @@ /* * This file is part of SeAT * - * Copyright (C) 2026 to present Leon Jacobs + * Copyright (C) 2015 to present Leon Jacobs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,9 +22,8 @@ namespace Seat\Eveapi\Models\CorporationProjects; - -use Seat\Services\Models\ExtensibleModel; use Seat\Eveapi\Models\Character\CharacterInfo; +use Seat\Services\Models\ExtensibleModel; class CorporationProjectContributor extends ExtensibleModel { @@ -37,12 +36,12 @@ class CorporationProjectContributor extends ExtensibleModel protected $fillable = [ 'project_id', 'character_id', - 'contributed' - ]; + 'contributed', + ]; protected $casts = [ - 'contributed' => 'integer' - ]; + 'contributed' => 'integer', + ]; public function project() { diff --git a/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php b/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php index 1cbb0d6b..a25d218d 100644 --- a/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php +++ b/src/database/migrations/2025_08_17_141928_create_corporation_projects_table.php @@ -34,9 +34,9 @@ class CreateCorporationProjectsTable extends Migration public function up() { Schema::create('corporation_projects', function (Blueprint $table) { - + // The below are all obtainable from the list api - + $table->uuid('id')->primary(); $table->bigInteger('corporation_id')->index(); // Index because the datatable will filter on it. $table->dateTime('last_modified'); diff --git a/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php b/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php index d2496469..e2e710c1 100644 --- a/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php +++ b/src/database/migrations/2025_08_21_075552_create_corporation_project_contributors_table.php @@ -34,7 +34,7 @@ class CreateCorporationProjectContributorsTable extends Migration public function up() { Schema::create('corporation_project_contributors', function (Blueprint $table) { - + $table->bigIncrements('id'); $table->foreignUuid('project_id')->constrained(table: 'corporation_projects')->cascadeOnDelete()->index(); $table->unsignedBigInteger('character_id')->index(); From c8cea7e726f8ba8a4181cdfe7e9b38a96b5a79b2 Mon Sep 17 00:00:00 2001 From: Crypta Eve Date: Mon, 23 Feb 2026 22:26:06 +1030 Subject: [PATCH 3/4] chore: bump eseye dependency --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c18ae597..e2e8140a 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "php": "^8.1", "laravel/framework": "^10.0", "maatwebsite/excel": "^3.1.45", - "eveseat/eseye": "^3.2", + "eveseat/eseye": "^3.2.1", "eveseat/services": "^5.1", "guzzlehttp/guzzle": "^7.0", "doctrine/dbal": "^3.0", From 8e7cec589ea97d479b8b36b300670946fe37bdda Mon Sep 17 00:00:00 2001 From: Crypta Eve Date: Wed, 25 Feb 2026 22:21:36 +1030 Subject: [PATCH 4/4] feat: thanks r'tree for review! --- src/Jobs/CorporationProjects/Contributors.php | 6 ++---- src/Jobs/CorporationProjects/Details.php | 9 ++------- src/Jobs/CorporationProjects/Projects.php | 4 ++-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Jobs/CorporationProjects/Contributors.php b/src/Jobs/CorporationProjects/Contributors.php index 0c9a8a18..22911078 100644 --- a/src/Jobs/CorporationProjects/Contributors.php +++ b/src/Jobs/CorporationProjects/Contributors.php @@ -52,7 +52,7 @@ class Contributors extends AbstractAuthCorporationJob /** * @var array */ - protected $roles = ['Project Manager']; // TODO: TBC + protected $roles = ['Project Manager']; /** * When this job was written, so ESI can try to serve a response compatible with the behaviour of the endpoint at that time. @@ -69,9 +69,7 @@ class Contributors extends AbstractAuthCorporationJob /** * @var string */ - protected $version = ''; - - private $project_id; + private string $project_id; public function __construct(int $corporation_id, RefreshToken $token, string $project_id) { diff --git a/src/Jobs/CorporationProjects/Details.php b/src/Jobs/CorporationProjects/Details.php index 115542a6..02844c03 100644 --- a/src/Jobs/CorporationProjects/Details.php +++ b/src/Jobs/CorporationProjects/Details.php @@ -65,12 +65,7 @@ class Details extends AbstractAuthCorporationJob /** * @var string */ - private $project_id; - - /** - * @var string - */ - protected $version = ''; + private string $project_id; public function __construct(int $corporation_id, RefreshToken $token, string $project_id) { @@ -104,7 +99,7 @@ public function handle() // Weird early projects, bad data $thresholdDate = Carbon::parse('2025-01-01'); if ($lm->isBefore($thresholdDate)){ - logger()->warning('early project detected', ['body' => $details]); // TODO investigate + logger()->warning('early project detected', ['body' => $details]); // These may need investigation by CCP if requried. return; } diff --git a/src/Jobs/CorporationProjects/Projects.php b/src/Jobs/CorporationProjects/Projects.php index 9367f9ce..f8c78e0e 100644 --- a/src/Jobs/CorporationProjects/Projects.php +++ b/src/Jobs/CorporationProjects/Projects.php @@ -111,14 +111,14 @@ public function handle() // Weird early projects $thresholdDate = Carbon::parse('2025-01-01'); if ($lm->isBefore($thresholdDate)){ - logger()->warning('early project detected', ['project' => $project]); // TODO investigate + logger()->warning('early project detected', ['project' => $project]); // // These may need investigation by CCP if requried. continue; } $proj = CorporationProject::firstOrNew([ 'id' => $project->id, ]); - // dd($project->last_modified, gettype(Carbon($project->last_modified)->format('Y-m-d H:i:s')), Carbon($project->last_modified)->format('Y-m-d H:i:s')); + ProjectsMapping::make($proj, $project, [ 'last_modified' => function () use ($lm) { return $lm->format('Y-m-d H:i:s');