Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Campaign Import #767

Merged
merged 41 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
af70d29
Campaign import: form vip
ilestis Nov 7, 2023
4095902
Merge branch 'main' into features/import
ilestis Nov 7, 2023
9000737
Import: VIP 2
ilestis Nov 9, 2023
2066967
Import: Gallery
ilestis Nov 10, 2023
30eabb8
Import: Gallery
ilestis Nov 10, 2023
23b270e
Import: Tags & Calendar boilerplate
ilestis Nov 10, 2023
dfce15a
Import: Tags & Calendar boilerplate
ilestis Nov 10, 2023
324c63e
Import: more boilerplate
ilestis Nov 10, 2023
0b499de
Map legend links
ilestis Nov 11, 2023
d122dce
Performance improvements on chunky dashboards
ilestis Nov 11, 2023
1e3f19d
Performance improvements on chunky dashboards
ilestis Nov 11, 2023
909e427
Performance tweak for who's enabling premium features
ilestis Nov 12, 2023
4379d86
Dashboard mentions performance tweaks
ilestis Nov 12, 2023
294b908
Fix spelling, quick creator "more", and buttons displayed twice on da…
ilestis Nov 12, 2023
dcf9861
Fix crash
ilestis Nov 12, 2023
bf72886
Fix new campaign error
ilestis Nov 12, 2023
70d2eb9
Default order of tags to alphabetical
ilestis Nov 12, 2023
f405a14
Perf improvements for grid thumbnails
ilestis Nov 12, 2023
9aba47c
Fix adding attributes not draggable on subform
ilestis Nov 12, 2023
44764fc
Fix purge issue
ilestis Nov 12, 2023
27a2b35
Fix cover backgorund on entity header
ilestis Nov 13, 2023
b6494b8
Fix family tree visibility
ilestis Nov 13, 2023
45bc3cc
Mapper: more base entities
ilestis Nov 13, 2023
bba9571
Fix grids on mobile
ilestis Nov 13, 2023
2895809
Merge branch 'main' into features/import
ilestis Nov 13, 2023
b3bdd6f
Remove junk from export
ilestis Nov 14, 2023
e45f3b4
Refactor export to only include useful data, better perf, and asset f…
ilestis Nov 16, 2023
a2a4803
Import: foreign values for characters
ilestis Nov 16, 2023
b12738b
Import: sub elements & refactoring
ilestis Nov 16, 2023
6f069cf
Import: mentions and foreign keys
ilestis Nov 16, 2023
4667b55
Import: created by
ilestis Nov 16, 2023
e41282c
Import: header image
ilestis Nov 16, 2023
2cd8704
Import: mentions
ilestis Nov 16, 2023
66f9864
Import: cleanup, finish importing related data
ilestis Nov 16, 2023
3789ef3
Import: better form
ilestis Nov 16, 2023
52c399b
Fix styling
ilestis Nov 16, 2023
896a0e0
Import: cleanup zip, laravel pint
ilestis Nov 16, 2023
4c7178a
Import: ui
ilestis Nov 16, 2023
6288f65
Export: include info.md
ilestis Nov 16, 2023
0d64fc5
Fix phpstan
ilestis Nov 17, 2023
33d0d88
Fix styling
ilestis Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions app/Console/Commands/Campaigns/ImportCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Console\Commands\Campaigns;

use App\Enums\CampaignImportStatus;
use App\Jobs\Campaigns\Import;
use App\Models\Campaign;
use App\Models\CampaignImport;
use Illuminate\Console\Command;

class ImportCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'campaigns:import {campaign}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Re-run an import job';

/**
* Execute the console command.
*/
public function handle()
{
$campaignID = $this->argument('campaign');
$campaign = Campaign::find($campaignID);

$job = CampaignImport::where('campaign_id', $campaign->id)->orderBy('created_at', 'DESC')->
where('status_id', '<>', 1)->first();
if (!$job) {
$this->info('No job for campaign ' . $campaign->id);
return;
}

$job->status_id = CampaignImportStatus::QUEUED;
$job->saveQuietly();

Import::dispatch($job);
$this->info('Re-queued campaign ' . $campaign->id);
}
}
12 changes: 12 additions & 0 deletions app/Enums/CampaignImportStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace App\Enums;

