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

Organisations can now have multiple locations #855

Merged
merged 4 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
56 changes: 56 additions & 0 deletions app/Console/Commands/Migrations/MigrateOrganisationLocations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace App\Console\Commands\Migrations;

use App\Models\Organisation;
use App\Models\OrganisationLocation;
use Illuminate\Console\Command;

class MigrateOrganisationLocations extends Command
{
public $count = 0;

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'organisation:locations';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Migrate organisation location to locations';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
OrganisationLocation::truncate();
Organisation::whereNotNull('location_id')->chunk(1000, function ($organisations) {
$this->info('1000 Chunk...');
foreach ($organisations as $organisation) {
$organisation->locations()->attach($organisation->location_id);
$this->count++;
}
});

$this->info('Migrated ' . $this->count . ' organisations');
return 0;
}
}
1 change: 1 addition & 0 deletions app/Datagrids/Bulks/CreatureBulk.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class CreatureBulk extends Bulk
'name',
'type',
'creature_id',
'locations',
'tags',
'private_choice',
'extinct_choice',
Expand Down
2 changes: 1 addition & 1 deletion app/Datagrids/Bulks/OrganisationBulk.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class OrganisationBulk extends Bulk
protected array $fields = [
'name',
'type',
'location_id',
'locations',
'organisation_id',
'tags',
'private_choice',
Expand Down
1 change: 1 addition & 0 deletions app/Datagrids/Bulks/RaceBulk.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class RaceBulk extends Bulk
'name',
'type',
'race_id',
'locations',
'tags',
'private_choice',
'entity_image',
Expand Down
1 change: 1 addition & 0 deletions app/Http/Controllers/Api/v1/OrganisationApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function store(Request $request, Campaign $campaign)
$data['campaign_id'] = $campaign->id;
$model = Organisation::create($data);
$this->crudSave($model);
$model->refresh();
return new Resource($model);
}

Expand Down
1 change: 0 additions & 1 deletion app/Http/Requests/StoreOrganisation.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public function rules()
'entry' => 'nullable|string',
'type' => 'nullable|string|max:191',
'image' => 'mimes:jpeg,png,jpg,gif,webp|max:' . Limit::upload(),
'location_id' => 'nullable|integer|exists:locations,id',
spitfire305 marked this conversation as resolved.
Show resolved Hide resolved
'organisation_id' => 'nullable|exists:organisations,id',
'image_url' => 'nullable|url|active_url',
'template_id' => 'nullable',
Expand Down
4 changes: 3 additions & 1 deletion app/Http/Resources/OrganisationResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ public function toArray($request)
{
/** @var Organisation $model */
$model = $this->resource;
$locationIDs = $model->locations()->pluck('locations.id');
return $this->entity([
'type' => $model->type,
'organisation_id' => $model->organisation_id,
'is_defunct' => (bool) $model->is_defunct,
'members' => OrganisationMemberResource::collection($model->members()->has('character')->with('character')->get())
'members' => OrganisationMemberResource::collection($model->members()->has('character')->with('character')->get()),
'locations' => $locationIDs
]);
}
}
56 changes: 54 additions & 2 deletions app/Models/Organisation.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* @property Collection|OrganisationMember[] $members
* @property Collection|Organisation[] $descendants
* @property Collection|Organisation[] $organisations
* * @property Collection|Location[] $locations
spitfire305 marked this conversation as resolved.
Show resolved Hide resolved
* @property bool $is_defunct
*/
class Organisation extends MiscModel
Expand All @@ -43,7 +44,6 @@ class Organisation extends MiscModel
'name',
'slug',
'entry',
'location_id',
'organisation_id',
'type',
'is_private',
Expand Down Expand Up @@ -75,6 +75,7 @@ class Organisation extends MiscModel
*/
protected array $foreignExport = [
'members',
'pivotLocations',
];

