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

Granular esi scheduling for characters #684

Merged
merged 12 commits into from
Sep 5, 2024
33 changes: 33 additions & 0 deletions src/Config/web.characterfilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/*
* This file is part of SeAT
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

return [
['name' => 'scopes', 'src' => 'seatcore::fastlookup.scopes', 'path' => 'refresh_token', 'field' => 'scopes', 'label' => 'Scopes'],
['name' => 'character', 'src' => 'seatcore::fastlookup.characters', 'path' => '', 'field' => 'character_id', 'label' => 'Character'],
['name' => 'title', 'src' => 'seatcore::fastlookup.titles', 'path' => 'titles', 'field' => 'id', 'label' => 'Title'],
['name' => 'corporation', 'src' => 'seatcore::fastlookup.corporations', 'path' => 'affiliation', 'field' => 'corporation_id', 'label' => 'Corporation'],
['name' => 'alliance', 'src' => 'seatcore::fastlookup.alliances', 'path' => 'affiliation', 'field' => 'alliance_id', 'label' => 'Alliance'],
['name' => 'skill', 'src' => 'seatcore::fastlookup.skills', 'path' => 'skills', 'field' => 'skill_id', 'label' => 'Skill'],
['name' => 'skill_level', 'src' => [['id' => 1, 'text' => 'Level 1'], ['id' => 2, 'text' => 'Level 2'], ['id' => 3, 'text' => 'Level 3'], ['id' => 4, 'text' => 'Level 4'], ['id' => 5, 'text' => 'Level 5']], 'path' => 'skills', 'field' => 'trained_skill_level', 'label' => 'Skill Level'],
['name' => 'type', 'src' => 'seatcore::fastlookup.items', 'path' => 'assets', 'field' => 'type_id', 'label' => 'Item'],
['name' => 'role', 'src' => 'seatcore::fastlookup.roles', 'path' => 'corporation_roles', 'field' => 'role', 'label' => 'Role'],
];
45 changes: 45 additions & 0 deletions src/Events/CharacterFilterDataUpdate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of SeAT
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

namespace Seat\Web\Events;

use Illuminate\Queue\SerializesModels;
use Seat\Eveapi\Models\Character\CharacterInfo;
use Seat\Web\Models\User;

/**
* This event is fired when character filters, like used in squads, need to recompute because the data they are based on changed.
*/
class CharacterFilterDataUpdate
{
use SerializesModels;

public CharacterInfo $character;

/**
* @param User $user
*/
public function __construct(CharacterInfo $character)
{
$this->character = $character;
}
}
45 changes: 45 additions & 0 deletions src/Http/Composers/CharacterFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of SeAT
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

namespace Seat\Web\Http\Composers;

use Illuminate\View\View;

class CharacterFilter
{
public function compose(View $view)
{
$rules = config('web.characterfilter');

// work with raw arrays since the filter code requires an array of objects, and laravel collections don't like to give us that
$newrules = [];
foreach ($rules as $rule) {
// convert route names to urls, but keep arrays with hardcoded options
if(is_string($rule['src'])){
$rule['src'] = route($rule['src']);
}
$newrules[] = (object) $rule;
}

$view->with('characterFilterRules', $newrules);
}
}
59 changes: 57 additions & 2 deletions src/Http/Controllers/Configuration/ScheduleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
namespace Seat\Web\Http\Controllers\Configuration;

use Artisan;
use Illuminate\Http\Request;
use Seat\Eveapi\Models\RefreshToken;
use Seat\Services\Models\Schedule;
use Seat\Web\Http\Controllers\Controller;
use Seat\Web\Http\Validation\NewSchedule;
use Seat\Web\Models\CharacterSchedulingRule;

/**
* Class ScheduleController.
Expand All @@ -52,11 +55,12 @@ public function listSchedule()
'every five minutes' => '*/5 * * * *',
'every ten minutes' => '*/10 * * * *',
'every thirty minutes' => '*/30 * * * *',

];

$scheduling_rules = CharacterSchedulingRule::all();

return view('web::configuration.schedule.view',
compact('schedule', 'commands', 'expressions'));
compact('schedule', 'commands', 'expressions', 'scheduling_rules'));
}