enum CampaignImportStatus: int
{
case PREPARED = 1;
case QUEUED = 2;
case RUNNING = 3;
case FINISHED = 4;
case FAILED = 5;
}
25 changes: 25 additions & 0 deletions app/Facades/ImportIdMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

/**
* Class QuestCache
* @package App\Facades
*
* @see \App\Services\Campaign\Import\ImportIdMapper
* @mixin \App\Services\Campaign\Import\ImportIdMapper
*/
class ImportIdMapper extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'importidmapper';
}
}
59 changes: 59 additions & 0 deletions app/Http/Controllers/Campaign/ImportController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace App\Http\Controllers\Campaign;

use App\Enums\CampaignImportStatus;
use App\Facades\Datagrid;
use App\Http\Controllers\Controller;
use App\Models\Campaign;
use App\Services\Campaign\Import\PrepareService;

class ImportController extends Controller
{
protected PrepareService $service;
public function __construct(PrepareService $prepareService)
{
$this->middleware('auth');
$this->service = $prepareService;
}

public function index(Campaign $campaign)
{
$this->authorize('setting', $campaign);


Datagrid::layout(\App\Renderers\Layouts\Campaign\CampaignImport::class);

$rows = $campaign->campaignImports()
->sort(request()->only(['o', 'k']))
->where('status_id', '<>', CampaignImportStatus::PREPARED)
->with(['user'])
->orderBy('updated_at', 'DESC')
->paginate();

// Ajax Datagrid
if (request()->ajax()) {
$html = view('layouts.datagrid._table')->with('rows', $rows)->render();
return response()->json([
'success' => true,
'html' => $html,
]);
}

$token = null;
if (auth()->user()->isSubscriber()) {
$token = $this->service
->campaign($campaign)
->user(auth()->user())
->token();
}



return view('campaigns.import.index')
->with('campaign', $campaign)
->with('token', $token)
->with('rows', $rows)
;
}
}
2 changes: 1 addition & 1 deletion app/Http/Controllers/CrudController.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public function crudIndex(Request $request)
// Don't use total as it won't use the distinct() filters (typically when doing
// left join on the entities table)
$filteredCount = $models->total();
//$filteredCount = count($models); //->total()
//$filteredCount = count($models); //->total()
} else {
/** @var Paginator $models */
$models = $base->paginate();
Expand Down
5 changes: 3 additions & 2 deletions app/Http/Controllers/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function index(Campaign $campaign)
}

$hasMap = false;
$hasCampaignHeader = false;
$hasCampaignHeader = $requestedDashboard === null;
foreach ($widgets as $w) {
if ($w->widget === Widget::Preview && $w->entity && $w->visible() && $w->entity->isMap()) {
$hasMap = true;
Expand Down Expand Up @@ -95,10 +95,11 @@ public function unmentioned(Campaign $campaign, $id)
]);
}

// @phpstan-ignore-next-line
$entities = \App\Models\Entity::unmentioned()
->inTags($widget->tags->pluck('id')->toArray())
->type($widget->conf('entity'))
->with(['updater'])
->type($widget->conf('entity'))
->paginate(10);

return view('dashboard.widgets._recent_list')
Expand Down
4 changes: 3 additions & 1 deletion app/Http/Controllers/Families/TreeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
use App\Http\Controllers\Controller;
use App\Models\Campaign;
use App\Models\Family;
use App\Traits\CampaignAware;
use App\Traits\GuestAuthTrait;