protected array $exportFields = [
Expand Down Expand Up @@ -107,6 +108,9 @@ public function scopePreparedWith(Builder $query): Builder
'entity.image',
'location',
spitfire305 marked this conversation as resolved.
Show resolved Hide resolved
'location.entity',
'locations' => function ($sub) {
$sub->select('id', 'name');
},
ilestis marked this conversation as resolved.
Show resolved Hide resolved
'parent' => function ($sub) {
$sub->select('id', 'name');
},
Expand All @@ -121,6 +125,40 @@ public function scopePreparedWith(Builder $query): Builder
]);
}

/**
* Filter on organisations in specific locations
*/
public function scopeLocation(Builder $query, int|null $location, FilterOption $filter): Builder
{
if ($filter === FilterOption::NONE) {
if (!empty($location)) {
return $query;
}
return $query
->whereRaw('(select count(*) from organisation_location as ol where ol.organisation_id = ' .
$this->getTable() . '.id and ol.location_id = ' . ((int) $location) . ') = 0');
} elseif ($filter === FilterOption::EXCLUDE) {
return $query
->whereRaw('(select count(*) from organisation_location as ol where ol.organisation_id = ' .
$this->getTable() . '.id and ol.location_id = ' . ((int) $location) . ') = 0');
}

$ids = [$location];
if ($filter === FilterOption::CHILDREN) {
/** @var Location|null $model */
$model = Location::find($location);
if (!empty($model)) {
$ids = [...$model->descendants->pluck('id')->toArray(), $model->id];
}
}
return $query
->select($this->getTable() . '.*')
->leftJoin('organisation_location as ol', function ($join) {
$join->on('ol.organisation_id', '=', $this->getTable() . '.id');
})
->whereIn('ol.location_id', $ids)->distinct();
}

/**
* Filter for organisations with specific member
*/
Expand Down Expand Up @@ -204,6 +242,20 @@ public function location()
return $this->belongsTo('App\Models\Location', 'location_id', 'id');
}

/**
* Creatures have multiple locations
*/
public function locations()
{
return $this->belongsToMany('App\Models\Location', 'organisation_location')
->with('entity');
}

public function pivotLocations()
{
return $this->hasMany('App\Models\OrganisationLocation');
}

/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
Expand Down Expand Up @@ -281,7 +333,7 @@ public function entityTypeId(): int
*/
public function showProfileInfo(): bool
{
return !empty($this->type) || !empty($this->location) || !$this->entity->elapsedEvents->isEmpty();
return !empty($this->type) || !empty($this->location) || !$this->entity->elapsedEvents->isEmpty() || $this->locations->isNotEmpty();
}