/**
Expand Down Expand Up @@ -85,4 +89,55 @@ public function deleteSchedule(int $schedule_id)
return redirect()->back()
->with('success', 'Schedule entry deleted!');
}

public function createSchedulingRule(Request $request)
{
$request->validate([
'filters' => 'required|json',
'name' => 'required|string',
'time' => 'required|numeric',
'timeunit' => 'required|in:hour,day,week',
]);

// $time_modifier: conversion factor from timeunit to seconds
if($request->timeunit === 'hour') {
$time_modifier = 60 * 60;
} elseif ($request->timeunit === 'day') {
$time_modifier = 60 * 60 * 24;
} elseif ($request->timeunit === 'week') {
$time_modifier = 60 * 60 * 24 * 7;
}
$time = $request->time * $time_modifier;

$rule = CharacterSchedulingRule::where('name', $request->name)->first();
if($rule === null) {
$rule = new CharacterSchedulingRule();
$rule->name = $request->name;
}
$rule->interval = $time;
$rule->filter = $request->filters;
$rule->save();

RefreshToken::all()->each(function ($token) {
CharacterSchedulingRule::updateRefreshTokenSchedule($token);
});

return redirect()->back()
->with('success', 'Character Scheduling Rule added!');
}

public function deleteSchedulingRule(Request $request)
{
$request->validate([
'rule_id' => 'required|numeric',
]);

CharacterSchedulingRule::destroy($request->rule_id);

RefreshToken::all()->each(function ($token) {
CharacterSchedulingRule::updateRefreshTokenSchedule($token);
});

return redirect()->back()->with('success', 'Successfully removed character scheduling rule!');
}
}
8 changes: 8 additions & 0 deletions src/Http/Routes/Configuration/Schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@
Route::get('/delete/{schedule_id}')
->name('seatcore::configuration.schedule.delete')
->uses('ScheduleController@deleteSchedule');

Route::post('/rules/create')
->name('seatcore::configuration.schedule.rule.create')
->uses('ScheduleController@createSchedulingRule');

Route::post('/rules/delete')
->name('seatcore::configuration.schedule.rule.delete')
->uses('ScheduleController@deleteSchedulingRule');
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

namespace Seat\Web\Observers;
namespace Seat\Web\Listeners;

use Illuminate\Database\Eloquent\Model;
use Seat\Web\Exceptions\InvalidFilterException;
use Seat\Web\Events\CharacterFilterDataUpdate;
use Seat\Web\Models\Squads\Squad;
use Seat\Web\Models\User;

/**
* Class AbstractSquadObserver.
*
* @package Seat\Web\Observers
*/
abstract class AbstractSquadObserver
class CharacterFilterDataUpdatedSquads
{
/**
* Return the User owning the model which fired the catch event.
*
* @param \Illuminate\Database\Eloquent\Model $fired_model The model which fired the catch event
* @return \Seat\Web\Models\User|null The user owning this model
*/
abstract protected function findRelatedUser(Model $fired_model): ?User;

/**
* Update squads to which the user owning model firing the event is member.
*
* @param \Illuminate\Database\Eloquent\Model $fired_model The model which fired the catch event
*
* @throws InvalidFilterException
*/
protected function updateUserSquads(Model $fired_model)
public static function handle(CharacterFilterDataUpdate $event)
{
$user = $this->findRelatedUser($fired_model);

if (! $user)
return;
$user = $event->character->user;

$member_squads = $user->squads;

Expand Down
34 changes: 34 additions & 0 deletions src/Listeners/CharacterFilterDataUpdatedTokens.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/*
* This file is part of SeAT
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

namespace Seat\Web\Listeners;

use Seat\Web\Events\CharacterFilterDataUpdate;
use Seat\Web\Models\CharacterSchedulingRule;

class CharacterFilterDataUpdatedTokens
{
public static function handle(CharacterFilterDataUpdate $update)
{
CharacterSchedulingRule::updateRefreshTokenSchedule($update->character->refresh_token);
}
}
93 changes: 93 additions & 0 deletions src/Models/CharacterSchedulingRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

/*
* This file is part of SeAT
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

namespace Seat\Web\Models;

use Seat\Eveapi\Models\Character\CharacterInfo;
use Seat\Eveapi\Models\RefreshToken;
use Seat\Eveapi\Models\RefreshTokenSchedule;
use Seat\Services\Models\ExtensibleModel;
use stdClass;

/**
* @property int $id
* @property string name
* @property string filter
* @property int interval
*/
class CharacterSchedulingRule extends ExtensibleModel
{
use Filterable;

/**
* @var bool
*/
public $timestamps = false;

/**
* The filters to use.
*
* @return \stdClass
*/
public function getFilters(): stdClass
{
return json_decode($this->filter);
}

/**
* Recomputes the update interval of a character and saves it in the refresh_token_schedules table.
*
* @param RefreshToken $token
* @return void
*/
public static function updateRefreshTokenSchedule(RefreshToken $token): void
{
$schedule = $token->token_schedule;

if($schedule === null) {
$schedule = new RefreshTokenSchedule();
$schedule->character_id = $token->character_id;
}

$schedule->update_interval = self::getCharacterSchedulingInterval($token->character);
$schedule->save();
}

/**
* Computes the scheduling interval from the character scheduling rules for a character.
*
* @param CharacterInfo $character
* @return int
*/
private static function getCharacterSchedulingInterval(CharacterInfo $character): int
{
$scheduling_rules = CharacterSchedulingRule::orderBy('interval', 'asc')->get();

foreach ($scheduling_rules as $rule) {
if($rule->isEligible($character)) {
return $rule->interval;
}
}

return 60 * 60; // 1 hour
}
}
Loading
Loading