class TreeController extends Controller
{
use CampaignAware;
use GuestAuthTrait;

public function index(Campaign $campaign, Family $family)
{
$this->authView($family);
$this->campaign($campaign)->authEntityView($family->entity);

return view('families.trees.index')
->with('family', $family)
Expand Down
4 changes: 3 additions & 1 deletion app/Http/Controllers/Families/Trees/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
use App\Models\Entity;
use App\Models\Family;
use App\Services\Families\FamilyTreeService;
use App\Traits\CampaignAware;
use App\Traits\GuestAuthTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class ApiController extends Controller
{
use CampaignAware;
use GuestAuthTrait;

protected FamilyTreeService $service;
Expand All @@ -27,7 +29,7 @@ public function __construct(FamilyTreeService $service)
*/
public function index(Campaign $campaign, Family $family): JsonResponse
{
$this->authView($family);
$this->campaign($campaign)->authEntityView($family->entity);

return response()->json(
$this
Expand Down
2 changes: 2 additions & 0 deletions app/Http/Middleware/LocaleChange.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public function handle(Request $request, Closure $next)

// If it's not a get request, don't touch it either
if (!$request->isMethod('get')) {
$locale = $this->currentLocale();
LaravelLocalization::setLocale($locale);
return $next($request);
}

Expand Down
76 changes: 76 additions & 0 deletions app/Jobs/Campaigns/Import.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace App\Jobs\Campaigns;

use App\Enums\CampaignImportStatus;
use App\Models\CampaignImport;
use App\Services\Campaign\Import\ImportService;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Throwable;

class Import implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;

/**
* The number of times the job may be attempted.
*
* @var int
*/
public $tries = 1;

protected int $jobID;

/**
* CampaignExport constructor.
*/
public function __construct(CampaignImport $campaignImport)
{
$this->jobID = $campaignImport->id;
}

/**
* Execute the job
* @throws Exception
*/
public function handle()
{
Log::info('Campaign import', ['init', 'id' => $this->jobID]);
/** @var CampaignImport $job */
$job = CampaignImport::find($this->jobID);
if (!$job) {
Log::info('Campaign import', ['empty', 'id' => $this->jobID]);
return 0;
}
if (!$job->campaign || !$job->user) {
Log::info('Campaign import', ['empty_campaign_or_user', 'id' => $this->jobID]);
return 0;
}
Log::info('Campaign import', ['running', 'id' => $this->jobID]);
$job->update(['status_id' => CampaignImportStatus::RUNNING]);

/** @var ImportService $service */
$service = app()->make(ImportService::class);
$service
->job($job)
->run();

return 1;
}

/**
*
*/
public function failed(Throwable $exception)
{
}
}
5 changes: 5 additions & 0 deletions app/Models/Ability.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class Ability extends MiscModel
*/
protected string $entityType = 'ability';

protected array $exportFields = [
'base',
'charges'
];

/**
* Parent ID used for the Node Trait
* @return string
Expand Down
16 changes: 15 additions & 1 deletion app/Models/Attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ protected function calculateListConstraints(): self
*/
public function listRange(): array
{
if (! is_array($this->listRange)) {
if (!is_array($this->listRange)) {
return [];
}
return $this->listRange;
Expand All @@ -365,4 +365,18 @@ public function listRangeText(): string
{
return implode(', ', $this->listRange);
}

public function exportFields(): array
{
return [
'id',
'type_id',
'name',
'value',
'is_private',
'default_order',
'is_pinned',
'is_hidden',
];
}
}
4 changes: 4 additions & 0 deletions app/Models/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ class Calendar extends MiscModel
'parameters' => 'array'
];

protected array $foreignExport = [
'calendarWeather',
];

protected array $loadedMonths;

protected array $loadedWeekdays;
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Campaign.php
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ public function thumbnail(int $width = 400, int $height = null, string $field =
public function exportable(): bool
{
if (!app()->isProduction()) {
return $this->queuedCampaignExports->count() === 0;
return true; //$this->queuedCampaignExports->count() === 0;
}

return empty($this->export_date) || !$this->export_date->isToday() && $this->queuedCampaignExports->count() === 0;
Expand Down
10 changes: 7 additions & 3 deletions app/Models/CampaignDashboardWidget.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ public function colSize(): int
*/
public function scopePositioned(Builder $query): Builder
{
return $query->with(['entity', 'entity.image', 'tags'])
return $query->with([
'entity', 'entity.image',
'tags',
'entity.mentions', 'entity.mentions.target', 'entity.mentions.target.tags:id,name,slug'
])
->orderBy('position', 'asc');
}

Expand Down Expand Up @@ -286,7 +290,7 @@ public function entities()
return $base
->inTags($this->tags->pluck('id')->toArray())
->type($entityTypeID)
->with(['image:campaign_id,id,ext'])
->with(['image:campaign_id,id,ext', 'mentions', 'mentions.target', 'mentions.target.tags'])
->paginate(10)
;
}
Expand Down Expand Up @@ -450,6 +454,6 @@ public function visible(): bool
return true;
}
// Linked but no entity or no child? Permission issue or deleted entity
return !empty($this->entity) && !empty($this->entity->child);
return !empty($this->entity);
}
}
Loading