/**
Expand Down
48 changes: 48 additions & 0 deletions app/Models/OrganisationLocation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace App\Models;

use App\Models\Concerns\Paginatable;
use Illuminate\Database\Eloquent\Relations\Pivot;

/**
* Class OrganisationLocation
* @package App\Models
*
* @property int $organisation_id
* @property int $location_id
* @property Organisation $organisation
* @property Location $location
*/
class OrganisationLocation extends Pivot
{
use Paginatable;

/**
* @var string
*/
public $table = 'organisation_location';

protected $fillable = ['organisation_id', 'location_id'];

/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function organisation()
{
return $this->belongsTo('App\Models\Organisation', 'organisation_id', 'id');
}

/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function location()
{
return $this->belongsTo('App\Models\Location', 'location_id', 'id');
}

public function exportFields(): array
{
return ['location_id'];
}
}
12 changes: 7 additions & 5 deletions app/Observers/Concerns/HasLocations.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ trait HasLocations
{
/**
*/
public function saveLocations(MiscModel|Creature $model)
public function saveLocations(MiscModel|Creature $model, array $locations = [])
{
/** @var Creature $model */
$existing = $unique = $recreate = [];
Expand All @@ -28,11 +28,13 @@ public function saveLocations(MiscModel|Creature $model)
if (!empty($recreate)) {
$model->locations()->attach($recreate);
}

$locations = request()->get('locations', []);
if (!$locations) {
$locations = request()->get('locations', []);
$detach = true;
}
$newLocations = [];
foreach ($locations as $id) {
// Existing race, do nothing
// Existing location, do nothing
if (!empty($existing[$id])) {
unset($existing[$id]);
continue;
Expand All @@ -51,7 +53,7 @@ public function saveLocations(MiscModel|Creature $model)
$model->locations()->attach($newLocations);

// Detach the remaining
if (!empty($existing)) {
if (!empty($existing) && isset($detach)) {
$model->locations()->detach($existing);
}
}
Expand Down
13 changes: 13 additions & 0 deletions app/Observers/OrganisationObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,27 @@
use App\Models\Character;
use App\Models\Organisation;
use App\Models\OrganisationMember;
use App\Observers\Concerns\HasLocations;

class OrganisationObserver extends MiscObserver
{
use HasLocations;

public function saved(Organisation $organisation)
{
$this->saveMembers($organisation);
}

/**
*/
public function crudSaved(Organisation $organisation)
{
if (!request()->has('save_locations') && !request()->has('locations')) {
return;
}
$this->saveLocations($organisation);
}

/**
*/
public function deleting(Organisation $organisation)
Expand Down
13 changes: 13 additions & 0 deletions app/Services/BulkService.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
use App\Models\MiscModel;
use Exception;
use Illuminate\Support\Str;
use App\Observers\Concerns\HasLocations;
use Stevebauman\Purify\Facades\Purify;

class BulkService
{
use CampaignAware;
use HasLocations;

protected EntityService $entityService;

Expand Down Expand Up @@ -275,6 +277,10 @@ public function editing(array $fields, Bulk $bulk): int
unset($filledFields['tags']);
$tagIds = Arr::get($fields, 'tags', []);

// Handle locations differently
unset($filledFields['locations']);
$locationIds = Arr::get($fields, 'locations', []);

// Handle images differently
if (isset($filledFields['entity_image'])) {
$imageUuid = $filledFields['entity_image'];
Expand Down Expand Up @@ -351,6 +357,13 @@ public function editing(array $fields, Bulk $bulk): int

$this->count++;

$locationsAction = Arr::get($fields, 'bulk-locations', 'add');
if ($locationsAction === 'remove') {
$entity->locations()->detach($locationIds);
} else {
$this->saveLocations($entity, $locationIds);
}

// No tags? We're done
if (empty($fields['tags'])) {
continue;
Expand Down
3 changes: 3 additions & 0 deletions app/Services/Campaign/Import/Mappers/EntityMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ protected function foreign(string $model, string $field): self

protected function pivot(string $relation, string $model, string $field): self
{
if ($relation == 'pivotLocations' && isset($this->data['location_id']) && !in_array(['location_id' => $this->data['location_id']], $this->data[$relation])) {
spitfire305 marked this conversation as resolved.
Show resolved Hide resolved
$this->data[$relation][] = ['location_id' => $this->data['location_id']];
}
foreach ($this->data[$relation] as $pivot) {
if (!ImportIdMapper::has($model, $pivot[$field])) {
continue;
Expand Down
4 changes: 2 additions & 2 deletions app/Services/Campaign/Import/Mappers/OrganisationMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class OrganisationMapper extends MiscMapper
{
protected array $ignore = ['id', 'campaign_id', 'slug', 'image', '_lft', '_rgt', 'organisation_id', 'location_id', 'created_at', 'updated_at'];
protected array $ignore = ['id', 'campaign_id', 'slug', 'image', '_lft', '_rgt', 'organisation_id', 'created_at', 'updated_at', 'location_id'];

protected string $className = Organisation::class;
protected string $mappingName = 'organisations';
Expand All @@ -22,7 +22,7 @@ public function second(): void
{
$this
->loadModel()
->foreign('locations', 'location_id')
->pivot('pivotLocations', 'locations', 'location_id')
->saveModel()
->entitySecond();
}
Expand Down
Loading