@@ -14,7 +14,7 @@
|
||||
"node": true,
|
||||
|
||||
// Allow ES6.
|
||||
"esversion": 6,
|
||||
"esversion": 7,
|
||||
|
||||
/*
|
||||
* ENFORCING OPTIONS
|
||||
|
||||
@@ -18,7 +18,8 @@ Mapping tool for [*EVE ONLINE*](https://www.eveonline.com)
|
||||
- [wiki](https://github.com/exodus4d/pathfinder/wiki)
|
||||
- Developer [Slack](https://slack.com) chat:
|
||||
- https://pathfinder-eve-online.slack.com
|
||||
- Please send me a mail for invite: pathfinder@exodus4d.de
|
||||
- Join channel [pathfinder-eve-online.slack.com](https://join.slack.com/t/pathfinder-eve-online/shared_invite/enQtMzMyOTkyMjczMTA3LWI2NGE1OTY5ODBmNDZlMDY3MDIzYjk5ZTljM2JjZjIwNDRkNzMyMTEwMDUzOGQwM2E3ZjE1NGEwNThlMzYzY2Y)
|
||||
- Can´t join? pathfinder@exodus4d.de
|
||||
|
||||
**Feel free to check the code for bugs and security issues.
|
||||
Issues should be reported in the [Issue](https://github.com/exodus4d/pathfinder/issues) section.**
|
||||
@@ -49,7 +50,7 @@ Issues should be reported in the [Issue](https://github.com/exodus4d/pathfinder/
|
||||
|-- app.js --> require.js config (!required for production!)
|
||||
|-- [0777] logs/ --> log files
|
||||
|-- ...
|
||||
| -- node_modules/ --> node.js modules (not used for production)
|
||||
|-- node_modules/ --> node.js modules (not used for production)
|
||||
|-- ...
|
||||
|-- [0755] public/ --> frontend source
|
||||
|-- css/ --> CSS dist/build folder (minified)
|
||||
|
||||
@@ -59,8 +59,13 @@ deleteStatisticsData = Cron\StatisticsUpdate->deleteStatisticsD
|
||||
; truncate map history log files
|
||||
truncateMapHistoryLogFiles = Cron\MapHistory->truncateFiles, @halfHour
|
||||
|
||||
; updates small amount of static system data from CCP API
|
||||
; sync "sovereignty" and "faction warfare" data from CCP´s ESI API
|
||||
updateSovereigntyData = Cron\Universe->updateSovereigntyData, @halfPastHour
|
||||
|
||||
; sync static system data from CCP´s ESI API
|
||||
; -> Job is WIP!
|
||||
;updateUniverseSystems = Cron\Universe->updateUniverseSystems, @instant
|
||||
|
||||
; setup universe DB with static data from ESI
|
||||
; bootstrap job for "eve_universe" DB from CCP´s ESI API
|
||||
; -> Only for development! This job is used to build the initial export/sql/eve_universe.sql
|
||||
;setup = Cron\Universe->setup, @instant
|
||||
@@ -213,7 +213,7 @@ class Cortex extends Cursor {
|
||||
} else
|
||||
$this->whitelist=$fields;
|
||||
$id=$this->dbsType=='sql'?$this->primary:'_id';
|
||||
if (!in_array($id,$this->whitelist))
|
||||
if (!in_array($id,$this->whitelist) && !($exclude && in_array($id,$fields)))
|
||||
$this->whitelist[]=$id;
|
||||
$this->applyWhitelist();
|
||||
return $this->whitelist;
|
||||
@@ -595,7 +595,7 @@ class Cortex extends Cursor {
|
||||
* @param array|null $filter
|
||||
* @param array|null $options
|
||||
* @param int $ttl
|
||||
* @return CortexCollection
|
||||
* @return CortexCollection|false
|
||||
*/
|
||||
public function find($filter = NULL, array $options = NULL, $ttl = 0) {
|
||||
$sort=false;
|
||||
@@ -731,12 +731,12 @@ class Cortex extends Cursor {
|
||||
$addToFilter = array($id.' IN ?', $result);
|
||||
}
|
||||
// *-to-one
|
||||
elseif ($this->dbsType == 'sql') {
|
||||
elseif (!$deep && $this->dbsType == 'sql') {
|
||||
// use sub-query inclusion
|
||||
$has_filter=$this->mergeFilter([$has_filter,
|
||||
[$this->rel($key)->getTable().'.'.$fromConf[1].'='.$this->getTable().'.'.$id]]);
|
||||
$result = $this->_refSubQuery($key,$has_filter,$has_options);
|
||||
$addToFilter = ['exists('.$result[0].')']+$result[1];
|
||||
$addToFilter = array_merge(['exists('.$result[0].')'],$result[1]);
|
||||
}
|
||||
elseif ($result = $this->_hasRefsIn($key,$has_filter,$has_options,$ttl))
|
||||
$addToFilter = array($id.' IN ?', $result);
|
||||
@@ -781,11 +781,11 @@ class Cortex extends Cursor {
|
||||
$options['order'] = preg_replace('/\h+DESC(?=\s*(?:$|,))/i',' DESC NULLS LAST',$options['order']);
|
||||
// assemble full sql query for joined queries
|
||||
if ($hasJoin) {
|
||||
$adhoc=[];
|
||||
// when in count-mode and grouping is active, wrap the query later
|
||||
// otherwise add a an adhoc counter field here
|
||||
if (!($subquery_mode=($options && !empty($options['group']))) && $count)
|
||||
$this->adhoc['_rows']=['expr'=>'COUNT(*)','value'=>NULL];
|
||||
$adhoc=[];
|
||||
$adhoc[]='(COUNT(*)) as _rows';
|
||||
if (!$count)
|
||||
// add bind parameters for filters in adhoc fields
|
||||
if ($this->preBinds) {
|
||||
@@ -1224,7 +1224,7 @@ class Cortex extends Cursor {
|
||||
// m:m save cascade
|
||||
if (!empty($this->saveCsd)) {
|
||||
foreach($this->saveCsd as $key => $val) {
|
||||
if($fields[$key]['relType'] == 'has-many') {
|
||||
if ($fields[$key]['relType'] == 'has-many') {
|
||||
$relConf = $fields[$key]['has-many'];
|
||||
if ($relConf['hasRel'] == 'has-many') {
|
||||
$mmTable = $this->mmTable($relConf,$key);
|
||||
@@ -1236,12 +1236,12 @@ class Cortex extends Cursor {
|
||||
$filter[] = $id;
|
||||
}
|
||||
// delete all refs
|
||||
if (is_null($val))
|
||||
if (empty($val))
|
||||
$mm->erase($filter);
|
||||
// update refs
|
||||
elseif (is_array($val)) {
|
||||
$mm->erase($filter);
|
||||
foreach($val as $v) {
|
||||
foreach(array_unique($val) as $v) {
|
||||
if ($relConf['isSelf'] && $v==$id)
|
||||
continue;
|
||||
$mm->set($key,$v);
|
||||
@@ -1256,7 +1256,7 @@ class Cortex extends Cursor {
|
||||
$rel = $this->getRelInstance($relConf[0],$relConf,$key);
|
||||
// find existing relations
|
||||
$refs = $rel->find([$relConf[1].' = ?',$this->getRaw($relConf['relField'])]);
|
||||
if (is_null($val)) {
|
||||
if (empty($val)) {
|
||||
foreach ($refs?:[] as $model) {
|
||||
$model->set($relConf[1],NULL);
|
||||
$model->save();
|
||||
@@ -1470,7 +1470,7 @@ class Cortex extends Cursor {
|
||||
// handle relations
|
||||
if (isset($fields[$key]['belongs-to-one'])) {
|
||||
// one-to-many, one-to-one
|
||||
if (is_null($val))
|
||||
if (empty($val))
|
||||
$val = NULL;
|
||||
elseif (is_object($val) &&
|
||||
!($this->dbsType=='mongo' && (
|
||||
@@ -1489,7 +1489,7 @@ class Cortex extends Cursor {
|
||||
$val = $this->db->legacy() ? new \MongoId($val) : new \MongoDB\BSON\ObjectId($val);
|
||||
} elseif (isset($fields[$key]['has-one'])){
|
||||
$relConf = $fields[$key]['has-one'];
|
||||
if (is_null($val)) {
|
||||
if (empty($val)) {
|
||||
$val = $this->get($key);
|
||||
$val->set($relConf[1],NULL);
|
||||
} else {
|
||||
@@ -2554,7 +2554,7 @@ class CortexQueryParser extends \Prefab {
|
||||
function($match) use($db) {
|
||||
if (!isset($match[1]))
|
||||
return $match[0];
|
||||
if (preg_match('/\b(AND|OR|IN|LIKE|NOT)\b/i',$match[1]))
|
||||
if (preg_match('/\b(AND|OR|IN|LIKE|NOT|HAVING|SELECT|FROM|WHERE)\b/i',$match[1]))
|
||||
return $match[1];
|
||||
return $db->quotekey($match[1]);
|
||||
}, $cond);
|
||||
@@ -2576,7 +2576,7 @@ class CortexQueryParser extends \Prefab {
|
||||
function($match) use($table) {
|
||||
if (!isset($match[3]))
|
||||
return $match[1];
|
||||
if (preg_match('/\b(AND|OR|IN|LIKE|NOT)\b/i',$match[3]))
|
||||
if (preg_match('/\b(AND|OR|IN|LIKE|NOT|HAVING|SELECT|FROM|WHERE)\b/i',$match[3]))
|
||||
return $match[0];
|
||||
return $match[2].$table.'.'.$match[3];
|
||||
}, $cond);
|
||||
|
||||
@@ -36,14 +36,15 @@ class AccessController extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* get current character and check if it is a valid character
|
||||
* check login status and look or a valid character
|
||||
* @param \Base $f3
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function isLoggedIn(\Base $f3) : string {
|
||||
$loginStatus = 'UNKNOWN';
|
||||
if($character = $this->getCharacter()){
|
||||
// disable ttl cache time here. Further getCharacter() calls should use a short ttl
|
||||
if($character = $this->getCharacter(0)){
|
||||
if($character->checkLoginTimer()){
|
||||
if(( $authStatus = $character->isAuthorized()) === 'OK'){
|
||||
$loginStatus = 'OK';
|
||||
|
||||
@@ -89,7 +89,7 @@ class Admin extends Controller{
|
||||
protected function getAdminCharacter(\Base $f3){
|
||||
$adminCharacter = null;
|
||||
if( !$f3->exists(Sso::SESSION_KEY_SSO_ERROR) ){
|
||||
if( $character = $this->getCharacter() ){
|
||||
if( $character = $this->getCharacter(0) ){
|
||||
if(in_array($character->roleId->name, ['SUPER', 'CORPORATION'], true)){
|
||||
// current character is admin
|
||||
$adminCharacter = $character;
|
||||
@@ -288,7 +288,7 @@ class Admin extends Controller{
|
||||
$characters = [];
|
||||
// check if kickCharacters belong to same Corp as admin character
|
||||
// -> remove admin char from valid characters...
|
||||
if( !empty($characterIds = array_diff( [$characterId], [$character->_id])) ){
|
||||
if( !empty($characterIds = array_diff([$characterId], [$character->_id])) ){
|
||||
if($character->roleId->name === 'SUPER'){
|
||||
if($filterCharacters = CharacterModel::getAll($characterIds)){
|
||||
$characters = $filterCharacters;
|
||||
@@ -337,7 +337,7 @@ class Admin extends Controller{
|
||||
$maps = $filterMaps;
|
||||
}
|
||||
}else{
|
||||
$maps = $character->getCorporation()->getMaps([$mapId], ['addInactive' => true, 'ignoreMapCount' => true]);
|
||||
$maps = $character->getCorporation()->getMaps($mapId, ['addInactive' => true, 'ignoreMapCount' => true]);
|
||||
}
|
||||
|
||||
return $maps;
|
||||
@@ -404,7 +404,7 @@ class Admin extends Controller{
|
||||
$corporations = $this->getAccessibleCorporations($character);
|
||||
|
||||
foreach($corporations as $corporation){
|
||||
if($maps = $corporation->getMaps([], ['addInactive' => true, 'ignoreMapCount' => true])){
|
||||
if($maps = $corporation->getMaps(null, ['addInactive' => true, 'ignoreMapCount' => true])){
|
||||
$data->corpMaps[$corporation->name] = $maps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,10 @@ class Map extends Controller\AccessController {
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initData(\Base $f3){
|
||||
// expire time in seconds
|
||||
$expireTimeCache = 60 * 60;
|
||||
|
||||
if(!$f3->exists(self::CACHE_KEY_INIT, $return)){
|
||||
// response should not be cached if invalid -> e.g. missing static data
|
||||
$validInitData = true;
|
||||
$validInitData = true;
|
||||
$ttl = 60 * 60;
|
||||
|
||||
if(!$exists = $f3->exists(self::CACHE_KEY_INIT, $return)){
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
|
||||
@@ -179,7 +176,10 @@ class Map extends Controller\AccessController {
|
||||
// get third party APIs -----------------------------------------------------------------------------------
|
||||
$return->url = [
|
||||
'ccpImageServer' => Config::getPathfinderData('api.ccp_image_server'),
|
||||
'zKillboard' => Config::getPathfinderData('api.z_killboard')
|
||||
'zKillboard' => Config::getPathfinderData('api.z_killboard'),
|
||||
'eveeye' => Config::getPathfinderData('api.eveeye'),
|
||||
'dotlan' => Config::getPathfinderData('api.dotlan'),
|
||||
'anoik' => Config::getPathfinderData('api.anoik')
|
||||
];
|
||||
|
||||
// Character default config -------------------------------------------------------------------------------
|
||||
@@ -199,29 +199,33 @@ class Map extends Controller\AccessController {
|
||||
|
||||
// structure status ---------------------------------------------------------------------------------------
|
||||
$structureStatus = Pathfinder\StructureStatusModel::getAll();
|
||||
$structureData = [];
|
||||
$structureStatusData = [];
|
||||
foreach($structureStatus as $status){
|
||||
$structureData[$status->_id] = $status->getData();
|
||||
$structureStatusData[$status->_id] = $status->getData();
|
||||
}
|
||||
$return->structureStatus = $structureData;
|
||||
$return->structureStatus = $structureStatusData;
|
||||
|
||||
$validInitData = $validInitData ? !empty($structureData) : $validInitData;
|
||||
$validInitData = $validInitData ? !empty($structureStatusData) : $validInitData;
|
||||
|
||||
// get available wormhole types ---------------------------------------------------------------------------
|
||||
/**
|
||||
* @var $wormhole Universe\WormholeModel
|
||||
* @var $groupUniverseModel Universe\GroupModel
|
||||
*/
|
||||
$wormhole = Universe\AbstractUniverseModel::getNew('WormholeModel');
|
||||
$groupUniverseModel = Universe\AbstractUniverseModel::getNew('GroupModel');
|
||||
$groupUniverseModel->getById(Config::ESI_GROUP_WORMHOLE_ID);
|
||||
$wormholesData = [];
|
||||
if($rows = $wormhole->find(null, ['order' => 'name asc'])){
|
||||
foreach($rows as $rowData){
|
||||
$wormholesData[$rowData->name] = $rowData->getData();
|
||||
/**
|
||||
* @var $typeModel Universe\TypeModel
|
||||
*/
|
||||
foreach($types = $groupUniverseModel->getTypes(false) as $typeModel){
|
||||
if(
|
||||
($wormholeData = $typeModel->getWormholeData()) &&
|
||||
mb_strlen((string)$wormholeData->name) === 4
|
||||
){
|
||||
$wormholesData[$wormholeData->name] = $wormholeData;
|
||||
}
|
||||
|
||||
$wormhole->reset();
|
||||
$wormhole->name = 'K162';
|
||||
$wormholesData[$wormhole->name] = $wormhole->getData();
|
||||
}
|
||||
ksort($wormholesData);
|
||||
$return->wormholes = $wormholesData;
|
||||
|
||||
$validInitData = $validInitData ? !empty($wormholesData) : $validInitData;
|
||||
@@ -231,20 +235,20 @@ class Map extends Controller\AccessController {
|
||||
* @var $categoryUniverseModel Universe\CategoryModel
|
||||
*/
|
||||
$categoryUniverseModel = Universe\AbstractUniverseModel::getNew('CategoryModel');
|
||||
$categoryUniverseModel->getById(6);
|
||||
$shipData = $categoryUniverseModel->getData(['mass']);
|
||||
$categoryUniverseModel->getById(65);
|
||||
$structureData = $categoryUniverseModel->getData();
|
||||
|
||||
$return->universeCategories = [
|
||||
6 => $shipData,
|
||||
65 => $structureData
|
||||
Config::ESI_CATEGORY_SHIP_ID =>
|
||||
($categoryUniverseModel->getById(Config::ESI_CATEGORY_SHIP_ID) && $categoryUniverseModel->valid()) ? $categoryUniverseModel->getData(['mass']) : null,
|
||||
Config::ESI_CATEGORY_STRUCTURE_ID =>
|
||||
($categoryUniverseModel->getById(Config::ESI_CATEGORY_STRUCTURE_ID) && $categoryUniverseModel->valid()) ? $categoryUniverseModel->getData() : null,
|
||||
];
|
||||
|
||||
$validInitData = $validInitData ? !empty($return->universeCategories[65]) : $validInitData;
|
||||
$validInitData = $validInitData ? !count(array_filter($return->universeCategories, function($v){
|
||||
return empty(array_filter((array)$v->groups));
|
||||
})) : $validInitData;
|
||||
|
||||
// response should not be cached if invalid -> e.g. missing static data
|
||||
if($validInitData){
|
||||
$f3->set(self::CACHE_KEY_INIT, $return, $expireTimeCache );
|
||||
$f3->set(self::CACHE_KEY_INIT, $return, $ttl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,6 +261,9 @@ class Map extends Controller\AccessController {
|
||||
$ssoError->message = $message;
|
||||
$return->error[] = $ssoError;
|
||||
$f3->clear(Controller\Ccp\Sso::SESSION_KEY_SSO_ERROR);
|
||||
}elseif($validInitData){
|
||||
// no errors and valid data -> send Cache header
|
||||
$f3->expire(Config::ttlLeft($exists, $ttl));
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
@@ -871,6 +878,7 @@ class Map extends Controller\AccessController {
|
||||
$getMapUserData = (bool)$postData['getMapUserData'];
|
||||
$mapTracking = (bool)$postData['mapTracking'];
|
||||
$systemData = (array)$postData['systemData'];
|
||||
$newSystemPositions = (array)$postData['newSystemPositions'];
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$return = (object)[];
|
||||
@@ -886,7 +894,7 @@ class Map extends Controller\AccessController {
|
||||
if( !is_null($map = $activeCharacter->getMap($mapId)) ){
|
||||
// check character log (current system) and manipulate map (e.g. add new system)
|
||||
if($mapTracking){
|
||||
$map = $this->updateMapByCharacter($map, $activeCharacter);
|
||||
$map = $this->updateMapByCharacter($map, $activeCharacter, $newSystemPositions);
|
||||
}
|
||||
|
||||
// mapUserData ----------------------------------------------------------------------------------------
|
||||
@@ -906,14 +914,13 @@ class Map extends Controller\AccessController {
|
||||
// systemData -----------------------------------------------------------------------------------------
|
||||
if(
|
||||
$mapId === (int)$systemData['mapId'] &&
|
||||
!is_null($system = $map->getSystemById((int)$systemData['systemData']['id']))
|
||||
!is_null($system = $map->getSystemById((int)$systemData['id']))
|
||||
){
|
||||
// data for currently selected system
|
||||
$return->system = $system->getData();
|
||||
$return->system->signatures = $system->getSignaturesData();
|
||||
$return->system->sigHistory = $system->getSignaturesHistory();
|
||||
$return->system->structures = $system->getStructuresData();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -932,10 +939,11 @@ class Map extends Controller\AccessController {
|
||||
* update map connections/systems based on $character´s location logs
|
||||
* @param Pathfinder\MapModel $map
|
||||
* @param Pathfinder\CharacterModel $character
|
||||
* @param array $newSystemPositions
|
||||
* @return Pathfinder\MapModel
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function updateMapByCharacter(Pathfinder\MapModel $map, Pathfinder\CharacterModel $character) : Pathfinder\MapModel {
|
||||
protected function updateMapByCharacter(Pathfinder\MapModel $map, Pathfinder\CharacterModel $character, array $newSystemPositions = []) : Pathfinder\MapModel {
|
||||
// map changed. update cache (system/connection) changed
|
||||
$mapDataChanged = false;
|
||||
|
||||
@@ -952,6 +960,9 @@ class Map extends Controller\AccessController {
|
||||
$sourceSystemId = (int)$sourceLog->systemId;
|
||||
|
||||
if($sourceSystemId){
|
||||
$defaultPositions = (array)$newSystemPositions['defaults'];
|
||||
$currentPosition = (array)$newSystemPositions['location'];
|
||||
|
||||
$sourceSystem = null;
|
||||
$targetSystem = null;
|
||||
|
||||
@@ -963,8 +974,8 @@ class Map extends Controller\AccessController {
|
||||
// system coordinates for system tha might be added next
|
||||
$systemOffsetX = 130;
|
||||
$systemOffsetY = 0;
|
||||
$systemPosX = 0;
|
||||
$systemPosY = 30;
|
||||
$systemPosX = ((int)$defaultPositions[0]['x']) ? : 0;
|
||||
$systemPosY = ((int)$defaultPositions[0]['y']) ? : 30;
|
||||
|
||||
// check if previous (solo) system is already on the map ----------------------------------------------
|
||||
$sourceSystem = $map->getSystemByCCPId($sourceSystemId, [AbstractModel::getFilter('active', true)]);
|
||||
@@ -972,12 +983,10 @@ class Map extends Controller\AccessController {
|
||||
// if systems don´t already exists on map -> get "blank" system
|
||||
// -> required for system type check (e.g. wormhole, k-space)
|
||||
if($sourceSystem){
|
||||
// system exists
|
||||
$sourceExists = true;
|
||||
|
||||
// system exists -> add target to the "right"
|
||||
$systemPosX = $sourceSystem->posX + $systemOffsetX;
|
||||
$systemPosY = $sourceSystem->posY + $systemOffsetY;
|
||||
}else{
|
||||
// system not exists -> get"blank" system
|
||||
$sourceSystem = $map->getNewSystem($sourceSystemId);
|
||||
}
|
||||
|
||||
@@ -992,6 +1001,11 @@ class Map extends Controller\AccessController {
|
||||
|
||||
if($targetSystem){
|
||||
$targetExists = true;
|
||||
|
||||
if($targetSystemId === (int)$currentPosition['systemId']){
|
||||
$systemPosX = (int)$currentPosition['position']['x'];
|
||||
$systemPosY = (int)$currentPosition['position']['y'];
|
||||
}
|
||||
}else{
|
||||
$targetSystem = $map->getNewSystem($targetSystemId);
|
||||
}
|
||||
@@ -1062,6 +1076,24 @@ class Map extends Controller\AccessController {
|
||||
break;
|
||||
}
|
||||
|
||||
// check for "abyss" systems =====================================================================
|
||||
if(!$map->trackAbyssalJumps){
|
||||
if(
|
||||
$sourceSystem->isAbyss() ||
|
||||
$targetSystem->isAbyss()
|
||||
){
|
||||
$addConnection = false;
|
||||
|
||||
if($sourceSystem->isAbyss()){
|
||||
$addSourceSystem = false;
|
||||
}
|
||||
|
||||
if($targetSystem->isAbyss()){
|
||||
$addTargetSystem = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save source system =============================================================================
|
||||
if(
|
||||
$addSourceSystem &&
|
||||
@@ -1074,9 +1106,15 @@ class Map extends Controller\AccessController {
|
||||
$map = $sourceSystem->mapId;
|
||||
$sourceExists = true;
|
||||
$mapDataChanged = true;
|
||||
// increase system position (prevent overlapping)
|
||||
$systemPosX = $sourceSystem->posX + $systemOffsetX;
|
||||
$systemPosY = $sourceSystem->posY + $systemOffsetY;
|
||||
|
||||
if(!empty($defaultPositions[1])){
|
||||
$systemPosX = (int)$defaultPositions[1]['x'];
|
||||
$systemPosY = (int)$defaultPositions[1]['y'];
|
||||
}else{
|
||||
// increase system position (prevent overlapping)
|
||||
$systemPosX = $sourceSystem->posX + $systemOffsetX;
|
||||
$systemPosY = $sourceSystem->posY + $systemOffsetY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class Signature extends AbstractRestController {
|
||||
$data['groupId'] == 5 ||
|
||||
$data['typeId'] == 0
|
||||
){
|
||||
unset( $data['typeId'] );
|
||||
unset($data['typeId']);
|
||||
}
|
||||
|
||||
// "sig reader" should not overwrite signature group information
|
||||
@@ -65,6 +65,7 @@ class Signature extends AbstractRestController {
|
||||
$signature->groupId > 0
|
||||
){
|
||||
unset($data['groupId']);
|
||||
unset($data['typeId']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,13 +79,20 @@ class Signature extends AbstractRestController {
|
||||
|
||||
// delete "old" signatures ----------------------------------------------------------------------------
|
||||
if((bool)$requestData['deleteOld']){
|
||||
// if linked ConnectionModels should be deleted as well
|
||||
$deleteConnectionId = (bool)$requestData['deleteConnection'];
|
||||
|
||||
$updatedSignatureIds = array_column($signaturesData, 'id');
|
||||
$signatures = $system->getSignatures();
|
||||
foreach($signatures as $signature){
|
||||
if(!in_array($signature->_id, $updatedSignatureIds)){
|
||||
// set if potential linked ConnectionModel should be deleted as well
|
||||
$signature->virtual('connectionIdDeleteCascade', $deleteConnectionId);
|
||||
if($signature->delete()){
|
||||
$updateSignaturesHistory = true;
|
||||
}
|
||||
// clear temp virtual field as well
|
||||
$signature->clearVirtual('connectionIdDeleteCascade');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,6 +198,9 @@ class Signature extends AbstractRestController {
|
||||
$system->getById($systemId);
|
||||
|
||||
if($system->hasAccess($activeCharacter)){
|
||||
// if linked ConnectionModels should be deleted as well
|
||||
$deleteConnectionId = (bool)$requestData['deleteConnection'];
|
||||
|
||||
// if there is any changed/deleted/updated signature
|
||||
// -> we need to update signature history data for the system
|
||||
$updateSignaturesHistory = false;
|
||||
@@ -202,11 +213,15 @@ class Signature extends AbstractRestController {
|
||||
$signature->getById($signatureId);
|
||||
// make sure signature belongs to main system (user has access)
|
||||
if($signature->get('systemId', true) == $systemId){
|
||||
// set if potential linked ConnectionModel should be deleted as well
|
||||
$signature->virtual('connectionIdDeleteCascade', $deleteConnectionId);
|
||||
if($signature->delete()){
|
||||
$deletedSignatureIds[] = $signatureId;
|
||||
$updateSignaturesHistory = true;
|
||||
}
|
||||
$signature->reset();
|
||||
// clear temp virtual field as well
|
||||
$signature->clearVirtual('connectionIdDeleteCascade');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class System extends AbstractRestController {
|
||||
$systemData->signatures = $system->getSignaturesData();
|
||||
$systemData->sigHistory = $system->getSignaturesHistory();
|
||||
$systemData->structures = $system->getStructuresData();
|
||||
$systemData->stations = $system->getStationsData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,14 +91,16 @@ class Route extends Controller\AccessController {
|
||||
* -> this data is equal for EACH route search (does not depend on map data)
|
||||
*/
|
||||
private function setStaticJumpData(){
|
||||
$query = "SELECT * FROM system_neighbour";
|
||||
$rows = $this->getDB()->exec($query, null, $this->staticJumpDataCacheTime);
|
||||
if($universeDB = $this->getDB('UNIVERSE')){
|
||||
$query = "SELECT * FROM system_neighbour";
|
||||
$rows = $universeDB->exec($query, null, $this->staticJumpDataCacheTime);
|
||||
|
||||
if(count($rows) > 0){
|
||||
array_walk($rows, function(&$row){
|
||||
$row['jumpNodes'] = array_map('intval', explode(':', $row['jumpNodes']));
|
||||
});
|
||||
$this->updateJumpData($rows);
|
||||
if(count($rows) > 0){
|
||||
array_walk($rows, function(&$row){
|
||||
$row['jumpNodes'] = array_map('intval', explode(':', $row['jumpNodes']));
|
||||
});
|
||||
$this->updateJumpData($rows);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
namespace Controller\Api;
|
||||
|
||||
use Controller;
|
||||
use lib\Config;
|
||||
use Model;
|
||||
|
||||
class Setup extends Controller\Controller {
|
||||
@@ -23,6 +24,7 @@ class Setup extends Controller\Controller {
|
||||
public function buildIndex(\Base $f3){
|
||||
$postData = (array)$f3->get('POST');
|
||||
$type = (string)$postData['type'];
|
||||
$countAll = (int)$postData['countAll'];
|
||||
$count = (int)$postData['count'];
|
||||
$offset = (int)$postData['offset'];
|
||||
|
||||
@@ -31,7 +33,7 @@ class Setup extends Controller\Controller {
|
||||
$return->type = $type;
|
||||
$return->count = $count;
|
||||
$return->offset = $offset;
|
||||
$return->countAll = 0;
|
||||
$return->countAll = $countAll;
|
||||
$return->countBuild = 0;
|
||||
$return->countBuildAll = 0;
|
||||
$return->progress = 0;
|
||||
@@ -42,7 +44,7 @@ class Setup extends Controller\Controller {
|
||||
* @param int $value
|
||||
* @return int
|
||||
*/
|
||||
$sum = function(int $carry, int $value){
|
||||
$sum = function(int $carry, int $value) : int {
|
||||
$carry += $value;
|
||||
return $carry;
|
||||
};
|
||||
@@ -62,49 +64,72 @@ class Setup extends Controller\Controller {
|
||||
case 'Systems':
|
||||
$length = 100;
|
||||
$buildInfo = $controller->buildSystemsIndex($offset, $length);
|
||||
|
||||
$return->offset = $buildInfo['offset'];
|
||||
$return->countAll = $buildInfo['countAll'];
|
||||
$return->countBuild = $buildInfo['countBuild'];
|
||||
$return->countBuildAll = $offset;
|
||||
$return->progress = $percent($return->countAll, $offset);
|
||||
$return->countBuildAll = $return->offset;
|
||||
break;
|
||||
case 'Wormholes':
|
||||
$groupId = Config::ESI_GROUP_WORMHOLE_ID;
|
||||
$length = 10;
|
||||
$buildInfo = $controller->setupGroup($groupId, $offset, $length, true);
|
||||
|
||||
$return->offset = $buildInfo['offset'];
|
||||
$return->countAll = $buildInfo['countAll'];
|
||||
$return->countBuild = $buildInfo['count'];
|
||||
$return->countBuildAll = $return->offset;
|
||||
break;
|
||||
case 'Structures':
|
||||
$categoryId = 65;
|
||||
$length = 2;
|
||||
$offset = $count * $length;
|
||||
$categoryId = Config::ESI_CATEGORY_STRUCTURE_ID;
|
||||
$length = 1;
|
||||
$buildInfo = $controller->setupCategory($categoryId, $offset, $length);
|
||||
|
||||
$categoryUniverseModel = Model\Universe\AbstractUniverseModel::getNew('CategoryModel');
|
||||
$categoryUniverseModel->getById($categoryId, 0);
|
||||
$return->countAll = (int)$f3->get('REQUIREMENTS.DATA.STRUCTURES');
|
||||
$return->countBuild = array_reduce($buildInfo, $sum, 0);
|
||||
$return->countBuildAll = $categoryUniverseModel->getTypesCount(false);
|
||||
$return->progress = $percent($return->countAll, $return->countBuildAll);
|
||||
|
||||
$return->offset = $buildInfo['offset'];
|
||||
$return->countBuild = $buildInfo['count'];
|
||||
$return->countBuildAll = $return->offset;
|
||||
$return->subCount = [
|
||||
'countBuildAll' => $categoryUniverseModel->getTypesCount(false)
|
||||
];
|
||||
break;
|
||||
case 'Ships':
|
||||
$categoryId = 6;
|
||||
$categoryId = Config::ESI_CATEGORY_SHIP_ID;
|
||||
$length = 2;
|
||||
$offset = $count * $length;
|
||||
$buildInfo = $controller->setupCategory($categoryId, $offset, $length);
|
||||
|
||||
$categoryUniverseModel = Model\Universe\AbstractUniverseModel::getNew('CategoryModel');
|
||||
$categoryUniverseModel->getById($categoryId, 0);
|
||||
$return->countAll = (int)$f3->get('REQUIREMENTS.DATA.SHIPS');
|
||||
$return->countBuild = array_reduce($buildInfo, $sum, 0);
|
||||
$return->countBuildAll = $categoryUniverseModel->getTypesCount(false);
|
||||
$return->progress = $percent($return->countAll, $return->countBuildAll);
|
||||
|
||||
$return->offset = $buildInfo['offset'];
|
||||
$return->countBuild = $buildInfo['count'];
|
||||
$return->countBuildAll = $return->offset;
|
||||
$return->subCount = [
|
||||
'countBuildAll' => $categoryUniverseModel->getTypesCount(false)
|
||||
];
|
||||
break;
|
||||
case 'SystemStatic':
|
||||
$length = 300;
|
||||
$buildInfo = $this->setupSystemStaticTable($offset, $length);
|
||||
|
||||
$return->offset = $buildInfo['offset'];
|
||||
$return->countAll = $buildInfo['countAll'];
|
||||
$return->countBuild = $buildInfo['count'];
|
||||
$return->countBuildAll = $return->offset;
|
||||
break;
|
||||
case 'SystemNeighbour':
|
||||
// Becomes deprecated with new Universe DB!!!
|
||||
$this->setupSystemJumpTable();
|
||||
$length = 1500;
|
||||
$buildInfo = $this->setupSystemJumpTable($offset, $length);
|
||||
|
||||
$return->countAll = (int)$f3->get('REQUIREMENTS.DATA.NEIGHBOURS');
|
||||
$return->countBuild = $f3->DB->getDB('PF')->getRowCount('system_neighbour');
|
||||
$return->countBuildAll = $return->countBuild;
|
||||
$return->progress = $percent($return->countAll, $return->countBuildAll);
|
||||
$return->offset = $buildInfo['offset'];
|
||||
$return->countAll = $buildInfo['countAll'];
|
||||
$return->countBuild = $buildInfo['count'];
|
||||
$return->countBuildAll = $return->offset;
|
||||
break;
|
||||
}
|
||||
|
||||
$return->progress = $percent($return->countAll, $return->countBuildAll);
|
||||
|
||||
if($return->countBuildAll < $return->countAll){
|
||||
$return->count++;
|
||||
}
|
||||
@@ -135,21 +160,87 @@ class Setup extends Controller\Controller {
|
||||
case 'Systems':
|
||||
$controller->clearSystemsIndex();
|
||||
$systemUniverseModel = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
$return->countAll = $f3->DB->getDB('UNIVERSE')->getRowCount($systemUniverseModel->getTable());
|
||||
$return->countAll = $systemUniverseModel->getRowCount();
|
||||
break;
|
||||
case 'SystemNeighbour':
|
||||
$systemNeighbourModel = Model\Universe\AbstractUniverseModel::getNew('SystemNeighbourModel');
|
||||
$systemNeighbourModel->truncate();
|
||||
$return->countAll = (int)$f3->get('REQUIREMENTS.DATA.NEIGHBOURS');
|
||||
break;
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* import static 'system_static` table data from *.csv
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setupSystemStaticTable(int $offset = 0, int $length = 0) : array {
|
||||
$info = ['countAll' => 0, 'countChunk' => 0, 'count' => 0, 'offset' => $offset];
|
||||
|
||||
/**
|
||||
* @var $systemStaticModel Model\Universe\SystemStaticModel
|
||||
*/
|
||||
$systemStaticModel = Model\Universe\AbstractUniverseModel::getNew('SystemStaticModel');
|
||||
if(!empty($csvData = $systemStaticModel::getCSVData($systemStaticModel->getTable()))){
|
||||
$info['countAll'] = count($csvData);
|
||||
if($length){
|
||||
$csvData = array_slice($csvData, $offset, $length);
|
||||
}
|
||||
$info['countChunk'] = count($csvData);
|
||||
$cols = ['typeId' => [], 'systemId' => []];
|
||||
foreach($csvData as $data){
|
||||
$validColCount = 0;
|
||||
$systemStaticModel->getById((int)$data['id'], 0);
|
||||
$systemStaticModel->id = (int)$data['id'];
|
||||
foreach($cols as $col => &$invalidIds){
|
||||
if($systemStaticModel->exists($col)){
|
||||
$colVal = (int)$data[$col];
|
||||
if(!in_array($colVal, $invalidIds)){
|
||||
$relModel = $systemStaticModel->rel($col);
|
||||
$relModel->getById($colVal, 0);
|
||||
if($relModel->valid()){
|
||||
$systemStaticModel->$col = $relModel;
|
||||
$validColCount++;
|
||||
}else{
|
||||
$invalidIds[] = $colVal;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($validColCount == count($cols)){
|
||||
$systemStaticModel->save();
|
||||
}
|
||||
$systemStaticModel->reset();
|
||||
|
||||
$info['count']++;
|
||||
$info['offset']++;
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is just for setting up the cache table 'system_neighbour' which is used
|
||||
* for system jump calculation. Call this function manually when CCP adds Systems/Stargates
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @return array
|
||||
*/
|
||||
protected function setupSystemJumpTable(){
|
||||
$universeDB = $this->getDB('UNIVERSE');
|
||||
protected function setupSystemJumpTable(int $offset = 0, int $length = 0) : array {
|
||||
$info = ['countAll' => 0, 'countChunk' => 0, 'count' => 0, 'offset' => $offset];
|
||||
$universeDB = $this->getDB('UNIVERSE');
|
||||
|
||||
$query = "SELECT
|
||||
$query = "SELECT SQL_CALC_FOUND_ROWS
|
||||
`system`.`id` `systemId`,
|
||||
`system`.`name` `systemName`,
|
||||
`system`.`constellationId` `constellationId`,
|
||||
@@ -178,58 +269,73 @@ class Setup extends Controller\Controller {
|
||||
`system`.`security` = :ls OR
|
||||
`system`.`security` = :hs
|
||||
)
|
||||
HAVING
|
||||
`jumpNodes` IS NOT NULL
|
||||
";
|
||||
|
||||
$rows = $universeDB->exec($query, [
|
||||
$args = [
|
||||
':regionIdJove1' => 10000017,
|
||||
':regionIdJove2' => 10000019,
|
||||
':regionIdJove3' => 10000004,
|
||||
':ns' => '0.0',
|
||||
':ls' => 'L',
|
||||
':hs' => 'H'
|
||||
]);
|
||||
];
|
||||
|
||||
if(count($rows)){
|
||||
$pfDB = $this->getDB('PF');
|
||||
if($length){
|
||||
$query .= ' LIMIT :limit';
|
||||
$args[':limit'] = $length;
|
||||
|
||||
// clear cache table
|
||||
$pfDB->exec("TRUNCATE system_neighbour");
|
||||
if($offset){
|
||||
$query .= ' OFFSET :offset';
|
||||
$args[':offset'] = $offset;
|
||||
}
|
||||
}
|
||||
|
||||
$rows = $universeDB->exec($query, $args);
|
||||
|
||||
if(!empty($countRes = $universeDB->exec("SELECT FOUND_ROWS() `count`")) && isset($countRes[0]['count'])){
|
||||
$info['countAll'] = (int)$countRes[0]['count'];
|
||||
}
|
||||
|
||||
if($info['countChunk'] = count($rows)){
|
||||
$placeholderStr = function(string $str) : string {
|
||||
return ':' . $str;
|
||||
};
|
||||
|
||||
$updateRule = function(string $str) : string {
|
||||
return $str . " = VALUES(" . $str . ")";
|
||||
};
|
||||
|
||||
$universeDB->begin();
|
||||
foreach($rows as $row){
|
||||
$info['count']++;
|
||||
$info['offset']++;
|
||||
|
||||
if(!$row['jumpNodes']){
|
||||
// should never happen!
|
||||
continue;
|
||||
}
|
||||
|
||||
$pfDB->exec("
|
||||
INSERT INTO
|
||||
system_neighbour(
|
||||
regionId,
|
||||
constellationId,
|
||||
systemName,
|
||||
systemId,
|
||||
jumpNodes,
|
||||
trueSec
|
||||
)
|
||||
VALUES(
|
||||
:regionId,
|
||||
:constellationId,
|
||||
:systemName,
|
||||
:systemId,
|
||||
:jumpNodes,
|
||||
:trueSec
|
||||
)",
|
||||
[
|
||||
':regionId' => $row['regionId'],
|
||||
':constellationId' => $row['constellationId'],
|
||||
':systemName' => $row['systemName'],
|
||||
':systemId' => $row['systemId'],
|
||||
':jumpNodes' => $row['jumpNodes'],
|
||||
':trueSec' => $row['trueSec']
|
||||
]
|
||||
);
|
||||
$columns = array_keys($row);
|
||||
$columnsQuoted = array_map($universeDB->quotekey, $columns);
|
||||
$placeholder = array_map($placeholderStr, $columns);
|
||||
$args = array_combine($placeholder, $row);
|
||||
|
||||
$updateSql = array_map($updateRule, $columns);
|
||||
|
||||
$sql = "INSERT INTO
|
||||
system_neighbour(" . implode(', ', $columnsQuoted) . ")
|
||||
VALUES(" . implode(', ', $placeholder) . ")
|
||||
ON DUPLICATE KEY UPDATE
|
||||
" . implode(', ', $updateSql);
|
||||
|
||||
$universeDB->exec($sql, $args);
|
||||
}
|
||||
$universeDB->commit();
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -111,7 +111,7 @@ class System extends Controller\AccessController {
|
||||
}
|
||||
|
||||
/**
|
||||
* set destination for specific systemIds
|
||||
* set destination for system, station or structure
|
||||
* @param \Base $f3
|
||||
* @throws \Exception
|
||||
*/
|
||||
@@ -120,25 +120,25 @@ class System extends Controller\AccessController {
|
||||
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
$return->systemData = [];
|
||||
$return->destData = [];
|
||||
|
||||
if( !empty($postData['systemData'] )){
|
||||
if(!empty($destData = (array)$postData['destData'])){
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$return->clearOtherWaypoints = (bool)$postData['clearOtherWaypoints'];
|
||||
$return->first = (bool)$postData['first'];
|
||||
|
||||
if( $accessToken = $activeCharacter->getAccessToken() ){
|
||||
if($accessToken = $activeCharacter->getAccessToken()){
|
||||
$options = [
|
||||
'clearOtherWaypoints' => $return->clearOtherWaypoints,
|
||||
'addToBeginning' => $return->first,
|
||||
];
|
||||
|
||||
foreach($postData['systemData'] as $systemData){
|
||||
$response = $f3->ccpClient()->setWaypoint($systemData['systemId'], $accessToken, $options);
|
||||
foreach($destData as $data){
|
||||
$response = $f3->ccpClient()->setWaypoint((int)$data['id'], $accessToken, $options);
|
||||
|
||||
if(empty($response)){
|
||||
$return->systemData[] = $systemData;
|
||||
$return->destData[] = $data;
|
||||
}else{
|
||||
$error = (object) [];
|
||||
$error->type = 'error';
|
||||
|
||||
@@ -112,7 +112,7 @@ class Universe extends Controller\AccessController {
|
||||
|
||||
$constellation = Model\Universe\AbstractUniverseModel::getNew('ConstellationModel');
|
||||
$constellation->getById($constellationId);
|
||||
if( !$constellation->dry() && $constellation->systems){
|
||||
if($constellation->valid() && $constellation->systems){
|
||||
/**
|
||||
* @var Model\Universe\SystemModel $system
|
||||
*/
|
||||
|
||||
@@ -128,7 +128,7 @@ class User extends Controller\Controller{
|
||||
// character is valid and allowed to login
|
||||
$return->character = reset($characters)->getData();
|
||||
// get Session status for character
|
||||
if($activeCharacter = $this->getCharacter()){
|
||||
if($activeCharacter = $this->getCharacter(0)){
|
||||
if($activeUser = $activeCharacter->getUser()){
|
||||
if($sessionCharacterData = $activeUser->findSessionCharacterData($return->character->id)){
|
||||
$return->character->hasActiveSession = true;
|
||||
|
||||
@@ -81,7 +81,7 @@ class Sso extends Api\User{
|
||||
|
||||
// check if character is valid and exists
|
||||
if(
|
||||
!$character->dry() &&
|
||||
$character->valid() &&
|
||||
$character->hasUserCharacter() &&
|
||||
($activeCharacter->getUser()->_id === $character->getUser()->_id)
|
||||
){
|
||||
@@ -217,9 +217,9 @@ class Sso extends Api\User{
|
||||
$characterModel = $characterModel->updateLog();
|
||||
|
||||
// connect character with current user
|
||||
if( is_null($user = $this->getUser()) ){
|
||||
if(is_null($user = $this->getUser())){
|
||||
// connect character with existing user (no changes)
|
||||
if( is_null( $user = $characterModel->getUser()) ){
|
||||
if(is_null($user = $characterModel->getUser())){
|
||||
// no user found (new character) -> create new user and connect to character
|
||||
/**
|
||||
* @var $user Pathfinder\UserModel
|
||||
@@ -234,7 +234,7 @@ class Sso extends Api\User{
|
||||
* @var $userCharactersModel Pathfinder\UserCharacterModel
|
||||
*/
|
||||
if( is_null($userCharactersModel = $characterModel->userCharacter) ){
|
||||
$userCharactersModel = Pathfinder\AbstractPathfinderModel::getNew('UserCharacterModel');
|
||||
$userCharactersModel = $characterModel->rel('userCharacter');
|
||||
$userCharactersModel->characterId = $characterModel;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,25 @@ class Universe extends Controller {
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* setup categories + all dependencies (e.g. groups, types)
|
||||
* id 2 -> Celestial (>100 groups -> >1000 types)
|
||||
* id 6 -> Ship (46 groups -> 4xx types)
|
||||
* id 65 -> Structure (10 groups -> 33 types)
|
||||
* @param array $categoriesWhitelist
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setupCategories(array $categoriesWhitelist = []) : array {
|
||||
$info = [];
|
||||
$categoryIds = Model\Universe\CategoryModel::getUniverseCategories();
|
||||
$categoryIds = array_intersect($categoriesWhitelist, $categoryIds);
|
||||
foreach($categoryIds as $categoryId){
|
||||
$info[$categoryId] = $this->setupCategory($categoryId);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup category + all dependencies (e.g. groups, types)
|
||||
* -> $length = 0 -> setup all groups
|
||||
@@ -63,41 +82,18 @@ class Universe extends Controller {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setupCategory(int $categoryId, int $offset = 0, int $length = 0) : array {
|
||||
$return = [];
|
||||
$info = ['countAll' => 0, 'countChunk' => 0, 'count' => 0, 'offset' => $offset, 'groupTypes' => []];
|
||||
|
||||
if($categoryId){
|
||||
/**
|
||||
* @var $category Model\Universe\CategoryModel
|
||||
*/
|
||||
$category = Model\Universe\AbstractUniverseModel::getNew('CategoryModel');
|
||||
$category->loadById($categoryId);
|
||||
$groupIds = $category->loadGroupsData($offset, $length);
|
||||
foreach((array)$category->groups as $group){
|
||||
// only load types for changed groups (not all)
|
||||
if(in_array($group->_id, $groupIds)){
|
||||
$return[$group->_id] = $group->loadTypesData();
|
||||
}
|
||||
}
|
||||
$info = $category->loadGroupsData($offset, $length);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup categories + all dependencies (e.g. groups, types)
|
||||
* id 2 -> Celestial (>100 groups -> >1000 types)
|
||||
* id 6 -> Ship (45 groups -> 490 types)
|
||||
* id 65 -> Structure (10 groups -> 33 types)
|
||||
* @param array $categoriesWhitelist
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setupCategories(array $categoriesWhitelist = []) : array {
|
||||
$return = [];
|
||||
$categoryIds = $this->getF3()->ccpClient()->getUniverseCategories();
|
||||
$categoryIds = array_intersect($categoriesWhitelist, $categoryIds);
|
||||
foreach($categoryIds as $categoryId){
|
||||
$return[$categoryId] = $this->setupCategory($categoryId);
|
||||
}
|
||||
return $return;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,19 +107,38 @@ class Universe extends Controller {
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setupGroups(array $groupsWhitelist = []) : array {
|
||||
$return = [];
|
||||
$groupIds = $this->getF3()->ccpClient()->getUniverseGroups();
|
||||
$info = [];
|
||||
$groupIds = Model\Universe\GroupModel::getUniverseGroups();
|
||||
$groupIds = array_intersect($groupsWhitelist, $groupIds);
|
||||
/**
|
||||
* @var $group Model\Universe\GroupModel
|
||||
*/
|
||||
$group = Model\Universe\AbstractUniverseModel::getNew('GroupModel');
|
||||
foreach($groupIds as $groupId){
|
||||
$group->loadById($groupId);
|
||||
$return[$group->_id] = $group->loadTypesData();
|
||||
$group->reset();
|
||||
$info[$groupId] = $this->setupGroup($groupId);
|
||||
}
|
||||
return $return;
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup group + all dependencies (e.g. types)
|
||||
* @param int $groupId
|
||||
* @param int $offset
|
||||
* @param int $length
|
||||
* @param bool $storeDogmaAttributes
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setupGroup(int $groupId, int $offset = 0, int $length = 0, bool $storeDogmaAttributes = false) : array {
|
||||
$info = ['countAll' => 0, 'countChunk' => 0, 'count' => 0, 'offset' => $offset];
|
||||
|
||||
if($groupId){
|
||||
/**
|
||||
* @var $group Model\Universe\GroupModel
|
||||
*/
|
||||
$group = Model\Universe\AbstractUniverseModel::getNew('GroupModel');
|
||||
$group->storeDogmaAttributes = $storeDogmaAttributes;
|
||||
$group->loadById($groupId);
|
||||
$info = $group->loadTypesData($offset, $length);
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
// system search index methods ====================================================================================
|
||||
@@ -146,10 +161,11 @@ class Universe extends Controller {
|
||||
$system = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
$indexData = [];
|
||||
foreach($systemIds as $systemId){
|
||||
$system->getById($systemId);
|
||||
$system->getById($systemId, 0);
|
||||
if($hashKeyId = $system->getHashKey()){
|
||||
$indexData[$hashKeyId] = $system->getData();
|
||||
}
|
||||
$system->reset();
|
||||
// offset must increase otherwise we get a endless loop
|
||||
// -> see /setup ajax build loop function
|
||||
$offset++;
|
||||
@@ -165,12 +181,14 @@ class Universe extends Controller {
|
||||
|
||||
/**
|
||||
* get systemIds for all systems
|
||||
* @param bool $ignoreCache
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getSystemIds() : array {
|
||||
public function getSystemIds(bool $ignoreCache = false) : array {
|
||||
$f3 = $this->getF3();
|
||||
if( !$f3->exists(self::SESSION_KEY_SYSTEM_IDS, $systemIds) ){
|
||||
$systemIds = [];
|
||||
if($ignoreCache || !$f3->exists(self::SESSION_KEY_SYSTEM_IDS, $systemIds)){
|
||||
/**
|
||||
* @var $system Model\Universe\SystemModel
|
||||
*/
|
||||
@@ -184,7 +202,7 @@ class Universe extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
return (array)$systemIds;
|
||||
return $systemIds ? : [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,20 +243,20 @@ class Universe extends Controller {
|
||||
* @return null|\stdClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getSystemData(int $systemId){
|
||||
public function getSystemData(int $systemId) : ?\stdClass {
|
||||
$data = null;
|
||||
if($systemId){
|
||||
// ...check index for data
|
||||
$cacheKeyRow = Model\Universe\AbstractUniverseModel::generateHashKeyRow('system', $systemId);
|
||||
$data = $this->get($cacheKeyRow);
|
||||
if(!$data){
|
||||
if(!$data = $this->get($cacheKeyRow)){
|
||||
// .. try to build index
|
||||
/**
|
||||
* @var $system Model\Universe\SystemModel
|
||||
*/
|
||||
$system = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
$system->getById($systemId);
|
||||
$data = $system->buildIndex();
|
||||
if($system->getById($systemId)){
|
||||
$data = $system->buildIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
@@ -249,7 +267,7 @@ class Universe extends Controller {
|
||||
* @param string $cacheKey
|
||||
* @return null|\stdClass
|
||||
*/
|
||||
private function get(string $cacheKey){
|
||||
private function get(string $cacheKey) : ?\stdClass {
|
||||
$data = null;
|
||||
if($this->getF3()->exists($cacheKey,$value)) {
|
||||
if(is_string($value) && strpos($value, Model\Universe\AbstractUniverseModel::CACHE_KEY_PREFIX) === 0) {
|
||||
|
||||
@@ -16,6 +16,7 @@ use lib\db\SQL;
|
||||
use lib\Resource;
|
||||
use lib\Monolog;
|
||||
use lib\Util;
|
||||
use Model\AbstractModel;
|
||||
use Model\Pathfinder;
|
||||
use DB;
|
||||
|
||||
@@ -381,13 +382,14 @@ class Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* get current character data from session
|
||||
* @return array
|
||||
* get current character from session data
|
||||
* @param int $ttl
|
||||
* @return Pathfinder\CharacterModel|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getSessionCharacterData() : array {
|
||||
$data = [];
|
||||
if($user = $this->getUser()){
|
||||
protected function getSessionCharacter(int $ttl = AbstractModel::DEFAULT_SQL_TTL) : ?Pathfinder\CharacterModel {
|
||||
$character = null;
|
||||
if($user = $this->getUser($ttl)){
|
||||
$header = self::getRequestHeaders();
|
||||
$requestedCharacterId = (int)$header['Pf-Character'];
|
||||
if( !$this->getF3()->get('AJAX') ){
|
||||
@@ -400,10 +402,10 @@ class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$data = $user->getSessionCharacterData($requestedCharacterId);
|
||||
$character = $user->getSessionCharacter($requestedCharacterId, $ttl);
|
||||
}
|
||||
|
||||
return $data;
|
||||
return $character;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,24 +414,8 @@ class Controller {
|
||||
* @return Pathfinder\CharacterModel|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getCharacter(int $ttl = 0) : ?Pathfinder\CharacterModel {
|
||||
$character = null;
|
||||
|
||||
if(!empty($characterData = $this->getSessionCharacterData())){
|
||||
/**
|
||||
* @var $characterModel Pathfinder\CharacterModel
|
||||
*/
|
||||
$characterModel = Pathfinder\AbstractPathfinderModel::getNew('CharacterModel');
|
||||
$characterModel->getById((int)$characterData['ID'], $ttl);
|
||||
if(
|
||||
!$characterModel->dry() &&
|
||||
$characterModel->hasUserCharacter()
|
||||
){
|
||||
$character = &$characterModel;
|
||||
}
|
||||
}
|
||||
|
||||
return $character;
|
||||
public function getCharacter(int $ttl = AbstractModel::DEFAULT_SQL_TTL) : ?Pathfinder\CharacterModel {
|
||||
return $this->getSessionCharacter($ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,7 +424,7 @@ class Controller {
|
||||
* @return Pathfinder\UserModel|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getUser($ttl = 0) : ?Pathfinder\UserModel {
|
||||
public function getUser($ttl = AbstractModel::DEFAULT_SQL_TTL) : ?Pathfinder\UserModel {
|
||||
$user = null;
|
||||
|
||||
if($this->getF3()->exists(Api\User::SESSION_KEY_USER_ID, $userId)){
|
||||
@@ -452,7 +438,7 @@ class Controller {
|
||||
!$userModel->dry() &&
|
||||
$userModel->hasUserCharacters()
|
||||
){
|
||||
$user = &$userModel;
|
||||
$user = $userModel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,10 +520,11 @@ class Controller {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getEveServerStatus(\Base $f3){
|
||||
$ttl = 60;
|
||||
$esiStatusVersion = 'latest';
|
||||
$cacheKey = 'eve_server_status';
|
||||
|
||||
if( !$f3->exists($cacheKey, $return) ){
|
||||
if(!$exists = $f3->exists($cacheKey, $return)){
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
|
||||
@@ -593,10 +580,10 @@ class Controller {
|
||||
// find top status
|
||||
$status = 'OK';
|
||||
$color = 'green';
|
||||
foreach($apiStatus['status'] as $statusData){
|
||||
foreach($apiStatus['status'] as &$statusData){
|
||||
if('red' == $statusData['status']){
|
||||
$status = 'unstable';
|
||||
$color = $statusData['status'];
|
||||
$color = $statusData['status'] = 'orange'; // red is already in use for fatal API errors (e.g. no response at all, or offline)
|
||||
break;
|
||||
}
|
||||
if('yellow' == $statusData['status']){
|
||||
@@ -613,11 +600,15 @@ class Controller {
|
||||
}
|
||||
|
||||
if(empty($return->error)){
|
||||
$f3->set($cacheKey, $return, 60);
|
||||
$f3->set($cacheKey, $return, $ttl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($return->error)){
|
||||
$f3->expire(Config::ttlLeft($exists, $ttl));
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,13 +118,13 @@ class LogController extends \Prefab {
|
||||
$updateSql = array_map($updateRule, $columnsForUpdate);
|
||||
|
||||
$sql = "INSERT DELAYED INTO
|
||||
activity_log (" . implode(', ', $columnsQuoted) . ") values(
|
||||
" . implode(', ', $placeholder) . "
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated = NOW(),
|
||||
" . implode(', ', $updateSql) . "
|
||||
";
|
||||
activity_log (" . implode(', ', $columnsQuoted) . ") VALUES(
|
||||
" . implode(', ', $placeholder) . "
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated = NOW(),
|
||||
" . implode(', ', $updateSql) . "
|
||||
";
|
||||
|
||||
$db->exec($sql, $args);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ class Setup extends Controller {
|
||||
'Model\Pathfinder\MapTypeModel',
|
||||
'Model\Pathfinder\SystemTypeModel',
|
||||
'Model\Pathfinder\SystemStatusModel',
|
||||
'Model\Pathfinder\SystemNeighbourModel',
|
||||
'Model\Pathfinder\RightModel',
|
||||
'Model\Pathfinder\RoleModel',
|
||||
'Model\Pathfinder\StructureModel',
|
||||
@@ -105,19 +104,27 @@ class Setup extends Controller {
|
||||
'UNIVERSE' => [
|
||||
'info' => [],
|
||||
'models' => [
|
||||
'Model\Universe\DogmaAttributeModel',
|
||||
'Model\Universe\TypeAttributeModel',
|
||||
'Model\Universe\TypeModel',
|
||||
'Model\Universe\GroupModel',
|
||||
'Model\Universe\CategoryModel',
|
||||
'Model\Universe\FactionModel',
|
||||
'Model\Universe\AllianceModel',
|
||||
'Model\Universe\CorporationModel',
|
||||
'Model\Universe\RaceModel',
|
||||
'Model\Universe\StationModel',
|
||||
'Model\Universe\StructureModel',
|
||||
'Model\Universe\WormholeModel',
|
||||
'Model\Universe\StargateModel',
|
||||
'Model\Universe\StarModel',
|
||||
'Model\Universe\PlanetModel',
|
||||
'Model\Universe\SystemModel',
|
||||
'Model\Universe\ConstellationModel',
|
||||
'Model\Universe\RegionModel',
|
||||
'Model\Universe\SystemStaticModel'
|
||||
'Model\Universe\SystemNeighbourModel',
|
||||
'Model\Universe\SystemStaticModel',
|
||||
'Model\Universe\SovereigntyMapModel',
|
||||
'Model\Universe\FactionWarSystemModel'
|
||||
]
|
||||
]
|
||||
];
|
||||
@@ -1665,18 +1672,111 @@ class Setup extends Controller {
|
||||
* @var $categoryUniverseModel Universe\CategoryModel
|
||||
*/
|
||||
$categoryUniverseModel = Universe\AbstractUniverseModel::getNew('CategoryModel');
|
||||
$categoryUniverseModel->getById(65, 0);
|
||||
$structureCount = $categoryUniverseModel->getTypesCount(false);
|
||||
$categoryUniverseModel->getById(Config::ESI_CATEGORY_STRUCTURE_ID, 0);
|
||||
$groupsCountStructure = $categoryUniverseModel->getGroupsCount(false);
|
||||
$typesCountStructure = $categoryUniverseModel->getTypesCount(false);
|
||||
|
||||
$categoryUniverseModel->getById(6, 0);
|
||||
$shipCount = $categoryUniverseModel->getTypesCount(false);
|
||||
$categoryUniverseModel->getById(Config::ESI_CATEGORY_SHIP_ID, 0);
|
||||
$groupsCountShip = $categoryUniverseModel->getGroupsCount(false);
|
||||
$typesCountShip = $categoryUniverseModel->getTypesCount(false);
|
||||
|
||||
/**
|
||||
* @var $systemNeighbourModel Pathfinder\SystemNeighbourModel
|
||||
* @var $groupUniverseModel Universe\GroupModel
|
||||
*/
|
||||
$systemNeighbourModel = Pathfinder\AbstractPathfinderModel::getNew('SystemNeighbourModel');
|
||||
|
||||
$groupUniverseModel = Universe\AbstractUniverseModel::getNew('GroupModel');
|
||||
$groupUniverseModel->getById(Config::ESI_GROUP_WORMHOLE_ID, 0);
|
||||
$wormholeCount = $groupUniverseModel->getTypesCount(false);
|
||||
|
||||
/**
|
||||
* @var $systemNeighbourModel Universe\SystemNeighbourModel
|
||||
*/
|
||||
$systemNeighbourModel = Universe\AbstractUniverseModel::getNew('SystemNeighbourModel');
|
||||
|
||||
/**
|
||||
* @var $systemStaticModel Universe\SystemStaticModel
|
||||
*/
|
||||
$systemStaticModel = Universe\AbstractUniverseModel::getNew('SystemStaticModel');
|
||||
|
||||
if(empty($systemCountAll = count(($universeController = new UniverseController())->getSystemIds(true)))){
|
||||
// no systems found in 'universe' DB. Clear potential existing system cache
|
||||
$universeController->clearSystemsIndex();
|
||||
}
|
||||
|
||||
$sum = function(int $carry, int $value) : int {
|
||||
return $carry + $value;
|
||||
};
|
||||
|
||||
$indexInfo = [
|
||||
'Wormholes' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'Wormholes data',
|
||||
'countBuild' => $wormholeCount,
|
||||
'countAll' => count(Universe\GroupModel::getUniverseGroupTypes(Config::ESI_GROUP_WORMHOLE_ID)),
|
||||
'tooltip' => 'import all wormhole types (e.g. L031) from ESI. Runtime: ~25s'
|
||||
],
|
||||
'Structures' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'Structures data',
|
||||
'countBuild' => $groupsCountStructure,
|
||||
'countAll' => count(Universe\CategoryModel::getUniverseCategoryGroups(Config::ESI_CATEGORY_STRUCTURE_ID)),
|
||||
'tooltip' => 'import all structure types (e.g. Citadels) from ESI. Runtime: ~15s',
|
||||
'subCount' => [
|
||||
'countBuild' => $typesCountStructure,
|
||||
'countAll' => array_reduce(array_map('count', Universe\CategoryModel::getUniverseCategoryTypes(Config::ESI_CATEGORY_STRUCTURE_ID)), $sum, 0),
|
||||
]
|
||||
],
|
||||
'Ships' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'Ships data',
|
||||
'countBuild' => $groupsCountShip,
|
||||
'countAll' => count(Universe\CategoryModel::getUniverseCategoryGroups(Config::ESI_CATEGORY_SHIP_ID)),
|
||||
'tooltip' => 'import all ships from ESI. Runtime: ~2min',
|
||||
'subCount' => [
|
||||
'countBuild' => $typesCountShip,
|
||||
'countAll' => array_reduce(array_map('count', Universe\CategoryModel::getUniverseCategoryTypes(Config::ESI_CATEGORY_SHIP_ID)), $sum, 0),
|
||||
]
|
||||
],
|
||||
'SystemStatic' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'Wormhole statics data',
|
||||
'countBuild' => $systemStaticModel->getRowCount(),
|
||||
'countAll' => 3772,
|
||||
'tooltip' => 'import all static wormholes for systems. Runtime: ~25s'
|
||||
],
|
||||
[
|
||||
'label' => 'Build search index',
|
||||
'icon' => 'fa-search',
|
||||
'tooltip' => 'Search indexes are build from static EVE universe data (e.g. systems, stargate connections,…). Re-build if underlying data was updated.'
|
||||
],
|
||||
'Systems' => [
|
||||
'task' => [
|
||||
[
|
||||
@@ -1691,81 +1791,36 @@ class Setup extends Controller {
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'build systems index',
|
||||
'countBuild' => count((new UniverseController())->getSystemsIndex()),
|
||||
'countAll' => count((new UniverseController())->getSystemIds()),
|
||||
'tooltip' => 'build up a static search index over all systems found on DB. Do not refresh page until import is complete (check progress)! Runtime: ~5min'
|
||||
],
|
||||
'Structures' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'import structures data',
|
||||
'countBuild' => $structureCount,
|
||||
'countAll' => (int)$f3->get('REQUIREMENTS.DATA.STRUCTURES'),
|
||||
'tooltip' => 'import all structure types (e.g. Citadels) from ESI. Runtime: ~15s'
|
||||
],
|
||||
'Ships' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'import ships data',
|
||||
'countBuild' => $shipCount,
|
||||
'countAll' => (int)$f3->get('REQUIREMENTS.DATA.SHIPS'),
|
||||
'tooltip' => 'import all ships types from ESI. Runtime: ~2min'
|
||||
'label' => 'Systems data index',
|
||||
'countBuild' => count($universeController->getSystemsIndex()),
|
||||
'countAll' => $systemCountAll,
|
||||
'tooltip' => 'Build up a static search index over all systems, found on DB. Runtime: ~5min'
|
||||
],
|
||||
'SystemNeighbour' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'clearIndex',
|
||||
'label' => 'Clear',
|
||||
'icon' => 'fa-trash',
|
||||
'btn' => 'btn-danger'
|
||||
],[
|
||||
'action' => 'buildIndex',
|
||||
'label' => 'Build',
|
||||
'icon' => 'fa-sync',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'build neighbour index',
|
||||
'countBuild' => $f3->DB->getDB('PF')->getRowCount($systemNeighbourModel->getTable()),
|
||||
'label' => 'Systems neighbour index',
|
||||
'countBuild' => $systemNeighbourModel->getRowCount(),
|
||||
'countAll' => (int)$f3->get('REQUIREMENTS.DATA.NEIGHBOURS'),
|
||||
'tooltip' => 'build up a static search index for route search. This is used as fallback in case ESI is down. Runtime: ~30s'
|
||||
|
||||
],
|
||||
// All following rows become deprecated
|
||||
/*
|
||||
'WormholeModel' => [
|
||||
'task' => [
|
||||
[
|
||||
'action' => 'exportTable',
|
||||
'label' => 'Export',
|
||||
'icon' => 'fa-download',
|
||||
'btn' => 'btn-default'
|
||||
],[
|
||||
'action' => 'importTable',
|
||||
'label' => 'Import',
|
||||
'icon' => 'fa-upload',
|
||||
'btn' => 'btn-primary'
|
||||
]
|
||||
],
|
||||
'label' => 'wormhole',
|
||||
'countBuild' => $f3->DB->getDB('PF')->getRowCount($wormholeModel->getTable()),
|
||||
'countAll' => 89
|
||||
'tooltip' => 'Build up a static search index for route search. This is used as fallback in case ESI is down. Runtime: ~10s'
|
||||
]
|
||||
*/
|
||||
];
|
||||
}else{
|
||||
$indexInfo = [
|
||||
'SystemNeighbour' => [
|
||||
'task' => [],
|
||||
'label' => 'Fix database errors first!'
|
||||
[
|
||||
'label' => 'Fix database errors first!',
|
||||
'class' => 'txt-color-danger text-center'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
@@ -10,13 +10,21 @@ namespace cron;
|
||||
|
||||
abstract class AbstractCron {
|
||||
|
||||
// default max_execution_time for cronJobs
|
||||
/**
|
||||
* default max_execution_time for cronJobs
|
||||
// -> should be less then execution period
|
||||
*/
|
||||
const DEFAULT_MAX_EXECUTION_TIME = 50;
|
||||
|
||||
/**
|
||||
* set max execution time for cronjobs
|
||||
* -> Default CLI execution time is "0" -> infinite!
|
||||
* default threshold time in seconds before a running script (e.g. a large loop) should stop
|
||||
* -> so there is some time or e.g. logging,... left
|
||||
*/
|
||||
const DEFAULT_EXECUTION_TIME_THRESHOLD = 3;
|
||||
|
||||
/**
|
||||
* set max execution time for cronJbs
|
||||
* -> Default CLI execution time is 0 == infinite!
|
||||
* php.ini settings are ignored! http://php.net/manual/en/info.configuration.php#ini.max-execution-time
|
||||
* @param int $time
|
||||
*/
|
||||
@@ -24,4 +32,33 @@ abstract class AbstractCron {
|
||||
ini_set('max_execution_time', $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* get max execution time
|
||||
* -> 0 means == infinite!
|
||||
* @return int
|
||||
*/
|
||||
protected function getMaxExecutionTime() : int {
|
||||
return (int)ini_get('max_execution_time');
|
||||
}
|
||||
|
||||
/**
|
||||
* checks execution time of a "long" running script
|
||||
* -> returns false if execution time is close to maxExecutionTime
|
||||
* @param float $timeTotalStart
|
||||
* @param float|null $timeCheck
|
||||
* @param int $timeThreshold
|
||||
* @return bool
|
||||
*/
|
||||
protected function isExecutionTimeLeft(float $timeTotalStart, float $timeCheck = null, int $timeThreshold = self::DEFAULT_EXECUTION_TIME_THRESHOLD) : bool {
|
||||
$timeLeft = true;
|
||||
if($timeTotalMax = $this->getMaxExecutionTime()){
|
||||
$timeTotalMaxThreshold = $timeTotalStart + $timeTotalMax - $timeThreshold;
|
||||
$timeCheck = $timeCheck ? : microtime(true);
|
||||
if($timeCheck >= $timeTotalMaxThreshold){
|
||||
$timeLeft = false;
|
||||
}
|
||||
}
|
||||
return $timeLeft;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,7 +65,7 @@ class CharacterUpdate extends AbstractCron {
|
||||
*/
|
||||
if(is_object($characterLog->characterId)){
|
||||
if($accessToken = $characterLog->characterId->getAccessToken()){
|
||||
if($this->isOnline($accessToken)){
|
||||
if($characterLog->characterId->isOnline($accessToken)){
|
||||
// force characterLog as "updated" even if no changes were made
|
||||
$characterLog->touch('updated');
|
||||
$characterLog->save();
|
||||
|
||||
@@ -13,6 +13,7 @@ use Model;
|
||||
class Universe extends AbstractCron {
|
||||
|
||||
const LOG_TEXT = '%s type: %s %s/%s peak: %s total: %s msg: %s';
|
||||
const LOG_TEXT_SOV_FW = '%s %4s/%-4s checked, %s peak, %s total, %4s updated [%4s sovChanges, %4s fwChanges], msg: %s';
|
||||
|
||||
|
||||
/**
|
||||
@@ -133,10 +134,11 @@ class Universe extends AbstractCron {
|
||||
* @param float $timeTotalStart
|
||||
*/
|
||||
private function echoLoaded(int $importCount, int $id, float $timeLoopStart, float $timeTotalStart){
|
||||
$time = microtime(true);
|
||||
echo '[' . date('H:i:s') . '] loaded ' . str_pad('', strlen($importCount), ' ') . ' id: ' . $this->formatIdValue($id) .
|
||||
' memory: ' . $this->formatMemoryValue(memory_get_usage()) .
|
||||
' time: ' . $this->formatSeconds(microtime(true) - $timeLoopStart) .
|
||||
' total: ' . $this->formatSeconds(microtime(true) - $timeTotalStart) . PHP_EOL;
|
||||
' time: ' . $this->formatSeconds($time - $timeLoopStart) .
|
||||
' total: ' . $this->formatSeconds($time - $timeTotalStart) . PHP_EOL;
|
||||
$this->echoFlush();
|
||||
}
|
||||
|
||||
@@ -169,8 +171,8 @@ class Universe extends AbstractCron {
|
||||
$msg = '';
|
||||
|
||||
$ids = [];
|
||||
$importCount = 0;
|
||||
$count = 0;
|
||||
$importCount = [];
|
||||
$modelClass = '';
|
||||
$setupModel = function(Model\Universe\AbstractUniverseModel &$model, int $id){};
|
||||
|
||||
@@ -193,12 +195,51 @@ class Universe extends AbstractCron {
|
||||
$model->loadStargatesData();
|
||||
};
|
||||
break;
|
||||
case 'station':
|
||||
$ids = $f3->ccpClient()->getUniverseSystems();
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id){
|
||||
if($model->getById($id)){
|
||||
$model->loadStationsData();
|
||||
}else{
|
||||
echo 'NOT VALID ' . $id . PHP_EOL;
|
||||
die();
|
||||
}
|
||||
};
|
||||
break;
|
||||
case 'sovereignty':
|
||||
// load sovereignty map data. Systems must be present first!
|
||||
$sovData = $f3->ccpClient()->getSovereigntyMap();
|
||||
$ids = !empty($sovData = $sovData['map']) ? array_keys($sovData): [];
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id) use ($sovData) {
|
||||
if($model->getById($id)){
|
||||
$model->updateSovereigntyData($sovData[$id]);
|
||||
}else{
|
||||
echo 'NOT VALID ' . $id . PHP_EOL;
|
||||
die();
|
||||
}
|
||||
};
|
||||
break;
|
||||
case 'faction_war_systems':
|
||||
$fwSystems = $f3->ccpClient()->getFactionWarSystems();
|
||||
$ids = !empty($fwSystems = $fwSystems['systems']) ? array_keys($fwSystems): [];
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id) use ($fwSystems) {
|
||||
if($model->getById($id)){
|
||||
$model->updateFactionWarData($fwSystems[$id]);
|
||||
}else{
|
||||
echo 'NOT VALID ' . $id . PHP_EOL;
|
||||
die();
|
||||
}
|
||||
};
|
||||
break;
|
||||
case 'index_system':
|
||||
// setup system index, Systems must be present first!
|
||||
$ids = $f3->ccpClient()->getUniverseSystems();
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id){
|
||||
$model->getById($id); // no loadById() here! would take "forever" when system not exists and build up first...
|
||||
$model->getById($id); // no loadById() here! would take "forever" when system not exists and must be build up first...
|
||||
$model->buildIndex();
|
||||
};
|
||||
break;
|
||||
@@ -216,6 +257,7 @@ class Universe extends AbstractCron {
|
||||
sort($ids, SORT_NUMERIC);
|
||||
$ids = array_slice($ids, $offset, $length);
|
||||
$importCount = count($ids);
|
||||
$count = 0;
|
||||
|
||||
$this->echoInfo($total, $offset, $importCount, $ids);
|
||||
$this->echoStart();
|
||||
@@ -237,9 +279,83 @@ class Universe extends AbstractCron {
|
||||
|
||||
// Log --------------------------------------------------------------------------------------------------------
|
||||
$log = new \Log('cron_' . __FUNCTION__ . '.log');
|
||||
$log->write( sprintf(self::LOG_TEXT, __FUNCTION__, $type,
|
||||
$log->write(sprintf(self::LOG_TEXT, __FUNCTION__, $type,
|
||||
$this->formatCounterValue($count), $importCount, $this->formatMemoryValue(memory_get_peak_usage ()),
|
||||
$this->formatSeconds(microtime(true) - $timeTotalStart), $msg) );
|
||||
$this->formatSeconds(microtime(true) - $timeTotalStart), $msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* update Sovereignty system data from ESI
|
||||
* -> this updates Faction warfare data as well
|
||||
* >> php index.php "/cron/updateSovereigntyData"
|
||||
* @param \Base $f3
|
||||
* @throws \Exception
|
||||
*/
|
||||
function updateSovereigntyData(\Base $f3){
|
||||
$this->setMaxExecutionTime();
|
||||
$timeTotalStart = microtime(true);
|
||||
$msg = '';
|
||||
|
||||
/**
|
||||
* @var $system Model\Universe\SystemModel
|
||||
*/
|
||||
$system = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
|
||||
$sovData = $f3->ccpClient()->getSovereigntyMap();
|
||||
$fwSystems = $f3->ccpClient()->getFactionWarSystems();
|
||||
$fwSystems = $fwSystems['systems'];
|
||||
$ids = !empty($sovData = $sovData['map']) ? array_keys($sovData): [];
|
||||
sort($ids, SORT_NUMERIC);
|
||||
$importCount = count($ids);
|
||||
$count = 0;
|
||||
|
||||
$changes = [];
|
||||
foreach($ids as $id){
|
||||
$count++;
|
||||
|
||||
// skip wormhole systems -> can not have sov data
|
||||
// -> even though they are returned from sovereignty/map endpoint?!
|
||||
if(
|
||||
$system->getById($id, 0) &&
|
||||
strpos($system->security, 'C') === false
|
||||
){
|
||||
if($changedSovData = $system->updateSovereigntyData($sovData[$id])){
|
||||
$changes['sovereignty'][] = $id;
|
||||
}
|
||||
|
||||
$changedFwData = false;
|
||||
if(is_array($fwSystems[$id])){
|
||||
if($changedFwData = $system->updateFactionWarData($fwSystems[$id])){
|
||||
$changes['factionWarfare'][] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
if($changedSovData || $changedFwData){
|
||||
$system->buildIndex();
|
||||
}
|
||||
}
|
||||
$system->reset();
|
||||
|
||||
// stop loop if runtime gets close to "max_execution_time"
|
||||
// -> we need some time for writing *.log file
|
||||
if(!$this->isExecutionTimeLeft($timeTotalStart)){
|
||||
$msg = 'Script execution stopped due to "max_execution_time" limit reached';
|
||||
// TODO store current loop index and use it as new "offset" for next call
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$changedIds = array_reduce($changes, function(array $reducedIds, array $changedIds) : array {
|
||||
return array_unique(array_merge($reducedIds, $changedIds));
|
||||
}, []);
|
||||
|
||||
// Log ------------------------
|
||||
$log = new \Log('cron_' . __FUNCTION__ . '.log');
|
||||
$log->write(sprintf(self::LOG_TEXT_SOV_FW, __FUNCTION__,
|
||||
$count, $importCount, $this->formatMemoryValue(memory_get_peak_usage ()),
|
||||
$this->formatSeconds(microtime(true) - $timeTotalStart),
|
||||
count($changedIds), count($changes['sovereignty'] ? : []), count($changes['factionWarfare'] ? : []),
|
||||
$msg));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,9 +367,12 @@ class Universe extends AbstractCron {
|
||||
*/
|
||||
function updateUniverseSystems(\Base $f3){
|
||||
$this->setMaxExecutionTime();
|
||||
|
||||
$system = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
$systems = $system->find( null, ['order' => 'updated', 'limit' => 2]);
|
||||
/**
|
||||
* @var $systemModel Model\Universe\SystemModel
|
||||
* @var $system Model\Universe\SystemModel
|
||||
*/
|
||||
$systemModel = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
$systems = $systemModel->find( null, ['order' => 'updated', 'limit' => 2]);
|
||||
if($systems){
|
||||
foreach ($systems as $system){
|
||||
$system->updateModel();
|
||||
|
||||
124
app/main/lib/PriorityCacheStore.php
Normal file
124
app/main/lib/PriorityCacheStore.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace lib;
|
||||
|
||||
|
||||
class PriorityCacheStore {
|
||||
|
||||
/**
|
||||
* default max entry limit before store gets truncated
|
||||
*/
|
||||
const DEFAULT_ENTRY_LIMIT = 100;
|
||||
|
||||
/**
|
||||
* default cleanup interval
|
||||
* -> truncate store after 10 inserts. Max store entries:
|
||||
* DEFAULT_ENTRY_LIMIT + DEFAULT_CLEANUP_INTERVAL - 1
|
||||
*/
|
||||
const DEFAULT_CLEANUP_INTERVAL = 10;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $entryLimit;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $cleanupInterval;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* @var \SplPriorityQueue
|
||||
*/
|
||||
protected $priorityQueue;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $priority = 0;
|
||||
|
||||
/**
|
||||
* PriorityCacheStore constructor.
|
||||
* @param int $entryLimit
|
||||
* @param int $cleanupInterval
|
||||
*/
|
||||
function __construct(int $entryLimit = self::DEFAULT_ENTRY_LIMIT, int $cleanupInterval = self::DEFAULT_CLEANUP_INTERVAL){
|
||||
$this->cleanupInterval = $cleanupInterval;
|
||||
$this->entryLimit = $entryLimit;
|
||||
$this->store = [];
|
||||
$this->priorityQueue = new \SplPriorityQueue ();
|
||||
$this->priorityQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $data
|
||||
*/
|
||||
public function set($key, $data){
|
||||
if(!$this->exists($key)){
|
||||
$this->priorityQueue->insert($key, $this->priority--);
|
||||
}
|
||||
|
||||
$this->store[$key] = $data;
|
||||
|
||||
// check cleanup interval and cleanup Store
|
||||
$this->cleanupInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get($key){
|
||||
return $this->exists($key) ? $this->store[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($key){
|
||||
return isset($this->store[$key]);
|
||||
}
|
||||
|
||||
public function cleanupInterval() : void {
|
||||
if(
|
||||
!$this->priorityQueue->isEmpty() && $this->cleanupInterval &&
|
||||
($this->priorityQueue->count() % $this->cleanupInterval === 0)
|
||||
){
|
||||
$this->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
public function cleanup(){
|
||||
while(
|
||||
$this->entryLimit < $this->priorityQueue->count() &&
|
||||
$this->priorityQueue->valid()
|
||||
){
|
||||
if($this->exists($key = $this->priorityQueue->extract()['data'])){
|
||||
unset($this->store[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clear(){
|
||||
$limit = $this->entryLimit;
|
||||
$this->entryLimit = 0;
|
||||
$this->cleanup();
|
||||
// restore entryLimit for next data
|
||||
$this->entryLimit = $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(){
|
||||
return 'Store count: ' . count($this->store) . ' priorityQueue count: ' . $this->priorityQueue->count();
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,30 @@ class Config extends \Prefab {
|
||||
*/
|
||||
const DOWNTIME_BUFFER = 1;
|
||||
|
||||
// ================================================================================================================
|
||||
// ESI API id´s
|
||||
// ================================================================================================================
|
||||
|
||||
/**
|
||||
* ESI categoryId or 'Structure's
|
||||
*/
|
||||
const ESI_CATEGORY_STRUCTURE_ID = 65;
|
||||
|
||||
/**
|
||||
* ESI categoryId or 'Ship's
|
||||
*/
|
||||
const ESI_CATEGORY_SHIP_ID = 6;
|
||||
|
||||
/**
|
||||
* ESI groupId or 'Wormhole's
|
||||
*/
|
||||
const ESI_GROUP_WORMHOLE_ID = 988;
|
||||
|
||||
/**
|
||||
* ESI dogmaAttributeId for 'scanWormholeStrength's
|
||||
*/
|
||||
const ESI_DOGMA_ATTRIBUTE_SCANWHSTRENGTH_ID = 1908;
|
||||
|
||||
/**
|
||||
* error message for missing Composer dependency class
|
||||
*/
|
||||
@@ -166,7 +190,7 @@ class Config extends \Prefab {
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getAllEnvironmentData(\Base $f3){
|
||||
if( !$f3->exists(self::HIVE_KEY_ENVIRONMENT, $environmentData) ){
|
||||
if(!$f3->exists(self::HIVE_KEY_ENVIRONMENT, $environmentData)){
|
||||
$environmentData = $this->setAllEnvironmentData($f3);
|
||||
}
|
||||
|
||||
@@ -320,7 +344,7 @@ class Config extends \Prefab {
|
||||
if($config['SCHEME'] == 'mysql'){
|
||||
$options[\PDO::MYSQL_ATTR_COMPRESS] = true;
|
||||
$options[\PDO::MYSQL_ATTR_INIT_COMMAND] = implode(',', [
|
||||
"SET NAMES " . strtolower(str_replace('-','', $f3->ENCODING)),
|
||||
"SET NAMES " . self::getRequiredDbVars($f3, $config['SCHEME'])['CHARACTER_SET_CONNECTION'] . " COLLATE " . self::getRequiredDbVars($f3, $config['SCHEME'])['COLLATION_CONNECTION'],
|
||||
"@@session.time_zone = '+00:00'",
|
||||
"@@session.default_storage_engine = " . self::getRequiredDbVars($f3, $config['SCHEME'])['DEFAULT_STORAGE_ENGINE']
|
||||
]);
|
||||
@@ -616,4 +640,18 @@ class Config extends \Prefab {
|
||||
return $format;
|
||||
}
|
||||
|
||||
static function ttlLeft($fromExists, int $ttlMax) : int {
|
||||
$ttlMax = max($ttlMax, 0);
|
||||
if($fromExists){
|
||||
// == true || array
|
||||
if(is_array($fromExists)){
|
||||
return max(min((int)ceil(round(array_sum($fromExists) - microtime(true), 4)), $ttlMax), 0);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
// == false
|
||||
return $ttlMax;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,8 +110,8 @@ class Pool extends \Prefab {
|
||||
$schema = new Schema($db);
|
||||
if(!in_array($newDbName, $schema->getDatabases())){
|
||||
$db->exec("CREATE DATABASE IF NOT EXISTS
|
||||
`" . $newDbName . "` DEFAULT CHARACTER SET utf8
|
||||
COLLATE utf8_general_ci;");
|
||||
`" . $newDbName . "` DEFAULT CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_unicode_ci;");
|
||||
$db->exec("USE `" . $newDbName . "`");
|
||||
|
||||
// check if DB create was successful
|
||||
|
||||
@@ -51,12 +51,30 @@ class Util {
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* transforms array with assoc. arrays as values
|
||||
* into assoc. array where $key column data is used for its key
|
||||
* @param array $array
|
||||
* @param string $key
|
||||
* @param bool $unsetKey
|
||||
* @return array
|
||||
*/
|
||||
static function arrayGetBy(array $array, string $key, bool $unsetKey = true) : array {
|
||||
// we can remove $key from nested arrays
|
||||
return array_map(function($val) use ($key, $unsetKey) : array {
|
||||
if($unsetKey){
|
||||
unset($val[$key]);
|
||||
}
|
||||
return $val;
|
||||
}, array_column($array, null, $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether an array is associative or not (sequential)
|
||||
* @param mixed $array
|
||||
* @return bool
|
||||
*/
|
||||
static function is_assoc($array): bool {
|
||||
static function is_assoc($array) : bool {
|
||||
$isAssoc = false;
|
||||
if(
|
||||
is_array($array) &&
|
||||
@@ -109,7 +127,7 @@ class Util {
|
||||
* @param int $maxHideChars
|
||||
* @return string
|
||||
*/
|
||||
static function obscureString(string $string, int $maxHideChars = 10): string {
|
||||
static function obscureString(string $string, int $maxHideChars = 10) : string {
|
||||
$formatted = '';
|
||||
$length = mb_strlen((string)$string);
|
||||
if($length > 0){
|
||||
@@ -125,7 +143,7 @@ class Util {
|
||||
* @param array $scopes
|
||||
* @return string
|
||||
*/
|
||||
static function getHashFromScopes($scopes){
|
||||
static function getHashFromScopes($scopes) : string {
|
||||
$scopes = (array)$scopes;
|
||||
sort($scopes);
|
||||
return md5(serialize($scopes));
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Model;
|
||||
use DB\Cortex;
|
||||
use DB\CortexCollection;
|
||||
use DB\SQL\Schema;
|
||||
use lib\Util;
|
||||
use lib\logging;
|
||||
use Controller;
|
||||
use Exception\ValidationException;
|
||||
@@ -44,6 +45,14 @@ abstract class AbstractModel extends Cortex {
|
||||
*/
|
||||
protected $addStaticFields = true;
|
||||
|
||||
/**
|
||||
* enables table truncate
|
||||
* -> see truncate();
|
||||
* -> CAUTION! if set to true truncate() will clear ALL rows!
|
||||
* @var bool
|
||||
*/
|
||||
protected $allowTruncate = false;
|
||||
|
||||
/**
|
||||
* enables change for "active" column
|
||||
* -> see setActive();
|
||||
@@ -89,6 +98,23 @@ abstract class AbstractModel extends Cortex {
|
||||
*/
|
||||
const DEFAULT_CACHE_TTL = 120;
|
||||
|
||||
/**
|
||||
* default TTL or temp table data read from *.csv file
|
||||
* -> used during data import
|
||||
*/
|
||||
const DEFAULT_CACHE_CSV_TTL = 120;
|
||||
|
||||
/**
|
||||
* cache key prefix name for "full table" indexing
|
||||
* -> used e.g. for a "search" index; or "import" index for *.csv imports
|
||||
*/
|
||||
const CACHE_KEY_PREFIX = 'INDEX';
|
||||
|
||||
/**
|
||||
* cache key name for temp data import from *.csv files per table
|
||||
*/
|
||||
const CACHE_KEY_CSV_PREFIX = 'CSV';
|
||||
|
||||
/**
|
||||
* default TTL for SQL query cache
|
||||
*/
|
||||
@@ -495,7 +521,7 @@ abstract class AbstractModel extends Cortex {
|
||||
* @return bool
|
||||
*/
|
||||
public function getById(int $id, int $ttl = self::DEFAULT_SQL_TTL, bool $isActive = true) : bool {
|
||||
return $this->getByForeignKey('id', $id, ['limit' => 1], $ttl, $isActive);
|
||||
return $this->getByForeignKey($this->primary, $id, ['limit' => 1], $ttl, $isActive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,10 +534,7 @@ abstract class AbstractModel extends Cortex {
|
||||
* @return bool
|
||||
*/
|
||||
public function getByForeignKey(string $key, $value, array $options = [], int $ttl = 0, bool $isActive = true) : bool {
|
||||
$filters = [];
|
||||
if($this->exists($key)){
|
||||
$filters[] = [$key . ' = :' . $key, ':' . $key => $value];
|
||||
}
|
||||
$filters = [self::getFilter($key, $value)];
|
||||
|
||||
if($isActive && $this->exists('active')){
|
||||
$filters[] = self::getFilter('active', true);
|
||||
@@ -658,6 +681,24 @@ abstract class AbstractModel extends Cortex {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get row count in this table
|
||||
* @return int
|
||||
*/
|
||||
public function getRowCount() : int {
|
||||
return is_object($this->db) ? $this->db->getRowCount($this->getTable()) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* truncate all table rows
|
||||
* -> Use with Caution!!!
|
||||
*/
|
||||
public function truncate(){
|
||||
if($this->allowTruncate && is_object($this->db)){
|
||||
$this->db->exec("TRUNCATE " . $this->getTable());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* format dateTime column
|
||||
* @param $column
|
||||
@@ -716,43 +757,78 @@ abstract class AbstractModel extends Cortex {
|
||||
}
|
||||
|
||||
/**
|
||||
* import table data from a *.csv file
|
||||
* @return array|bool
|
||||
* read *.csv file for a $table name
|
||||
* -> 'group' by $getByKey column name and return array
|
||||
* @param string $table
|
||||
* @param string $getByKey
|
||||
* @return array
|
||||
*/
|
||||
public function importData(){
|
||||
$status = false;
|
||||
public static function getCSVData(string $table, string $getByKey = 'id') : array {
|
||||
$hashKeyTableCSV = static::generateHashKeyTable($table, static::CACHE_KEY_PREFIX . '_' . self::CACHE_KEY_CSV_PREFIX);
|
||||
|
||||
if(
|
||||
!self::getF3()->exists($hashKeyTableCSV, $tableData) &&
|
||||
!empty($tableData = Util::arrayGetBy(self::loadCSV($table), $getByKey, false))
|
||||
){
|
||||
self::getF3()->set($hashKeyTableCSV, $tableData, self::DEFAULT_CACHE_CSV_TTL);
|
||||
}
|
||||
|
||||
return $tableData;
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from *.csv file
|
||||
* @param string $fileName
|
||||
* @return array
|
||||
*/
|
||||
protected static function loadCSV(string $fileName) : array {
|
||||
$tableData = [];
|
||||
|
||||
// rtrim(); for arrays (removes empty values) from the end
|
||||
$rtrim = function($array = [], $lengthMin = false){
|
||||
$rtrim = function($array = [], $lengthMin = false) : array {
|
||||
$length = key(array_reverse(array_diff($array, ['']), 1))+1;
|
||||
$length = $length < $lengthMin ? $lengthMin : $length;
|
||||
return array_slice($array, 0, $length);
|
||||
};
|
||||
|
||||
if(static::$enableDataImport){
|
||||
$filePath = $this->getF3()->get('EXPORT') . 'csv/' . $this->getTable() . '.csv';
|
||||
|
||||
if($fileName){
|
||||
$filePath = self::getF3()->get('EXPORT') . 'csv/' . $fileName . '.csv';
|
||||
if(is_file($filePath)){
|
||||
$handle = @fopen($filePath, 'r');
|
||||
$keys = array_map('lcfirst', fgetcsv($handle, 0, ';'));
|
||||
$keys = $rtrim($keys);
|
||||
|
||||
if(count($keys) > 0){
|
||||
$tableData = [];
|
||||
while (!feof($handle)) {
|
||||
$tableData[] = array_combine($keys, $rtrim(fgetcsv($handle, 0, ';'), count($keys)));
|
||||
}
|
||||
// import row data
|
||||
$status = $this->importStaticData($tableData);
|
||||
$this->getF3()->status(202);
|
||||
}else{
|
||||
$this->getF3()->error(500, 'File could not be read');
|
||||
self::getF3()->error(500, 'File could not be read');
|
||||
}
|
||||
}else{
|
||||
$this->getF3()->error(404, 'File not found: ' . $filePath);
|
||||
self::getF3()->error(404, 'File not found: ' . $filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return $tableData;
|
||||
}
|
||||
|
||||
/**
|
||||
* import table data from a *.csv file
|
||||
* @return array|bool
|
||||
*/
|
||||
public function importData(){
|
||||
$status = false;
|
||||
|
||||
if(
|
||||
static::$enableDataImport &&
|
||||
!empty($tableData = self::loadCSV($this->getTable()))
|
||||
){
|
||||
// import row data
|
||||
$status = $this->importStaticData($tableData);
|
||||
$this->getF3()->status(202);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
@@ -896,6 +972,15 @@ abstract class AbstractModel extends Cortex {
|
||||
return \Base::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* get model data as array
|
||||
* @param $data
|
||||
* @return array
|
||||
*/
|
||||
public static function toArray($data) : array {
|
||||
return json_decode(json_encode($data), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* get new filter array representation
|
||||
* -> $suffix can be used fore unique placeholder,
|
||||
@@ -1019,6 +1104,17 @@ abstract class AbstractModel extends Cortex {
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate hashKey for a complete table
|
||||
* -> should hold hashKeys for multiple rows
|
||||
* @param string $table
|
||||
* @param string $prefix
|
||||
* @return string
|
||||
*/
|
||||
public static function generateHashKeyTable(string $table, string $prefix = self::CACHE_KEY_PREFIX ) : string {
|
||||
return $prefix . '_' . strtolower($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrites parent
|
||||
* @param null $db
|
||||
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class AllianceMapModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'alliance_map';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
|
||||
@@ -13,8 +13,14 @@ use lib\Config;
|
||||
|
||||
class AllianceModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'alliance';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -145,7 +151,7 @@ class AllianceModel extends AbstractPathfinderModel {
|
||||
if($this->isOutdated()){
|
||||
// request alliance data
|
||||
$allianceData = self::getF3()->ccpClient()->getAllianceData($id);
|
||||
if( !empty($allianceData) ){
|
||||
if(!empty($allianceData) && !isset($allianceData['error'])){
|
||||
$this->copyfrom($allianceData, ['id', 'name', 'ticker']);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
@@ -96,6 +96,15 @@ class CharacterLogModel extends AbstractPathfinderModel {
|
||||
'default' => '',
|
||||
'activity-log' => true
|
||||
],
|
||||
'structureTypeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'structureTypeName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'structureId' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'index' => true,
|
||||
@@ -146,9 +155,13 @@ class CharacterLogModel extends AbstractPathfinderModel {
|
||||
}
|
||||
|
||||
if( isset($logData['structure']) ){
|
||||
$this->structureTypeId = (int)$logData['structure']['type']['id'];
|
||||
$this->structureTypeName = $logData['structure']['type']['name'];
|
||||
$this->structureId = (int)$logData['structure']['id'];
|
||||
$this->structureName = $logData['structure']['name'];
|
||||
}else{
|
||||
$this->structureTypeId = null;
|
||||
$this->structureTypeName = '';
|
||||
$this->structureId = null;
|
||||
$this->structureName = '';
|
||||
}
|
||||
@@ -178,20 +191,15 @@ class CharacterLogModel extends AbstractPathfinderModel {
|
||||
$logData->station->name = $this->stationName;
|
||||
|
||||
$logData->structure = (object) [];
|
||||
$logData->structure->type = (object) [];
|
||||
$logData->structure->type->id = $this->structureTypeId;
|
||||
$logData->structure->type->name = $this->structureTypeName;
|
||||
$logData->structure->id = (int)$this->structureId;
|
||||
$logData->structure->name = $this->structureName;
|
||||
|
||||
return $logData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get 'character log' data as array
|
||||
* @return array
|
||||
*/
|
||||
public function getDataAsArray() : array {
|
||||
return json_decode(json_encode($this->getData()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
|
||||
@@ -499,14 +499,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
* @return UserModel|null
|
||||
*/
|
||||
public function getUser() : ?UserModel {
|
||||
$user = null;
|
||||
if($this->hasUserCharacter()){
|
||||
/**
|
||||
* @var $user UserModel
|
||||
*/
|
||||
$user = $this->userCharacter->userId;
|
||||
}
|
||||
return $user;
|
||||
return $this->hasUserCharacter() ? $this->userCharacter->userId : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -864,23 +857,22 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
if($this->isOnline($accessToken)){
|
||||
$locationData = self::getF3()->ccpClient()->getCharacterLocationData($this->_id, $accessToken);
|
||||
|
||||
if( !empty($locationData['system']['id']) ){
|
||||
if(!empty($locationData['system']['id'])){
|
||||
// character is currently in-game
|
||||
|
||||
// get current $characterLog or get new ---------------------------------------------------
|
||||
if( !($characterLog = $this->getLog()) ){
|
||||
// get current $characterLog or get new -------------------------------------------------------
|
||||
if(!$characterLog = $this->getLog()){
|
||||
// create new log
|
||||
$characterLog = $this->rel('characterLog');
|
||||
}
|
||||
|
||||
// get current log data and modify on change
|
||||
$logData = $characterLog->getDataAsArray();
|
||||
$logData = $characterLog::toArray($characterLog->getData());
|
||||
|
||||
// check system and station data for changes ----------------------------------------------
|
||||
// check system and station data for changes --------------------------------------------------
|
||||
|
||||
// IDs for "systemId", "stationId" that require more data
|
||||
$lookupUniverseIds = [];
|
||||
|
||||
if(
|
||||
empty($logData['system']['name']) ||
|
||||
$logData['system']['id'] !== $locationData['system']['id']
|
||||
@@ -889,33 +881,18 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
$lookupUniverseIds[] = $locationData['system']['id'];
|
||||
}
|
||||
|
||||
if( !empty($locationData['station']['id']) ){
|
||||
if(
|
||||
empty($logData['station']['name']) ||
|
||||
$logData['station']['id'] !== $locationData['station']['id']
|
||||
){
|
||||
// station changed -> request "station name" for current station
|
||||
$lookupUniverseIds[] = $locationData['station']['id'];
|
||||
}
|
||||
}else{
|
||||
unset($logData['station']);
|
||||
}
|
||||
|
||||
$logData = array_replace_recursive($logData, $locationData);
|
||||
|
||||
// get "more" data for systemId and/or stationId -----------------------------------------
|
||||
if( !empty($lookupUniverseIds) ){
|
||||
// get "more" data for systemId ---------------------------------------------------------------
|
||||
if(!empty($lookupUniverseIds)){
|
||||
// get "more" information for some Ids (e.g. name)
|
||||
$universeData = self::getF3()->ccpClient()->getUniverseNamesData($lookupUniverseIds);
|
||||
|
||||
if( !empty($universeData) && !isset($universeData['error']) ){
|
||||
if(!empty($universeData) && !isset($universeData['error'])){
|
||||
// We expect max ONE system AND/OR station data, not an array of e.g. systems
|
||||
if(!empty($universeData['system'])){
|
||||
$universeData['system'] = reset($universeData['system']);
|
||||
}
|
||||
if(!empty($universeData['station'])){
|
||||
$universeData['station'] = reset($universeData['station']);
|
||||
}
|
||||
|
||||
$logData = array_replace_recursive($logData, $universeData);
|
||||
}else{
|
||||
@@ -924,32 +901,63 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
}
|
||||
}
|
||||
|
||||
// check structure data for changes -------------------------------------------------------
|
||||
// check station data for changes -------------------------------------------------------------
|
||||
if(!$deleteLog){
|
||||
// IDs for "stationId" that require more data
|
||||
$lookupStationId = 0;
|
||||
if(!empty($locationData['station']['id'])){
|
||||
if(
|
||||
empty($logData['station']['name']) ||
|
||||
$logData['station']['id'] !== $locationData['station']['id']
|
||||
){
|
||||
// station changed -> request station data
|
||||
$lookupStationId = $locationData['station']['id'];
|
||||
}
|
||||
}else{
|
||||
unset($logData['station']);
|
||||
}
|
||||
|
||||
// get "more" data for stationId
|
||||
if($lookupStationId > 0){
|
||||
/**
|
||||
* @var $stationModel Universe\StationModel
|
||||
*/
|
||||
$stationModel = Universe\AbstractUniverseModel::getNew('StationModel');
|
||||
$stationModel->loadById($lookupStationId, $accessToken, $additionalOptions);
|
||||
if($stationModel->valid()){
|
||||
$stationData['station'] = $stationModel::toArray($stationModel->getData());
|
||||
$logData = array_replace_recursive($logData, $stationData);
|
||||
}else{
|
||||
unset($logData['station']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check structure data for changes -----------------------------------------------------------
|
||||
if(!$deleteLog){
|
||||
// IDs for "structureId" that require more data
|
||||
$lookupStructureId = 0;
|
||||
if( !empty($locationData['structure']['id']) ){
|
||||
if(!empty($locationData['structure']['id'])){
|
||||
if(
|
||||
empty($logData['structure']['name']) ||
|
||||
$logData['structure']['id'] !== $locationData['structure']['id']
|
||||
){
|
||||
// structure changed -> request "structure name" for current station
|
||||
// structure changed -> request structure data
|
||||
$lookupStructureId = $locationData['structure']['id'];
|
||||
}
|
||||
}else{
|
||||
unset($logData['structure']);
|
||||
}
|
||||
|
||||
// get "more" data for structureId ---------------------------------------------------
|
||||
// get "more" data for structureId
|
||||
if($lookupStructureId > 0){
|
||||
/**
|
||||
* @var $structureModel Universe\StructureModel
|
||||
*/
|
||||
$structureModel = Universe\AbstractUniverseModel::getNew('StructureModel');
|
||||
$structureModel->loadById($lookupStructureId, $accessToken, $additionalOptions);
|
||||
if(!$structureModel->dry()){
|
||||
$structureData['structure'] = (array)$structureModel->getData();
|
||||
if($structureModel->valid()){
|
||||
$structureData['structure'] = $structureModel::toArray($structureModel->getData());
|
||||
$logData = array_replace_recursive($logData, $structureData);
|
||||
}else{
|
||||
unset($logData['structure']);
|
||||
@@ -957,13 +965,13 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
}
|
||||
}
|
||||
|
||||
// check ship data for changes ------------------------------------------------------------
|
||||
if( !$deleteLog ){
|
||||
// check ship data for changes ----------------------------------------------------------------
|
||||
if(!$deleteLog){
|
||||
$shipData = self::getF3()->ccpClient()->getCharacterShipData($this->_id, $accessToken);
|
||||
|
||||
// IDs for "shipTypeId" that require more data
|
||||
$lookupShipTypeId = 0;
|
||||
if( !empty($shipData['ship']['typeId']) ){
|
||||
if(!empty($shipData['ship']['typeId'])){
|
||||
if(
|
||||
empty($logData['ship']['typeName']) ||
|
||||
$logData['ship']['typeId'] !== $shipData['ship']['typeId']
|
||||
@@ -980,7 +988,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
$invalidResponse = true;
|
||||
}
|
||||
|
||||
// get "more" data for shipTypeId ----------------------------------------------------
|
||||
// get "more" data for shipTypeId
|
||||
if($lookupShipTypeId > 0){
|
||||
/**
|
||||
* @var $typeModel Universe\TypeModel
|
||||
@@ -997,7 +1005,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
}
|
||||
}
|
||||
|
||||
if( !$deleteLog ){
|
||||
if(!$deleteLog){
|
||||
// mark log as "updated" even if no changes were made
|
||||
if($additionalOptions['markUpdated'] === true){
|
||||
$characterLog->touch('updated');
|
||||
@@ -1086,7 +1094,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
){
|
||||
$task = 'add';
|
||||
$mapIds = [];
|
||||
$historyLog = $characterLog->getDataAsArray();
|
||||
$historyLog = $characterLog::toArray($characterLog->getData());
|
||||
|
||||
if($logHistoryData = $this->getLogsHistory()){
|
||||
// skip logging if no relevant fields changed
|
||||
|
||||
@@ -14,8 +14,14 @@ use lib\logging;
|
||||
|
||||
class ConnectionModel extends AbstractMapTrackingModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'connection';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class CorporationMapModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'corporation_map';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
|
||||
@@ -13,6 +13,9 @@ use lib\Config;
|
||||
|
||||
class CorporationModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'corporation';
|
||||
|
||||
/**
|
||||
@@ -91,6 +94,9 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
'map_export'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -181,17 +187,19 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* get all maps for this corporation
|
||||
* @param array $mapIds
|
||||
* @param int|null $mapId
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
public function getMaps($mapIds = [], $options = []) : array {
|
||||
public function getMaps(?int $mapId = null, $options = []) : array {
|
||||
$maps = [];
|
||||
$this->filterRel();
|
||||
|
||||
if(!empty($mapIds)){
|
||||
$filters = [];
|
||||
$filters[] = ['mapId IN (:mapId)', ':mapId' => $mapIds];
|
||||
if($mapId){
|
||||
$filters = [
|
||||
self::getFilter('mapId', $mapId)
|
||||
];
|
||||
|
||||
$this->filter('mapCorporations', $this->mergeWithRelFilter('mapCorporations', $this->mergeFilter($filters)), $this->getRelFilterOption('mapCorporations'));
|
||||
}
|
||||
|
||||
@@ -217,7 +225,7 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
* @param array $options
|
||||
* @return CharacterModel[]
|
||||
*/
|
||||
public function getCharacters($characterIds = [], $options = []){
|
||||
public function getCharacters($characterIds = [], $options = []) : array {
|
||||
$characters = [];
|
||||
$filter = ['active = ?', 1];
|
||||
|
||||
@@ -244,30 +252,28 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* get all structure data for this corporation
|
||||
* @param array $systemIds
|
||||
* @param int $systemId
|
||||
* @return array
|
||||
*/
|
||||
public function getStructuresData(array $systemIds = []) : array {
|
||||
public function getStructuresData(int $systemId) : array {
|
||||
$structuresData = [];
|
||||
$structure = $this->rel('structures');
|
||||
|
||||
$this->filter('corporationStructures', ['active = ?', 1]);
|
||||
$this->has('corporationStructures.structureId', ['active = ?', 1]);
|
||||
$filters = [
|
||||
self::getFilter('corporationId', $this->id),
|
||||
self::getFilter('active', true)
|
||||
];
|
||||
|
||||
if($systemIds){
|
||||
if(count($systemIds) == 1){
|
||||
$filterSystems = 'systemId = ?';
|
||||
$filterSystemIds = reset($systemIds);
|
||||
}else{
|
||||
$filterSystems = 'systemId IN (?)';
|
||||
$filterSystemIds = $systemIds;
|
||||
}
|
||||
$structure->has('structureCorporations', $this->mergeFilter($filters));
|
||||
|
||||
$this->has('corporationStructures.structureId', [$filterSystems, $filterSystemIds]);
|
||||
}
|
||||
$filters = [
|
||||
self::getFilter('systemId', $systemId),
|
||||
self::getFilter('active', true)
|
||||
];
|
||||
|
||||
if($this->corporationStructures) {
|
||||
foreach($this->corporationStructures as $corporationStructure){
|
||||
$structuresData[] = $corporationStructure->structureId->getData();
|
||||
if($structures = $structure->find($this->mergeFilter($filters))){
|
||||
foreach($structures as $structure){
|
||||
$structuresData[] = $structure->getData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +357,7 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
if($this->isOutdated()){
|
||||
// request corporation data
|
||||
$corporationData = self::getF3()->ccpClient()->getCorporationData($id);
|
||||
if( !empty($corporationData) ){
|
||||
if(!empty($corporationData) && !isset($corporationData['error'])){
|
||||
// check for NPC corporation
|
||||
$corporationData['isNPC'] = self::getF3()->ccpClient()->isNpcCorporation($id);
|
||||
|
||||
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class CorporationStructureModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'corporation_structure';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
|
||||
@@ -17,6 +17,9 @@ use lib\logging;
|
||||
|
||||
class MapModel extends AbstractMapTrackingModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'map';
|
||||
|
||||
/**
|
||||
@@ -27,6 +30,9 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
const ERROR_SLACK_CHANNEL = 'Invalid #Slack channel column [%s]';
|
||||
const ERROR_DISCORD_CHANNEL = 'Invalid #Discord channel column [%s]';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -98,6 +104,12 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
'default' => 1,
|
||||
'activity-log' => true
|
||||
],
|
||||
'trackAbyssalJumps' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'activity-log' => true
|
||||
],
|
||||
'logActivity' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
@@ -223,6 +235,7 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
$mapData->deleteEolConnections = $this->deleteEolConnections;
|
||||
$mapData->persistentAliases = $this->persistentAliases;
|
||||
$mapData->persistentSignatures = $this->persistentSignatures;
|
||||
$mapData->trackAbyssalJumps = $this->trackAbyssalJumps;
|
||||
|
||||
// map scope
|
||||
$mapData->scope = (object) [];
|
||||
@@ -563,41 +576,37 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* get either all system models in this map
|
||||
* @return SystemModel[]
|
||||
* get systems in this map
|
||||
* @return CortexCollection|array
|
||||
*/
|
||||
protected function getSystems(){
|
||||
$systems = [];
|
||||
$filters = [
|
||||
self::getFilter('active', true)
|
||||
];
|
||||
|
||||
// orderBy x-Coordinate for smoother frontend animation (left to right)
|
||||
$this->filter('systems', ['active = 1'],
|
||||
['order' => 'posX']
|
||||
);
|
||||
|
||||
if($this->systems){
|
||||
$systems = $this->systems;
|
||||
}
|
||||
|
||||
return $systems;
|
||||
return $this->relFind('systems', $this->mergeFilter($filters)) ? : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* get all system data for all systems in this map
|
||||
* @return \stdClass[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getSystemsData() : array{
|
||||
$systemData = [];
|
||||
$systems = $this->getSystems();
|
||||
public function getSystemsData() : array {
|
||||
$systemsData = [];
|
||||
|
||||
foreach($systems as $system){
|
||||
foreach($this->getSystems() as $system){
|
||||
/**
|
||||
* @var $system SystemModel
|
||||
*/
|
||||
$systemData[] = $system->getData();
|
||||
$systemsData[] = $system->getData();
|
||||
}
|
||||
|
||||
return $systemData;
|
||||
// orderBy x-Coordinate for smoother frontend animation (left to right)
|
||||
usort($systemsData, function($sysDataA, $sysDataB){
|
||||
return $sysDataA->position->x <=> $sysDataB->position->x;
|
||||
});
|
||||
|
||||
return $systemsData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -650,25 +659,24 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public function getConnectionsData() : array {
|
||||
$connectionData = [];
|
||||
$connections = $this->getConnections();
|
||||
$connectionsData = [];
|
||||
|
||||
foreach($connections as $connection){
|
||||
foreach($this->getConnections() as $connection){
|
||||
/**
|
||||
* @var $connection ConnectionModel
|
||||
*/
|
||||
$connectionData[] = $connection->getData(true);
|
||||
$connectionsData[] = $connection->getData(true);
|
||||
}
|
||||
|
||||
return $connectionData;
|
||||
return $connectionsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all structures data for this map
|
||||
* @param array $systemIds
|
||||
* @param int $systemId
|
||||
* @return array
|
||||
*/
|
||||
public function getStructuresData(array $systemIds = []) : array {
|
||||
public function getStructuresData(int $systemId) : array {
|
||||
$structuresData = [];
|
||||
$corporations = $this->getAllCorporations();
|
||||
|
||||
@@ -676,7 +684,7 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
// corporations should be unique
|
||||
if( !isset($structuresData[$corporation->_id]) ){
|
||||
// get all structures for current corporation
|
||||
$corporationStructuresData = $corporation->getStructuresData($systemIds);
|
||||
$corporationStructuresData = $corporation->getStructuresData($systemId);
|
||||
if( !empty($corporationStructuresData) ){
|
||||
// corporation has structures
|
||||
$structuresData[$corporation->_id] = [
|
||||
@@ -819,11 +827,6 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
$characters = [];
|
||||
$filter = ['active = ?', 1];
|
||||
|
||||
if( !empty($characterIds) ){
|
||||
$filter[0] .= ' AND id IN (?)';
|
||||
$filter[] = $characterIds;
|
||||
}
|
||||
|
||||
$this->filter('mapCharacters', $filter);
|
||||
|
||||
if($this->mapCharacters){
|
||||
@@ -839,7 +842,7 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
* get corporations that have access to this map
|
||||
* @return CorporationModel[]
|
||||
*/
|
||||
public function getCorporations() : array {
|
||||
private function getCorporations() : array {
|
||||
$corporations = [];
|
||||
|
||||
if($this->isCorporation()){
|
||||
@@ -847,7 +850,7 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
|
||||
if($this->mapCorporations){
|
||||
foreach($this->mapCorporations as $mapCorporation){
|
||||
$corporations[] = $mapCorporation->corporationId;
|
||||
$corporations[$mapCorporation->corporationId->_id] = $mapCorporation->corporationId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class RightModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'right';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -24,7 +30,9 @@ class RightModel extends AbstractPathfinderModel {
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
'default' => '',
|
||||
'index' => true,
|
||||
'unique' => true
|
||||
],
|
||||
'label' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
@@ -41,6 +49,9 @@ class RightModel extends AbstractPathfinderModel {
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $tableData = [
|
||||
[
|
||||
'id' => 1,
|
||||
|
||||
@@ -19,11 +19,6 @@ class StructureModel extends AbstractPathfinderModel {
|
||||
*/
|
||||
protected $table = 'structure';
|
||||
|
||||
/**
|
||||
* categoryId (from ESI) that holds all "groups" with structure "types"
|
||||
*/
|
||||
const CATEGORY_STRUCTURE_ID = 65;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -130,15 +125,15 @@ class StructureModel extends AbstractPathfinderModel {
|
||||
/**
|
||||
* set corporationId (owner) for this structure
|
||||
* -> if corporation does not exists in DB -> load from API
|
||||
* @param int $corporationId
|
||||
* @param int|null $corporationId
|
||||
* @return int|null
|
||||
*/
|
||||
public function set_corporationId(int $corporationId) : ?int {
|
||||
public function set_corporationId(?int $corporationId) : ?int {
|
||||
$oldCorporationId = $this->get('corporationId', true) ? : 0;
|
||||
|
||||
if($corporationId){
|
||||
if($corporationId !== $oldCorporationId){
|
||||
// make sure there is already corporation data stored for new corporationId
|
||||
// make sure there is already corporation data available for new corporationId
|
||||
/**
|
||||
* @var CorporationModel $corporation
|
||||
*/
|
||||
@@ -156,26 +151,20 @@ class StructureModel extends AbstractPathfinderModel {
|
||||
}
|
||||
/**
|
||||
* validates systemId
|
||||
* -> a structure always belongs to the same system
|
||||
* @param string $key
|
||||
* @param string $val
|
||||
* @return bool
|
||||
*/
|
||||
protected function validate_systemId(string $key, string $val): bool {
|
||||
$valid = true;
|
||||
|
||||
if( !$this->dry() && $this->systemId !== (int)$val ){
|
||||
// structure always belongs to the same system
|
||||
$valid = false;
|
||||
}
|
||||
|
||||
return $valid;
|
||||
protected function validate_systemId(string $key, string $val) : bool {
|
||||
return !($this->valid() && $this->systemId !== (int)$val);
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether this model is valid or not
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid(): bool {
|
||||
public function isValid() : bool {
|
||||
if($valid = parent::isValid()){
|
||||
// structure always belongs to a systemId
|
||||
if(!(int)$this->systemId){
|
||||
@@ -244,7 +233,7 @@ class StructureModel extends AbstractPathfinderModel {
|
||||
* @param string $name
|
||||
* @param int $systemId
|
||||
*/
|
||||
public function getByName(CorporationModel $corporation, string $name, int $systemId) {
|
||||
public function getByName(CorporationModel $corporation, string $name, int $systemId){
|
||||
if( !$corporation->dry() && $name){
|
||||
$this->has('structureCorporations', ['corporationId = :corporationId', ':corporationId' => $corporation->_id]);
|
||||
$this->load(['name = :name AND systemId = :systemId AND active = :active',
|
||||
|
||||
@@ -13,8 +13,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class StructureStatusModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'structure_status';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -42,6 +48,9 @@ class StructureStatusModel extends AbstractPathfinderModel {
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $tableData = [
|
||||
[
|
||||
'id' => 1,
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Model\Pathfinder;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
use lib\logging;
|
||||
use lib\PriorityCacheStore;
|
||||
use Controller\Ccp\Universe;
|
||||
|
||||
class SystemModel extends AbstractMapTrackingModel {
|
||||
@@ -39,16 +40,16 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
*/
|
||||
const DATA_CACHE_KEY_SIGNATURES_HISTORY = 'HISTORY_SIGNATURES';
|
||||
|
||||
/**
|
||||
* @var PriorityCacheStore
|
||||
*/
|
||||
protected static $priorityCacheStore;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'system';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $staticSystemDataCache = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -161,80 +162,79 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
/**
|
||||
* get map data as object
|
||||
* @return \stdClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getData(){
|
||||
|
||||
// check if there is cached data
|
||||
$systemData = $this->getCacheData();
|
||||
|
||||
if(is_null($systemData)){
|
||||
// no cached system data found
|
||||
|
||||
$systemData = (object) [];
|
||||
$systemData->id = $this->_id;
|
||||
$systemData->mapId = is_object($this->mapId) ? $this->get('mapId', true) : 0;
|
||||
$systemData->systemId = $this->systemId;
|
||||
$systemData->alias = $this->alias;
|
||||
if(is_null($data = $this->getCacheData())){
|
||||
$data = (object) [];
|
||||
$data->id = $this->_id;
|
||||
$data->mapId = is_object($this->mapId) ? $this->get('mapId', true) : 0;
|
||||
$data->systemId = $this->systemId;
|
||||
$data->alias = $this->alias;
|
||||
|
||||
if(is_object($this->typeId)){
|
||||
$systemData->type = $this->typeId->getData();
|
||||
$data->type = $this->typeId->getData();
|
||||
}
|
||||
|
||||
if(is_object($this->statusId)){
|
||||
$systemData->status = $this->statusId->getData();
|
||||
$data->status = $this->statusId->getData();
|
||||
}
|
||||
|
||||
$systemData->locked = $this->locked;
|
||||
$systemData->rallyUpdated = strtotime($this->rallyUpdated);
|
||||
$systemData->rallyPoke = $this->rallyPoke;
|
||||
$systemData->description = $this->description ? : '';
|
||||
$data->locked = $this->locked;
|
||||
$data->drifter = $this->isDrifter();
|
||||
$data->rallyUpdated = strtotime($this->rallyUpdated);
|
||||
$data->rallyPoke = $this->rallyPoke;
|
||||
$data->description = $this->description ? : '';
|
||||
|
||||
$systemData->position = (object) [];
|
||||
$systemData->position->x = $this->posX;
|
||||
$systemData->position->y = $this->posY;
|
||||
$data->position = (object) [];
|
||||
$data->position->x = $this->posX;
|
||||
$data->position->y = $this->posY;
|
||||
|
||||
$systemData->created = (object) [];
|
||||
$systemData->created->created = strtotime($this->created);
|
||||
$data->created = (object) [];
|
||||
$data->created->created = strtotime($this->created);
|
||||
if(is_object($this->createdCharacterId)){
|
||||
$systemData->created->character = $this->createdCharacterId->getData();
|
||||
$data->created->character = $this->createdCharacterId->getData();
|
||||
}
|
||||
|
||||
$systemData->updated = (object) [];
|
||||
$systemData->updated->updated = strtotime($this->updated);
|
||||
$data->updated = (object) [];
|
||||
$data->updated->updated = strtotime($this->updated);
|
||||
if(is_object($this->updatedCharacterId)){
|
||||
$systemData->updated->character = $this->updatedCharacterId->getData();
|
||||
$data->updated->character = $this->updatedCharacterId->getData();
|
||||
}
|
||||
|
||||
// static system data -------------------------------------------------------------------------------------
|
||||
$systemData->name = $this->name;
|
||||
$systemData->security = $this->security;
|
||||
$systemData->trueSec = $this->trueSec;
|
||||
$systemData->effect = $this->effect;
|
||||
$systemData->shattered = $this->shattered;
|
||||
$data->name = $this->name;
|
||||
$data->security = $this->security;
|
||||
$data->trueSec = $this->trueSec;
|
||||
$data->effect = $this->effect;
|
||||
$data->shattered = $this->shattered;
|
||||
|
||||
$systemData->constellation = (object) [];
|
||||
$systemData->constellation->id = $this->constellationId;
|
||||
$systemData->constellation->name = $this->constellation;
|
||||
$data->constellation = (object) [];
|
||||
$data->constellation->id = $this->constellationId;
|
||||
$data->constellation->name = $this->constellation;
|
||||
|
||||
$systemData->region = (object) [];
|
||||
$systemData->region->id = $this->regionId;
|
||||
$systemData->region->name = $this->region;
|
||||
$data->region = (object) [];
|
||||
$data->region->id = $this->regionId;
|
||||
$data->region->name = $this->region;
|
||||
|
||||
$systemData->planets = $this->planets ? : [];
|
||||
$systemData->statics = $this->statics ? : [];
|
||||
$data->planets = $this->planets ? : [];
|
||||
$data->statics = $this->statics ? : [];
|
||||
|
||||
if(is_object($this->faction)){
|
||||
$systemData->faction = $this->faction;
|
||||
if(is_object($sovereignty = $this->sovereignty)){
|
||||
$data->sovereignty = $sovereignty;
|
||||
}
|
||||
|
||||
if(is_object($factionWar = $this->factionWar)){
|
||||
$data->factionWar = $factionWar;
|
||||
}
|
||||
|
||||
// max caching time for a system
|
||||
// the cached date has to be cleared manually on any change
|
||||
// this includes system, connection,... changes (all dependencies)
|
||||
$this->updateCacheData($systemData);
|
||||
$this->updateCacheData($data);
|
||||
}
|
||||
|
||||
return $systemData;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,14 +244,19 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
*/
|
||||
private function getStaticSystemData(){
|
||||
$staticData = null;
|
||||
if( !empty($this->staticSystemDataCache[$this->systemId]) ){
|
||||
$staticData = $this->staticSystemDataCache[$this->systemId];
|
||||
if(!is_object(self::$priorityCacheStore)){
|
||||
self::$priorityCacheStore = new PriorityCacheStore();
|
||||
}
|
||||
|
||||
if(self::$priorityCacheStore->exists($this->systemId)){
|
||||
$staticData = self::$priorityCacheStore->get($this->systemId);
|
||||
}else{
|
||||
$staticData = (new Universe())->getSystemData($this->systemId);
|
||||
if($staticData){
|
||||
$this->staticSystemDataCache = [$this->systemId => $staticData];
|
||||
self::$priorityCacheStore->set($this->systemId, $staticData);
|
||||
}
|
||||
}
|
||||
|
||||
return $staticData;
|
||||
}
|
||||
|
||||
@@ -435,10 +440,6 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
return ($constellationData && $constellationData->region) ? $constellationData->region->name : null;
|
||||
}
|
||||
|
||||
public function get_faction(){
|
||||
return $this->getStaticSystemValue('faction');
|
||||
}
|
||||
|
||||
public function get_security(){
|
||||
return $this->getStaticSystemValue('security');
|
||||
}
|
||||
@@ -463,6 +464,18 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
return $this->getStaticSystemValue('planets');
|
||||
}
|
||||
|
||||
public function get_stations(){
|
||||
return $this->getStaticSystemValue('stations');
|
||||
}
|
||||
|
||||
public function get_sovereignty(){
|
||||
return $this->getStaticSystemValue('sovereignty');
|
||||
}
|
||||
|
||||
public function get_factionWar(){
|
||||
return $this->getStaticSystemValue('factionWar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* @param self $self
|
||||
@@ -652,7 +665,15 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public function getStructuresData() : array {
|
||||
return $this->getMap()->getStructuresData([$this->systemId]);
|
||||
return $this->getMap()->getStructuresData($this->systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* get data for all stations in this system
|
||||
* @return array
|
||||
*/
|
||||
public function getStationsData() : array {
|
||||
return $this->stations ? : [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -679,6 +700,14 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
return ($this->typeId->id === 3 && $this->security === 'A');
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether this system is in drifter-space
|
||||
* @return bool
|
||||
*/
|
||||
public function isDrifter() : bool {
|
||||
return in_array($this->security, ['C14', 'C15', 'C16', 'C17', 'C18']);
|
||||
}
|
||||
|
||||
/**
|
||||
* send rally point poke to various "APIs"
|
||||
* -> send to a Slack channel
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 24.12.2015
|
||||
* Time: 00:59
|
||||
*/
|
||||
|
||||
namespace Model\Pathfinder;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class SystemNeighbourModel extends AbstractPathfinderModel {
|
||||
|
||||
protected $table = 'system_neighbour';
|
||||
|
||||
protected $fieldConf = [
|
||||
'regionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'constellationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'systemName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'default' => ''
|
||||
],
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'jumpNodes' => [
|
||||
'type' => Schema::DT_VARCHAR512,
|
||||
'default' => ''
|
||||
],
|
||||
'trueSec' => [
|
||||
'type' => Schema::DT_DECIMAL,
|
||||
'default' => 0
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* No static columns added
|
||||
* @var bool
|
||||
*/
|
||||
protected $addStaticFields = false;
|
||||
}
|
||||
@@ -13,8 +13,14 @@ use lib\logging;
|
||||
|
||||
class SystemSignatureModel extends AbstractMapTrackingModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'system_signature';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -278,6 +284,13 @@ class SystemSignatureModel extends AbstractMapTrackingModel {
|
||||
*/
|
||||
public function afterEraseEvent($self, $pkeys){
|
||||
$self->logActivity('signatureDelete');
|
||||
|
||||
if(
|
||||
$self->connectionIdDeleteCascade === true &&
|
||||
($connection = $self->getConnection())
|
||||
){
|
||||
$connection->erase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class SystemTypeModel extends AbstractPathfinderModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'system_type';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
@@ -28,6 +34,9 @@ class SystemTypeModel extends AbstractPathfinderModel {
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $tableData = [
|
||||
[
|
||||
'id' => 1,
|
||||
|
||||
@@ -202,16 +202,15 @@ class UserModel extends AbstractPathfinderModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* get current character data from session
|
||||
* get current character from session data
|
||||
* -> if $characterId == 0 -> get first character data (random)
|
||||
* @param int $characterId
|
||||
* @param bool $objectCheck
|
||||
* @return array
|
||||
* @param int $ttl
|
||||
* @return CharacterModel|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getSessionCharacterData($characterId = 0, $objectCheck = true) : array {
|
||||
public function getSessionCharacter(int $characterId = 0, int $ttl = self::DEFAULT_SQL_TTL) : ?CharacterModel {
|
||||
$data = [];
|
||||
$characterId = (int)$characterId;
|
||||
$currentSessionUser = (array)$this->getF3()->get(User::SESSION_KEY_USER);
|
||||
|
||||
if($this->_id === $currentSessionUser['ID']){
|
||||
@@ -228,28 +227,22 @@ class UserModel extends AbstractPathfinderModel {
|
||||
}
|
||||
}
|
||||
|
||||
if(
|
||||
$objectCheck === true &&
|
||||
!empty($data)
|
||||
){
|
||||
if($characterId = (int)$data['ID']){
|
||||
// check if character still exists on DB (e.g. was manually removed in the meantime)
|
||||
// -> This should NEVER happen just for security and "local development"
|
||||
/**
|
||||
* @var $character CharacterModel
|
||||
*/
|
||||
$character = AbstractPathfinderModel::getNew('CharacterModel');
|
||||
$character->getById((int)$data['ID']);
|
||||
$character->getById($characterId, $ttl);
|
||||
|
||||
if(
|
||||
$character->dry() ||
|
||||
!$character->hasUserCharacter()
|
||||
){
|
||||
// character data is invalid!
|
||||
$data = [];
|
||||
if($character->valid() && $character->hasUserCharacter()){
|
||||
// character data is valid!
|
||||
return $character;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,10 +252,9 @@ class UserModel extends AbstractPathfinderModel {
|
||||
*/
|
||||
public function findSessionCharacterData(int $characterId) : array {
|
||||
$data = [];
|
||||
if($characterId){
|
||||
$sessionCharacters = (array)$this->getF3()->get(User::SESSION_KEY_CHARACTERS);
|
||||
if($characterId && $this->getF3()->exists(User::SESSION_KEY_CHARACTERS, $sessionCharacters)){
|
||||
// search for specific characterData
|
||||
foreach($sessionCharacters as $characterData){
|
||||
foreach((array)$sessionCharacters as $characterData){
|
||||
if($characterId === (int)$characterData['ID']){
|
||||
$data = $characterData;
|
||||
break;
|
||||
|
||||
@@ -20,7 +20,7 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const CACHE_KEY_PREFIX = 'index_universe_';
|
||||
const CACHE_KEY_PREFIX = parent::CACHE_KEY_PREFIX . '_' . self::DB_ALIAS;
|
||||
|
||||
/**
|
||||
* cache key for model data -> should "never" expire
|
||||
@@ -36,6 +36,21 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for positions array (x/y/z)
|
||||
* @param $position
|
||||
* @return null
|
||||
*/
|
||||
public function set_position($position){
|
||||
$position = (array)$position;
|
||||
if(count($position) === 3){
|
||||
$this->x = $position['x'];
|
||||
$this->y = $position['y'];
|
||||
$this->z = $position['z'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
@@ -46,7 +61,7 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
public function beforeUpdateEvent($self, $pkeys) : bool {
|
||||
// if model changed, 'update' col needs to be updated as well
|
||||
// -> data no longer "outdated"
|
||||
$this->touch('updated');
|
||||
$self->touch('updated');
|
||||
|
||||
return parent::beforeUpdateEvent($self, $pkeys);
|
||||
}
|
||||
@@ -59,7 +74,7 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
*/
|
||||
public function getHashKey(string $column = '_id'){
|
||||
$key = false;
|
||||
if( !$this->dry() && $this->exists($column) ){
|
||||
if($this->valid() && $this->exists($column)){
|
||||
$key = self::generateHashKeyRow($this->getTable(), $this->$column);
|
||||
}
|
||||
return $key;
|
||||
@@ -110,21 +125,6 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* add $rowKeys (hashKeys) to a search index that holds all rowKeys of a table
|
||||
* @param AbstractUniverseModel $model
|
||||
* @param array $rowKeys
|
||||
*/
|
||||
public static function buildTableIndex(AbstractUniverseModel $model, array $rowKeys = []){
|
||||
$hashKeyTable = self::generateHashKeyTable($model->getTable());
|
||||
if( !self::getF3()->exists($hashKeyTable, $cachedData) ){
|
||||
$cachedData = [];
|
||||
}
|
||||
$cachedData = array_unique(array_merge($cachedData, $rowKeys));
|
||||
|
||||
self::getF3()->set($hashKeyTable, $cachedData, self::CACHE_INDEX_EXPIRE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* get data from "search" index for this model
|
||||
* -> if data not found -> try to build up index for this model
|
||||
@@ -166,6 +166,45 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
*/
|
||||
abstract protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []);
|
||||
|
||||
/**
|
||||
* convert CCPs ids for system security into Pathfinder security label
|
||||
* -> used e.g. in "Dogma Attributes" (wormholeTargetSystemClass) for wormhole types
|
||||
* @param int $id
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getSystemSecurityFromId(int $id) : ?string {
|
||||
$security = null;
|
||||
if(
|
||||
($id >= 1 && $id <= 6) ||
|
||||
($id >= 12 && $id <= 18)
|
||||
){
|
||||
$security = 'C' . $id;
|
||||
}elseif($id == 7){
|
||||
$security = 'H';
|
||||
}elseif($id == 8){
|
||||
$security = 'L';
|
||||
}elseif($id == 9){
|
||||
$security = '0.0';
|
||||
}
|
||||
|
||||
return $security;
|
||||
}
|
||||
|
||||
/**
|
||||
* add $rowKeys (hashKeys) to a search index that holds all rowKeys of a table
|
||||
* @param AbstractUniverseModel $model
|
||||
* @param array $rowKeys
|
||||
*/
|
||||
public static function buildTableIndex(AbstractUniverseModel $model, array $rowKeys = []){
|
||||
$hashKeyTable = static::generateHashKeyTable($model->getTable());
|
||||
if( !self::getF3()->exists($hashKeyTable, $cachedData) ){
|
||||
$cachedData = [];
|
||||
}
|
||||
$cachedData = array_unique(array_merge($cachedData, $rowKeys));
|
||||
|
||||
self::getF3()->set($hashKeyTable, $cachedData, self::CACHE_INDEX_EXPIRE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate hashKey for a table row data for search index build
|
||||
* @param string $table
|
||||
@@ -173,16 +212,17 @@ abstract class AbstractUniverseModel extends AbstractModel {
|
||||
* @return string
|
||||
*/
|
||||
public static function generateHashKeyRow(string $table, $value) : string {
|
||||
return self::generateHashKeyTable($table) . '_' . md5(strtolower((string)$value));
|
||||
return static::generateHashKeyTable($table) . '_' . md5(strtolower((string)$value));
|
||||
}
|
||||
|
||||
/**
|
||||
* generate hashKey for a complete table
|
||||
* -> should hold hashKeys for multiple rows
|
||||
* @param string $table
|
||||
* @param string $prefix
|
||||
* @return string
|
||||
*/
|
||||
public static function generateHashKeyTable(string $table) : string {
|
||||
return self::CACHE_KEY_PREFIX . strtolower($table);
|
||||
public static function generateHashKeyTable(string $table, string $prefix = self::CACHE_KEY_PREFIX) : string {
|
||||
return parent::generateHashKeyTable($table, $prefix);
|
||||
}
|
||||
}
|
||||
103
app/main/model/universe/alliancemodel.php
Normal file
103
app/main/model/universe/alliancemodel.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class AllianceModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'alliance';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'ticker' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'dateFounded' => [
|
||||
'type' => Schema::DT_DATETIME,
|
||||
'default' => null
|
||||
],
|
||||
'factionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'SET NULL'
|
||||
]
|
||||
]
|
||||
],
|
||||
'corporations' => [
|
||||
'has-many' => ['Model\Universe\CorporationModel', 'allianceId']
|
||||
],
|
||||
'sovereigntySystems' => [
|
||||
'has-many' => ['Model\Universe\SovereigntyMapModel', 'allianceId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$data = (object) [];
|
||||
$data->id = $this->_id;
|
||||
$data->name = $this->name;
|
||||
$data->ticker = $this->ticker;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $date
|
||||
* @return string|null
|
||||
*/
|
||||
public function set_dateFounded($date){
|
||||
if(is_string($date) && !empty($date)){
|
||||
try{
|
||||
$dateTime = new \DateTime($date);
|
||||
$date = $dateTime->format('Y-m-d H:i:s');
|
||||
}catch(\Exception $e){
|
||||
$date = null;
|
||||
}
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* load alliance by Id either from DB or load data from API
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getAllianceData($id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
if($data['factionId']){
|
||||
/**
|
||||
* @var $faction FactionModel
|
||||
*/
|
||||
$faction = $this->rel('factionId');
|
||||
$faction->loadById($data['factionId'], $accessToken, $additionalOptions);
|
||||
$data['factionId'] = $faction;
|
||||
}
|
||||
|
||||
$this->copyfrom($data, ['id', 'name', 'ticker', 'dateFounded', 'factionId']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function getData(array $additionalData = []){
|
||||
$categoryData = (object) [];
|
||||
$categoryData->id = $this->id;
|
||||
$categoryData->id = $this->_id;
|
||||
$categoryData->name = $this->name;
|
||||
|
||||
if($groupsData = $this->getGroupsData($additionalData)){
|
||||
@@ -77,6 +77,9 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
$groupsData = [];
|
||||
$groups = $this->getGroups();
|
||||
|
||||
/**
|
||||
* @var $group GroupModel
|
||||
*/
|
||||
foreach($groups as $group){
|
||||
$groupsData[] = $group->getData($additionalData);
|
||||
}
|
||||
@@ -84,6 +87,15 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
return $groupsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get groups count
|
||||
* @param bool $published
|
||||
* @return int
|
||||
*/
|
||||
public function getGroupsCount(bool $published = true) : int {
|
||||
return $this->valid() ? count($this->getGroups($published)) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* count all types that belong to groups in this category
|
||||
* @param bool $published
|
||||
@@ -91,7 +103,7 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function getTypesCount(bool $published = true) : int {
|
||||
$count = 0;
|
||||
if( !$this->dry() ){
|
||||
if($this->valid()){
|
||||
/**
|
||||
* @var $group GroupModel
|
||||
*/
|
||||
@@ -109,8 +121,7 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseCategoryData($id);
|
||||
if(!empty($data)){
|
||||
if(!empty($data = self::getUniverseCategoryData($id))){
|
||||
$this->copyfrom($data, ['id', 'name', 'published']);
|
||||
$this->save();
|
||||
}
|
||||
@@ -123,25 +134,71 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
* @return array
|
||||
*/
|
||||
public function loadGroupsData(int $offset = 0, int $length = 0) : array {
|
||||
$groupIds = [];
|
||||
if( !$this->dry() ){
|
||||
$data = self::getF3()->ccpClient()->getUniverseCategoryData($this->_id);
|
||||
if(!empty($data)){
|
||||
array_multisort($data['groups'], SORT_ASC, SORT_NUMERIC);
|
||||
if($length){
|
||||
$data['groups'] = array_slice($data['groups'], $offset, $length);
|
||||
}
|
||||
foreach($data['groups'] as $groupId){
|
||||
/**
|
||||
* @var $group GroupModel
|
||||
*/
|
||||
$group = $this->rel('groups');
|
||||
$group->loadById($groupId);
|
||||
$groupIds[] = $groupId;
|
||||
$group->reset();
|
||||
}
|
||||
$info = ['countAll' => 0, 'countChunk' => 0, 'count' => 0, 'offset' => $offset, 'groupTypes' => []];
|
||||
|
||||
if(
|
||||
$this->valid() &&
|
||||
!empty($data = self::getUniverseCategoryData($this->_id))
|
||||
){
|
||||
$info['countAll'] = count($data['groups']);
|
||||
|
||||
array_multisort($data['groups'], SORT_ASC, SORT_NUMERIC);
|
||||
if($length){
|
||||
$data['groups'] = array_slice($data['groups'], $offset, $length);
|
||||
}
|
||||
|
||||
$info['countChunk'] = count($data['groups']);
|
||||
foreach($data['groups'] as $groupId){
|
||||
/**
|
||||
* @var $group GroupModel
|
||||
*/
|
||||
$group = $this->rel('groups');
|
||||
$group->loadById($groupId);
|
||||
|
||||
$info['groupTypes'][$groupId] = $group->loadTypesData();
|
||||
|
||||
$group->reset();
|
||||
|
||||
$info['count']++;
|
||||
$info['offset']++;
|
||||
}
|
||||
}
|
||||
return $groupIds;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseCategoryData(int $id) : array {
|
||||
return self::getF3()->ccpClient()->getUniverseCategoryData($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseCategories() : array {
|
||||
return self::getF3()->ccpClient()->getUniverseCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseCategoryGroups(int $id) : array {
|
||||
return empty($data = self::getUniverseCategoryData($id)) ? [] : $data['groups'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseCategoryTypes(int $id) : array {
|
||||
$types = [];
|
||||
foreach($groupIds = self::getUniverseCategoryGroups($id) as $groupId){
|
||||
$types[$groupId] = GroupModel::getUniverseGroupTypes($groupId);
|
||||
}
|
||||
return $types;
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,9 @@ class ConstellationModel extends AbstractUniverseModel {
|
||||
],
|
||||
'systems' => [
|
||||
'has-many' => ['Model\Universe\SystemModel', 'constellationId']
|
||||
],
|
||||
'systemNeighbours' => [
|
||||
'has-many' => ['Model\Universe\SystemNeighbourModel', 'constellationId']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -71,21 +74,6 @@ class ConstellationModel extends AbstractUniverseModel {
|
||||
return $constellationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for positions array (x/y/z)
|
||||
* @param $position
|
||||
* @return null
|
||||
*/
|
||||
public function set_position($position){
|
||||
$position = (array)$position;
|
||||
if(count($position) === 3){
|
||||
$this->x = $position['x'];
|
||||
$this->y = $position['y'];
|
||||
$this->z = $position['z'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
|
||||
135
app/main/model/universe/corporationmodel.php
Normal file
135
app/main/model/universe/corporationmodel.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class CorporationModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'corporation';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'ticker' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'dateFounded' => [
|
||||
'type' => Schema::DT_DATETIME,
|
||||
'default' => null
|
||||
],
|
||||
'memberCount' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'isNPC' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'factionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'SET NULL'
|
||||
]
|
||||
]
|
||||
],
|
||||
'allianceId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\AllianceModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'alliance',
|
||||
'on-delete' => 'SET NULL'
|
||||
]
|
||||
]
|
||||
],
|
||||
'sovereigntySystems' => [
|
||||
'has-many' => ['Model\Universe\SovereigntyMapModel', 'corporationId']
|
||||
],
|
||||
'stations' => [
|
||||
'has-many' => ['Model\Universe\StationModel', 'corporationId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$data = (object) [];
|
||||
$data->id = $this->_id;
|
||||
$data->name = $this->name;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $date
|
||||
* @return string|null
|
||||
*/
|
||||
public function set_dateFounded($date){
|
||||
if(is_string($date) && !empty($date)){
|
||||
try{
|
||||
$dateTime = new \DateTime($date);
|
||||
$date = $dateTime->format('Y-m-d H:i:s');
|
||||
}catch(\Exception $e){
|
||||
$date = null;
|
||||
}
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* load corporation by Id either from DB or load data from API
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getCorporationData($id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
// check for NPC corporation
|
||||
$data['isNPC'] = self::getF3()->ccpClient()->isNpcCorporation($id);
|
||||
|
||||
if($data['factionId']){
|
||||
/**
|
||||
* @var $faction FactionModel
|
||||
*/
|
||||
$faction = $this->rel('factionId');
|
||||
$faction->loadById($data['factionId'], $accessToken, $additionalOptions);
|
||||
$data['factionId'] = $faction;
|
||||
}
|
||||
|
||||
if($data['allianceId']){
|
||||
/**
|
||||
* @var $alliance AllianceModel
|
||||
*/
|
||||
$alliance = $this->rel('allianceId');
|
||||
$alliance->loadById($data['allianceId'], $accessToken, $additionalOptions);
|
||||
$data['allianceId'] = $alliance;
|
||||
}
|
||||
|
||||
$this->copyfrom($data, ['id', 'name', 'ticker', 'dateFounded', 'memberCount', 'isNPC', 'factionId', 'allianceId']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
97
app/main/model/universe/dogmaattributemodel.php
Normal file
97
app/main/model/universe/dogmaattributemodel.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus4D
|
||||
* Date: 15.08.2019
|
||||
* Time: 22:00
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class DogmaAttributeModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'dogma_attribute';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'displayName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'description' => [
|
||||
'type' => Schema::DT_TEXT
|
||||
],
|
||||
'published' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'stackable' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'highIsGood' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'defaultValue' => [
|
||||
'type' => Schema::DT_FLOAT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'iconId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'unitId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'attributeTypes' => [
|
||||
'has-many' => ['Model\Universe\TypeAttributeModel', 'attributeId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$attributeData = (object) [];
|
||||
$attributeData->id = $this->_id;
|
||||
$attributeData->name = $this->name;
|
||||
$attributeData->description = $this->description;
|
||||
|
||||
return $attributeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getDogmaAttributeData($id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
$this->copyfrom($data, ['id', 'name', 'displayName', 'description', 'published', 'stackable', 'highIsGood', 'defaultValue', 'iconId', 'unitId']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,8 +46,23 @@ class FactionModel extends AbstractUniverseModel {
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'systems' => [
|
||||
'has-many' => ['Model\Universe\SystemModel', 'factionId']
|
||||
'race' => [ // faction API endpoint dont have "raceId" data, but race API endpoint has
|
||||
'has-one' => ['Model\Universe\RaceModel', 'factionId']
|
||||
],
|
||||
'alliances' => [
|
||||
'has-many' => ['Model\Universe\AllianceModel', 'factionId']
|
||||
],
|
||||
'corporations' => [
|
||||
'has-many' => ['Model\Universe\CorporationModel', 'factionId']
|
||||
],
|
||||
'sovereigntySystems' => [
|
||||
'has-many' => ['Model\Universe\SovereigntyMapModel', 'factionId']
|
||||
],
|
||||
'factionWarSystemOwners' => [
|
||||
'has-many' => ['Model\Universe\FactionWarSystemModel', 'ownerFactionId']
|
||||
],
|
||||
'factionWarSystemOccupiers' => [
|
||||
'has-many' => ['Model\Universe\FactionWarSystemModel', 'occupierFactionId']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -70,7 +85,7 @@ class FactionModel extends AbstractUniverseModel {
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseFactionData($id);
|
||||
if(!empty($data)){
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
$this->copyfrom($data, ['id', 'name', 'description', 'sizeFactor', 'stationCount', 'stationSystemCount']);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
120
app/main/model/universe/factionwarsystemmodel.php
Normal file
120
app/main/model/universe/factionwarsystemmodel.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class FactionWarSystemModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'faction_war_system';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'unique' => true,
|
||||
'belongs-to-one' => 'Model\Universe\SystemModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'ownerFactionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'occupierFactionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'contested' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'victoryPoints' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'victoryPointsThreshold' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* No static columns added
|
||||
* @var bool
|
||||
*/
|
||||
protected $addStaticFields = false;
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$data = (object) [];
|
||||
$data->contested = $this->contested;
|
||||
|
||||
if($this->ownerFactionId){
|
||||
$data->ownerFaction = $this->ownerFactionId->getData();
|
||||
$data->victoryPercentage = $this->getVictoryPercentage();
|
||||
|
||||
if(
|
||||
$this->occupierFactionId &&
|
||||
$this->get('occupierFactionId', true) !== $this->get('ownerFactionId', true)
|
||||
){
|
||||
$data->occupierFaction = $this->occupierFactionId->getData();
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate victory progress in percent
|
||||
* @return int
|
||||
*/
|
||||
protected function getVictoryPercentage() : int {
|
||||
$percent = 0;
|
||||
|
||||
if($this->victoryPoints && $this->victoryPointsThreshold){
|
||||
$percent = floor((100 / $this->victoryPointsThreshold) * $this->victoryPoints);
|
||||
}
|
||||
|
||||
return $percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){}
|
||||
}
|
||||
@@ -12,8 +12,19 @@ use DB\SQL\Schema;
|
||||
|
||||
class GroupModel extends AbstractUniverseModel {
|
||||
|
||||
protected $table = 'group';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'group';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $storeDogmaAttributes = TypeModel::DEFAULT_STORE_DOGMA_ATTRIBUTES;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
@@ -50,7 +61,7 @@ class GroupModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function getData(array $additionalData = []){
|
||||
$groupData = (object) [];
|
||||
$groupData->id = $this->id;
|
||||
$groupData->id = $this->_id;
|
||||
$groupData->name = $this->name;
|
||||
|
||||
if($typesData = $this->getTypesData($additionalData)){
|
||||
@@ -65,7 +76,7 @@ class GroupModel extends AbstractUniverseModel {
|
||||
* @param bool $published
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getTypes(bool $published = true){
|
||||
public function getTypes(bool $published = true){
|
||||
$types = [];
|
||||
if($published){
|
||||
$this->filter('types', [
|
||||
@@ -102,7 +113,7 @@ class GroupModel extends AbstractUniverseModel {
|
||||
* @return int
|
||||
*/
|
||||
public function getTypesCount(bool $published = true) : int {
|
||||
return $this->dry() ? 0 : count($this->getTypes($published));
|
||||
return $this->valid() ? count($this->getTypes($published)) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,8 +122,7 @@ class GroupModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseGroupData($id);
|
||||
if(!empty($data)){
|
||||
if(!empty($data = self::getUniverseGroupData($id))){
|
||||
/**
|
||||
* @var $category CategoryModel
|
||||
*/
|
||||
@@ -127,24 +137,62 @@ class GroupModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* load types data for this group
|
||||
* @return int
|
||||
* @param int $offset
|
||||
* @param int $length 0 -> all types
|
||||
* @return array
|
||||
*/
|
||||
public function loadTypesData(){
|
||||
$count = 0;
|
||||
if( !$this->dry() ){
|
||||
$data = self::getF3()->ccpClient()->getUniverseGroupData($this->_id);
|
||||
if(!empty($data)){
|
||||
foreach((array)$data['types'] as $typeId){
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
*/
|
||||
$type = $this->rel('types');
|
||||
$type->loadById($typeId);
|
||||
$type->reset();
|
||||
$count++;
|
||||
}
|
||||
public function loadTypesData(int $offset = 0, int $length = 0) : array {
|
||||
$info = ['countAll' => 0, 'countChunk' => 0, 'count' => 0, 'offset' => $offset];
|
||||
|
||||
if(
|
||||
$this->valid() &&
|
||||
!empty($data = self::getUniverseGroupData($this->_id))
|
||||
){
|
||||
$info['countAll'] = count($data['types']);
|
||||
|
||||
array_multisort($data['types'], SORT_ASC, SORT_NUMERIC);
|
||||
if($length){
|
||||
$data['types'] = array_slice($data['types'], $offset, $length);
|
||||
}
|
||||
|
||||
$info['countChunk'] = count($data['types']);
|
||||
foreach($data['types'] as $typeId){
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
*/
|
||||
$type = $this->rel('types');
|
||||
$type->storeDogmaAttributes = $this->storeDogmaAttributes;
|
||||
$type->loadById($typeId);
|
||||
$type->reset();
|
||||
|
||||
$info['count']++;
|
||||
$info['offset']++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseGroupData(int $id) : array {
|
||||
return self::getF3()->ccpClient()->getUniverseGroupData($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseGroups() : array {
|
||||
return self::getF3()->ccpClient()->getUniverseGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseGroupTypes(int $id) : array {
|
||||
return empty($data = self::getUniverseGroupData($id)) ? [] : $data['types'];
|
||||
}
|
||||
}
|
||||
@@ -66,28 +66,13 @@ class PlanetModel extends AbstractUniverseModel {
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$planetData = (object) [];
|
||||
$planetData->name = $this->name;
|
||||
$data = (object) [];
|
||||
$data->name = $this->name;
|
||||
|
||||
$planetData->type = (object) [];
|
||||
$planetData->type->name = $this->typeId->name;
|
||||
$data->type = (object) [];
|
||||
$data->type->name = $this->typeId->name;
|
||||
|
||||
return $planetData;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for positions array (x/y/z)
|
||||
* @param $position
|
||||
* @return null
|
||||
*/
|
||||
public function set_position($position){
|
||||
$position = (array)$position;
|
||||
if(count($position) === 3){
|
||||
$this->x = $position['x'];
|
||||
$this->y = $position['y'];
|
||||
$this->z = $position['z'];
|
||||
}
|
||||
return null;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
82
app/main/model/universe/racemodel.php
Normal file
82
app/main/model/universe/racemodel.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus 4D
|
||||
* Date: 22.10.2019
|
||||
* Time: 03:21
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class RaceModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'race';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'description' => [
|
||||
'type' => Schema::DT_TEXT
|
||||
],
|
||||
'factionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'stations' => [
|
||||
'has-many' => ['Model\Universe\StationModel', 'raceId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$data = (object) [];
|
||||
$data->id = $this->_id;
|
||||
$data->name = $this->name;
|
||||
$data->faction = $this->factionId->getData();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from API into $this and save $this
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseRaceData($id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
/**
|
||||
* @var $faction FactionModel
|
||||
*/
|
||||
$faction = $this->rel('factionId');
|
||||
$faction->loadById($data['factionId'], $accessToken, $additionalOptions);
|
||||
$data['factionId'] = $faction;
|
||||
|
||||
$this->copyfrom($data, ['id', 'name', 'description', 'factionId']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,9 @@ class RegionModel extends AbstractUniverseModel {
|
||||
],
|
||||
'constellations' => [
|
||||
'has-many' => ['Model\Universe\ConstellationModel', 'regionId']
|
||||
],
|
||||
'systemNeighbours' => [
|
||||
'has-many' => ['Model\Universe\SystemNeighbourModel', 'regionId']
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
101
app/main/model/universe/sovereigntymapmodel.php
Normal file
101
app/main/model/universe/sovereigntymapmodel.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class SovereigntyMapModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'sovereignty_map';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'unique' => true,
|
||||
'belongs-to-one' => 'Model\Universe\SystemModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'factionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'allianceId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\AllianceModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'alliance',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'corporationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\CorporationModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'corporation',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* No static columns added
|
||||
* @var bool
|
||||
*/
|
||||
protected $addStaticFields = false;
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$data = (object) [];
|
||||
|
||||
if($this->factionId){
|
||||
$data->faction = $this->factionId->getData();
|
||||
}else{
|
||||
if($this->allianceId){
|
||||
$data->alliance = $this->allianceId->getData();
|
||||
}
|
||||
|
||||
if($this->corporationId){
|
||||
$data->corporation = $this->corporationId->getData();
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){}
|
||||
}
|
||||
@@ -74,7 +74,6 @@ class StargateModel extends AbstractUniverseModel {
|
||||
];
|
||||
|
||||
public function getData(){
|
||||
|
||||
$stargateData = (object) [];
|
||||
$stargateData->id = $this->_id;
|
||||
$stargateData->type = $this->typeId->name;
|
||||
@@ -83,21 +82,6 @@ class StargateModel extends AbstractUniverseModel {
|
||||
return $stargateData;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for positions array (x/y/z)
|
||||
* @param $position
|
||||
* @return null
|
||||
*/
|
||||
public function set_position($position){
|
||||
$position = (array)$position;
|
||||
if(count($position) === 3){
|
||||
$this->x = $position['x'];
|
||||
$this->y = $position['y'];
|
||||
$this->z = $position['z'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class StarModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'star';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
|
||||
165
app/main/model/universe/stationmodel.php
Normal file
165
app/main/model/universe/stationmodel.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus 4D
|
||||
* Date: 22.10.2019
|
||||
* Time: 03:00
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class StationModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'station';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\SystemModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'typeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\TypeModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'type',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'corporationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\CorporationModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'corporation',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'raceId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\RaceModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'race',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'services' => [
|
||||
'type' => self::DT_JSON
|
||||
],
|
||||
'x' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'y' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'z' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$data = (object) [];
|
||||
$data->id = $this->_id;
|
||||
$data->name = $this->name;
|
||||
$data->type = $this->typeId->getData();
|
||||
$data->services = $this->services ? : [];
|
||||
|
||||
// according to ESIs Swagger conf, "raceId" AND "corporationId"(= "owner") are optional
|
||||
// -> I haven´t seen any imported NPC station data where "raceId" OR "corporationId" not exist
|
||||
if($this->corporationId){
|
||||
$data->corporation = $this->corporationId->getData();
|
||||
}
|
||||
|
||||
if($this->raceId){
|
||||
$data->race = $this->raceId->getData();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from API into $this and save $this
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseStationData($id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
/**
|
||||
* @var $system SystemModel
|
||||
*/
|
||||
$system = $this->rel('systemId');
|
||||
$system->loadById($data['systemId'], $accessToken, $additionalOptions);
|
||||
$data['systemId'] = $system;
|
||||
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
*/
|
||||
$type = $this->rel('typeId');
|
||||
$type->loadById($data['typeId'], $accessToken, $additionalOptions);
|
||||
$data['typeId'] = $type;
|
||||
|
||||
if($data['corporationId']){
|
||||
/**
|
||||
* @var $faction CorporationModel
|
||||
*/
|
||||
$corporation = $this->rel('corporationId');
|
||||
$corporation->loadById($data['corporationId'], $accessToken, $additionalOptions);
|
||||
$data['corporationId'] = $corporation;
|
||||
}
|
||||
|
||||
if($data['raceId']){
|
||||
/**
|
||||
* @var $race RaceModel
|
||||
*/
|
||||
$race = $this->rel('raceId');
|
||||
$race->loadById($data['raceId'], $accessToken, $additionalOptions);
|
||||
$data['raceId'] = $race;
|
||||
}
|
||||
|
||||
$this->copyfrom($data, ['id', 'name', 'systemId', 'typeId', 'corporationId', 'raceId', 'services', 'position']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,8 +13,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class StructureModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'structure';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
@@ -23,9 +29,15 @@ class StructureModel extends AbstractUniverseModel {
|
||||
],
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
'index' => true
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\SystemModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'typeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -63,9 +75,10 @@ class StructureModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function getData(): \stdClass {
|
||||
$data = (object) [];
|
||||
if(!$this->dry()){
|
||||
$data->id = $this->_id;
|
||||
if($this->valid()){
|
||||
$data->id = $this->_id;
|
||||
$data->name = $this->name;
|
||||
$data->type = $this->typeId->getData();
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
@@ -78,7 +91,7 @@ class StructureModel extends AbstractUniverseModel {
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseStructureData($id, $accessToken);
|
||||
if(!empty($data)){
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
*/
|
||||
|
||||
@@ -17,11 +17,6 @@ class SystemModel extends AbstractUniverseModel {
|
||||
*/
|
||||
protected $table = 'system';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const ERROR_INVALID_WORMHOLE = 'Invalid wormhole name "%s" for system: "%s"';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@@ -55,18 +50,6 @@ class SystemModel extends AbstractUniverseModel {
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'factionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\FactionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'faction',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'security' => [
|
||||
'type' => Schema::DT_VARCHAR128
|
||||
],
|
||||
@@ -86,11 +69,6 @@ class SystemModel extends AbstractUniverseModel {
|
||||
'effect' => [
|
||||
'type' => Schema::DT_VARCHAR128
|
||||
],
|
||||
'shattered' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'x' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => false,
|
||||
@@ -114,6 +92,21 @@ class SystemModel extends AbstractUniverseModel {
|
||||
],
|
||||
'stargates' => [
|
||||
'has-many' => ['Model\Universe\StargateModel', 'systemId']
|
||||
],
|
||||
'stations' => [
|
||||
'has-many' => ['Model\Universe\StationModel', 'systemId']
|
||||
],
|
||||
'structures' => [
|
||||
'has-many' => ['Model\Universe\StructureModel', 'systemId']
|
||||
],
|
||||
'neighbour' => [
|
||||
'has-one' => ['Model\Universe\SystemNeighbourModel', 'systemId']
|
||||
],
|
||||
'sovereignty' => [
|
||||
'has-one' => ['Model\Universe\SovereigntyMapModel', 'systemId']
|
||||
],
|
||||
'factionWar' => [
|
||||
'has-one' => ['Model\Universe\FactionWarSystemModel', 'systemId']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -123,37 +116,52 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
|
||||
$systemData = (object) [];
|
||||
$systemData->id = $this->_id;
|
||||
$systemData->name = $this->name;
|
||||
$systemData->constellation = $this->constellationId->getData();
|
||||
$systemData->security = $this->security;
|
||||
$systemData->trueSec = (float)$this->trueSec;
|
||||
$systemData->effect = $this->effect;
|
||||
$systemData->shattered = (bool)$this->shattered;
|
||||
$data = (object) [];
|
||||
$data->id = $this->_id;
|
||||
$data->name = $this->name;
|
||||
$data->constellation = $this->constellationId->getData();
|
||||
$data->security = $this->security;
|
||||
$data->trueSec = (float)$this->trueSec;
|
||||
$data->effect = $this->effect;
|
||||
$data->shattered = false;
|
||||
|
||||
if($this->starId){
|
||||
$systemData->star = $this->starId->getData();
|
||||
$data->star = $this->starId->getData();
|
||||
}
|
||||
|
||||
if($this->factionId){
|
||||
$systemData->faction = $this->factionId->getData();
|
||||
if($this->sovereignty){
|
||||
$data->sovereignty = $this->sovereignty->getData();
|
||||
}
|
||||
|
||||
if($this->factionWar){
|
||||
$data->factionWar = $this->factionWar->getData();
|
||||
}
|
||||
|
||||
if( !empty($planetsData = $this->getPlanetsData()) ){
|
||||
$systemData->planets = $planetsData;
|
||||
$data->planets = $planetsData;
|
||||
|
||||
// 'Shattered' systems have ONLY planets named with '(shattered)'
|
||||
// -> system 'Thera' has '(shattered)' AND other planets -> not shattered.
|
||||
// -> system 'J164104, 'J115422' - the only non-shattered wormholes which have a shattered planet -> not shattered.
|
||||
$data->shattered = count(array_filter($planetsData, function(object $planetData){
|
||||
return property_exists($planetData, 'type') &&
|
||||
(strpos(strtolower($planetData->type->name), '(shattered)') !== false);
|
||||
})) == count($planetsData);
|
||||
}
|
||||
|
||||
if( !empty($staticsData = $this->getStaticsData()) ){
|
||||
$systemData->statics = $staticsData;
|
||||
$data->statics = $staticsData;
|
||||
}
|
||||
|
||||
if( !empty($stargatesData = $this->getStargatesData()) ){
|
||||
$systemData->stargates = $stargatesData;
|
||||
$data->stargates = $stargatesData;
|
||||
}
|
||||
|
||||
return $systemData;
|
||||
if( !empty($stationsData = $this->getStationsData()) ){
|
||||
$data->stations = $stationsData;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,11 +193,18 @@ class SystemModel extends AbstractUniverseModel {
|
||||
}
|
||||
$this->trueSec = $trueSec;
|
||||
// set 'security' for NON wormhole systems! -> those get updated from csv import
|
||||
if(!preg_match('/^j\d+$/i', $this->name)){
|
||||
// check for "Abyssal" system
|
||||
if(
|
||||
$this->get('constellationId', true) >= 22000001 &&
|
||||
$this->get('constellationId', true) <= 22000025
|
||||
// 'J1226-0' is also a wormhole with a '-' in the name! (single system)
|
||||
if(
|
||||
!preg_match('/^j(\d{6}|\d{4}-\d)$/i', $this->name) &&
|
||||
$this->name != 'Thera'
|
||||
){
|
||||
$constellationId = (int)$this->get('constellationId', true);
|
||||
if($constellationId == 23000001){
|
||||
// "Pocket" system
|
||||
$security = 'P';
|
||||
}elseif(
|
||||
$constellationId >= 22000001 &&
|
||||
$constellationId <= 22000025
|
||||
){
|
||||
// "Abyssal" system
|
||||
$security = 'A';
|
||||
@@ -220,30 +235,141 @@ class SystemModel extends AbstractUniverseModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for positions array (x/y/z)
|
||||
* @param $position
|
||||
* @return null
|
||||
* @param array $sovData
|
||||
* @return bool true if sovereignty data changed
|
||||
*/
|
||||
public function set_position($position){
|
||||
$position = (array)$position;
|
||||
if(count($position) === 3){
|
||||
$this->x = $position['x'];
|
||||
$this->y = $position['y'];
|
||||
$this->z = $position['z'];
|
||||
public function updateSovereigntyData(array $sovData = []) : bool {
|
||||
$hasChanged = false;
|
||||
$systemId = (int)$sovData['systemId'];
|
||||
$factionId = (int)$sovData['factionId'];
|
||||
$allianceId = (int)$sovData['allianceId'];
|
||||
$corporationId = (int)$sovData['corporationId'];
|
||||
|
||||
if($this->valid()){
|
||||
if($systemId === $this->_id){
|
||||
// sov data belongs to this system
|
||||
$validSovData = (bool)max($factionId, $allianceId, $corporationId);
|
||||
if($validSovData){
|
||||
// at least one of these Ids must exist for a sovereignty relation
|
||||
/**
|
||||
* @var $sovereignty SovereigntyMapModel
|
||||
*/
|
||||
if(!$sovereignty = $this->sovereignty){
|
||||
// insert new sovereignty data
|
||||
$sovereignty = $this->rel('sovereignty');
|
||||
}
|
||||
|
||||
$sovData['systemId'] = $this;
|
||||
|
||||
if($factionId){
|
||||
// HS, L - systems have "faction war"
|
||||
$sovData['allianceId'] = null;
|
||||
$sovData['corporationId'] = null;
|
||||
|
||||
/**
|
||||
* @var $faction FactionModel
|
||||
*/
|
||||
$faction = $sovereignty->rel('factionId');
|
||||
$faction->loadById($factionId);
|
||||
$sovData['factionId'] = $faction;
|
||||
}else{
|
||||
// 0.0 - systems have sovereignty data by corp and/or ally
|
||||
$sovData['factionId'] = null;
|
||||
|
||||
/**
|
||||
* @var $alliance AllianceModel|null
|
||||
*/
|
||||
$alliance = null;
|
||||
if($allianceId){
|
||||
$alliance = $sovereignty->rel('allianceId');
|
||||
$alliance->loadById($allianceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var $corporation CorporationModel|null
|
||||
*/
|
||||
$corporation = null;
|
||||
if($corporationId){
|
||||
$corporation = $sovereignty->rel('corporationId');
|
||||
$corporation->loadById($corporationId);
|
||||
}
|
||||
|
||||
$sovData['allianceId'] = $alliance;
|
||||
$sovData['corporationId'] = $corporation;
|
||||
}
|
||||
|
||||
$sovereignty->copyfrom($sovData, ['systemId', 'factionId', 'allianceId', 'corporationId']);
|
||||
|
||||
// must be called before save(). Changed fields get reset after save() is called!
|
||||
if($sovereignty->changed()){
|
||||
$hasChanged = true;
|
||||
}
|
||||
|
||||
$sovereignty->save();
|
||||
}elseif($this->sovereignty){
|
||||
// delete existing sov data
|
||||
// -> hint: WH - systems never have sovereignty data
|
||||
$this->sovereignty->erase();
|
||||
$hasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return $hasChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for static systems (wormholes)
|
||||
* -> comma separated string or array
|
||||
* @param $staticNames
|
||||
* @return null
|
||||
* @param array $fwData
|
||||
* @return bool true if faction warfare data changed
|
||||
*/
|
||||
public function set_staticNames($staticNames){
|
||||
$staticNames = array_unique(is_string($staticNames) ? explode(',', $staticNames) : (array)$staticNames);
|
||||
$this->virtual('staticNames', array_map('strtoupper', $staticNames));
|
||||
return null;
|
||||
public function updateFactionWarData(array $fwData = []) : bool {
|
||||
$hasChanged = false;
|
||||
$systemId = (int)$fwData['systemId'];
|
||||
$ownerFactionId = (int)$fwData['ownerFactionId'];
|
||||
$occupierFactionId = (int)$fwData['occupierFactionId'];
|
||||
|
||||
if($this->valid()){
|
||||
if($systemId === $this->_id){
|
||||
/**
|
||||
* @var $factionWar FactionWarSystemModel
|
||||
*/
|
||||
if(!$factionWar = $this->factionWar){
|
||||
// insert new faction war data
|
||||
$factionWar = $this->rel('factionWar');
|
||||
}
|
||||
|
||||
$fwData['systemId'] = $this;
|
||||
|
||||
if($ownerFactionId){
|
||||
/**
|
||||
* @var $ownerFaction FactionModel
|
||||
*/
|
||||
$ownerFaction = $factionWar->rel('ownerFactionId');
|
||||
$ownerFaction->loadById($ownerFactionId);
|
||||
$fwData['ownerFactionId'] = $ownerFaction;
|
||||
}
|
||||
|
||||
if($occupierFactionId){
|
||||
/**
|
||||
* @var $occupierFaction FactionModel
|
||||
*/
|
||||
$occupierFaction = $factionWar->rel('occupierFactionId');
|
||||
$occupierFaction->loadById($occupierFactionId);
|
||||
$fwData['occupierFactionId'] = $occupierFaction;
|
||||
}
|
||||
|
||||
$factionWar->copyfrom($fwData, ['systemId', 'ownerFactionId', 'occupierFactionId', 'contested', 'victoryPoints', 'victoryPointsThreshold']);
|
||||
|
||||
// must be called before save(). Changed fields get reset after save() is called!
|
||||
if($factionWar->changed()){
|
||||
$hasChanged = true;
|
||||
}
|
||||
|
||||
$factionWar->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $hasChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,38 +379,8 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterUpdateEvent($self, $pkeys){
|
||||
$staticNames = (array)$self->staticNames;
|
||||
|
||||
if(
|
||||
count($staticNames) > 0 && // make sure statics are set. In case a wh system get updated without statics are set
|
||||
preg_match('/^c\d+$/i', $self->security) // make sure it is a wormhole
|
||||
){
|
||||
foreach((array)$self->statics as $static){
|
||||
if(in_array($static->wormholeId->name, $staticNames)){
|
||||
unset($staticNames[array_search($static->wormholeId->name, $staticNames)]);
|
||||
}else{
|
||||
$static->erase();
|
||||
}
|
||||
}
|
||||
|
||||
// add new statics
|
||||
foreach($staticNames as $staticName){
|
||||
$static = $self->rel('statics');
|
||||
/**
|
||||
* @var $wormhole WormholeModel
|
||||
*/
|
||||
$wormhole = $static->rel('wormholeId')->getByForeignKey('name', $staticName, ['limit' => 1]);
|
||||
if( !$wormhole->dry() ){
|
||||
$static->systemId = $self;
|
||||
$static->wormholeId = $wormhole;
|
||||
$static->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build search index
|
||||
$self->buildIndex();
|
||||
|
||||
return parent::afterUpdateEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
@@ -292,14 +388,14 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* get data from all planets
|
||||
* @return array
|
||||
*/
|
||||
protected function getPlanetsData(){
|
||||
protected function getPlanetsData() : array {
|
||||
$planetsData = [];
|
||||
|
||||
if($this->planets){
|
||||
/**
|
||||
* @var $planet PlanetModel
|
||||
*/
|
||||
foreach($this->planets as &$planet){
|
||||
/**
|
||||
* @var $planet PlanetModel
|
||||
*/
|
||||
$planetsData[] = $planet->getData();
|
||||
}
|
||||
}
|
||||
@@ -310,14 +406,14 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* get data from all static wormholes
|
||||
* @return array
|
||||
*/
|
||||
protected function getStaticsData(){
|
||||
protected function getStaticsData() : array {
|
||||
$staticsData = [];
|
||||
|
||||
if($this->statics){
|
||||
/**
|
||||
* @var $static SystemStaticModel
|
||||
*/
|
||||
foreach($this->statics as &$static){
|
||||
/**
|
||||
* @var $static SystemStaticModel
|
||||
*/
|
||||
$staticsData[] = $static->getData();
|
||||
}
|
||||
}
|
||||
@@ -328,25 +424,62 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* get data from all stargates
|
||||
* @return array
|
||||
*/
|
||||
protected function getStargatesData(){
|
||||
protected function getStargatesData() : array {
|
||||
$stargatesData = [];
|
||||
|
||||
if($this->stargates){
|
||||
/**
|
||||
* @var $stargate StargateModel
|
||||
*/
|
||||
foreach($this->stargates as &$stargate){
|
||||
/**
|
||||
* @var $stargate StargateModel
|
||||
*/
|
||||
$stargatesData[] = $stargate->getData();
|
||||
}
|
||||
}
|
||||
return $stargatesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get data from all stations
|
||||
* @return array
|
||||
*/
|
||||
protected function getStationsData() : array {
|
||||
$stationsData = [];
|
||||
|
||||
if($this->stations){
|
||||
/**
|
||||
* @var $station StationModel
|
||||
*/
|
||||
foreach($this->stations as &$station){
|
||||
$data = $station->getData();
|
||||
if(!$data->race){
|
||||
// should never happen NPC stations always have a owning race
|
||||
$data->race = (object) [];
|
||||
$data->race->id = 0;
|
||||
$data->race->name = 'unknown';
|
||||
$data->race->faction = (object) [];
|
||||
$data->race->faction->id = 0;
|
||||
$data->race->faction->name = 'unknown';
|
||||
}
|
||||
|
||||
if(!array_key_exists($data->race->faction->id, $stationsData)){
|
||||
$stationsData[$data->race->faction->id] = [
|
||||
'id' => $data->race->faction->id,
|
||||
'name' => $data->race->name,
|
||||
'stations' => []
|
||||
];
|
||||
}
|
||||
|
||||
$stationsData[$data->race->faction->id]['stations'][] = $data;
|
||||
}
|
||||
}
|
||||
return $stationsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* update system from ESI
|
||||
*/
|
||||
public function updateModel(){
|
||||
if( !$this->dry() ){
|
||||
if($this->valid()){
|
||||
$this->loadData($this->_id);
|
||||
$this->loadPlanetsData();
|
||||
}
|
||||
@@ -387,7 +520,7 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* load planets data for this system
|
||||
*/
|
||||
public function loadPlanetsData(){
|
||||
if( !$this->dry() ){
|
||||
if($this->valid()){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($this->_id);
|
||||
if($data['planets']){
|
||||
// planets are optional since ESI v4 (e.g. Abyssal systems)
|
||||
@@ -408,9 +541,9 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* -> stargates to destination system which is not in DB get ignored
|
||||
*/
|
||||
public function loadStargatesData(){
|
||||
if( !$this->dry() ){
|
||||
if($this->valid()){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($this->_id);
|
||||
if(!empty($data)){
|
||||
if($data['stargates']){
|
||||
foreach((array)$data['stargates'] as $stargateId){
|
||||
/**
|
||||
* @var $stargate StargateModel
|
||||
@@ -422,4 +555,23 @@ class SystemModel extends AbstractUniverseModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load NPC owned stations for this system
|
||||
*/
|
||||
public function loadStationsData(){
|
||||
if($this->valid()){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($this->_id);
|
||||
if($data['stations']){
|
||||
foreach((array)$data['stations'] as $stationId){
|
||||
/**
|
||||
* @var $station SystemModel
|
||||
*/
|
||||
$station = $this->rel('stations');
|
||||
$station->loadById($stationId);
|
||||
$station->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
92
app/main/model/universe/systemneighbourmodel.php
Normal file
92
app/main/model/universe/systemneighbourmodel.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class SystemNeighbourModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'system_neighbour';
|
||||
|
||||
/**
|
||||
* allow table truncate
|
||||
* -> used on /setup page or index build
|
||||
* @var bool
|
||||
*/
|
||||
protected $allowTruncate = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'regionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\RegionModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'region',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'constellationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\ConstellationModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'constellation',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'unique' => true,
|
||||
'belongs-to-one' => 'Model\Universe\SystemModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'systemName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'jumpNodes' => [
|
||||
'type' => Schema::DT_VARCHAR512,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'trueSec' => [
|
||||
'type' => Schema::DT_DECIMAL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* No static columns added
|
||||
* @var bool
|
||||
*/
|
||||
protected $addStaticFields = false;
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){}
|
||||
}
|
||||
@@ -12,8 +12,14 @@ use DB\SQL\Schema;
|
||||
|
||||
class SystemStaticModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'system_static';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -27,13 +33,13 @@ class SystemStaticModel extends AbstractUniverseModel {
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'wormholeId' => [
|
||||
'typeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\WormholeModel',
|
||||
'belongs-to-one' => 'Model\Universe\TypeModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'wormhole',
|
||||
'table' => 'type',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
@@ -52,8 +58,14 @@ class SystemStaticModel extends AbstractUniverseModel {
|
||||
* @return null|string
|
||||
*/
|
||||
public function getData(){
|
||||
return $this->wormholeId ? $this->wormholeId->name : null;
|
||||
return $this->typeId ? $this->typeId->getWormholeName() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){}
|
||||
|
||||
/**
|
||||
@@ -66,7 +78,7 @@ class SystemStaticModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public static function setup($db = null, $table = null, $fields = null){
|
||||
if($status = parent::setup($db, $table, $fields)){
|
||||
$status = parent::setMultiColumnIndex(['systemId', 'wormholeId'], true);
|
||||
$status = parent::setMultiColumnIndex(['systemId', 'typeId'], true);
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
92
app/main/model/universe/typeattributemodel.php
Normal file
92
app/main/model/universe/typeattributemodel.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus4D
|
||||
* Date: 15.08.2019
|
||||
* Time: 22:00
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class TypeAttributeModel extends AbstractUniverseModel {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'type_attribute';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'typeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\TypeModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'type',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'attributeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\DogmaAttributeModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'dogma_attribute',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'value' => [
|
||||
'type' => Schema::DT_FLOAT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* No static columns added
|
||||
* @var bool
|
||||
*/
|
||||
protected $addStaticFields = false;
|
||||
|
||||
/**
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
$typeAttributeData = $this->attributeId->getData();
|
||||
$typeAttributeData->value = (float)$this->value;
|
||||
|
||||
return $typeAttributeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){}
|
||||
|
||||
/**
|
||||
* overwrites parent
|
||||
* @param null $db
|
||||
* @param null $table
|
||||
* @param null $fields
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function setup($db = null, $table = null, $fields = null){
|
||||
if($status = parent::setup($db, $table, $fields)){
|
||||
$status = parent::setMultiColumnIndex(['typeId', 'attributeId'], true);
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,31 @@
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
use lib\Config;
|
||||
use lib\Util;
|
||||
|
||||
class TypeModel extends AbstractUniverseModel {
|
||||
|
||||
protected $table = 'type';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'type';
|
||||
|
||||
/**
|
||||
* default store option for 'dogma' typeAttributes data
|
||||
* -> set to true will store all typeAttributes from ESI for a type
|
||||
* -> should be enabled for specific types, where data is used by Pathfinder
|
||||
*/
|
||||
const DEFAULT_STORE_DOGMA_ATTRIBUTES = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $storeDogmaAttributes = self::DEFAULT_STORE_DOGMA_ATTRIBUTES;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
@@ -83,6 +103,9 @@ class TypeModel extends AbstractUniverseModel {
|
||||
'default' => 0,
|
||||
'index' => true
|
||||
],
|
||||
'stations' => [
|
||||
'has-many' => ['Model\Universe\StationModel', 'typeId']
|
||||
],
|
||||
'structures' => [
|
||||
'has-many' => ['Model\Universe\StructureModel', 'typeId']
|
||||
],
|
||||
@@ -92,11 +115,46 @@ class TypeModel extends AbstractUniverseModel {
|
||||
'stars' => [
|
||||
'has-many' => ['Model\Universe\StarModel', 'typeId']
|
||||
],
|
||||
'wormholes' => [
|
||||
'has-many' => ['Model\Universe\WormholeModel', 'typeId']
|
||||
'attributes' => [
|
||||
'has-many' => ['Model\Universe\TypeAttributeModel', 'typeId']
|
||||
],
|
||||
'stargates' => [
|
||||
'has-many' => ['Model\Universe\StargateModel', 'typeId']
|
||||
],
|
||||
'statics' => [
|
||||
'has-many' => ['Model\Universe\SystemStaticModel', 'typeId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* set 'dogma_attributes' during ESI import process to a virtual field
|
||||
* -> 'dogma_attributes' get imported after type is saved
|
||||
* @see loadData()
|
||||
* @param $dogmaAttributesData
|
||||
* @return null
|
||||
*/
|
||||
public function set_dogma_attributes($dogmaAttributesData){
|
||||
$this->virtual('dogmaAttributes', (array)$dogmaAttributesData);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* special getter for 'wormhole' types
|
||||
* @return string|null
|
||||
*/
|
||||
public function getWormholeName(){
|
||||
return self::formatWormholeName($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $mapper
|
||||
* @return NULL|void
|
||||
*/
|
||||
public function reset($mapper = true){
|
||||
$this->clearVirtual('dogmaAttributes');
|
||||
parent::reset($mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* get type data
|
||||
* @param array $additionalData
|
||||
@@ -104,24 +162,70 @@ class TypeModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function getData(array $additionalData = []){
|
||||
$typeData = (object) [];
|
||||
$typeData->id = $this->id;
|
||||
$typeData->id = $this->_id;
|
||||
$typeData->name = $this->name;
|
||||
|
||||
foreach($additionalData as $key){
|
||||
$typeData->$key = $this->$key;
|
||||
if($key == 'attributes'){
|
||||
// add 'dogma' typeAttributes data
|
||||
$typeData->$key = $this->getAttributesData();
|
||||
}elseif($this->exists($key)){
|
||||
$typeData->$key = $this->$key;
|
||||
}
|
||||
}
|
||||
|
||||
return $typeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get wormholeData from object
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getWormholeData() : \stdClass {
|
||||
$wormholeData = (object) [];
|
||||
if($this->valid()){
|
||||
$wormholeData->name = $this->getWormholeName();
|
||||
$wormholeData->static = $this->statics ? (bool)count($this->statics) : false;
|
||||
$wormholeData->security = '';
|
||||
$wormholeData->massTotal = null;
|
||||
$wormholeData->massIndividual = null;
|
||||
$wormholeData->maxStableTime = null;
|
||||
foreach($this->getAttributesData() as $id => $attributesData){
|
||||
switch($id){
|
||||
case 1381: // 'wormholeTargetSystemClass' -> 'security'
|
||||
$wormholeData->security = self::getSystemSecurityFromId((int)$attributesData['value']);
|
||||
break;
|
||||
case 1383: // 'wormholeMaxStableMass' -> 'massTotal'
|
||||
$wormholeData->massTotal = $attributesData['value'];
|
||||
break;
|
||||
case 1385: // 'wormholeMaxJumpMass' -> 'massIndividual'
|
||||
$wormholeData->massIndividual = $attributesData['value'];
|
||||
break;
|
||||
case 1384: // 'wormholeMassRegeneration' -> 'massRegeneration'
|
||||
if($attributesData['value']){
|
||||
$wormholeData->massRegeneration = $attributesData['value'];
|
||||
}
|
||||
break;
|
||||
case 1382: // 'wormholeMaxStableTime' -> 'maxStableTime'
|
||||
$wormholeData->maxStableTime = $attributesData['value'] / 60;
|
||||
break;
|
||||
case Config::ESI_DOGMA_ATTRIBUTE_SCANWHSTRENGTH_ID: // 'scanWormholeStrength' -> 'scanWormholeStrength'
|
||||
$wormholeData->scanWormholeStrength = $attributesData['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $wormholeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get shipData from object
|
||||
* -> more fields can be added in here if needed
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getShipData(): \stdClass {
|
||||
public function getShipData() : \stdClass {
|
||||
$shipData = (object) [];
|
||||
if(!$this->dry()){
|
||||
if($this->valid()){
|
||||
$shipData->typeId = $this->_id;
|
||||
$shipData->typeName = $this->name;
|
||||
$shipData->mass = $this->mass;
|
||||
@@ -129,6 +233,118 @@ class TypeModel extends AbstractUniverseModel {
|
||||
return $shipData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getAttributesData() : array {
|
||||
$attributesData = [];
|
||||
|
||||
if($this->attributes){
|
||||
foreach($this->attributes as $typeAttribute){
|
||||
/**
|
||||
* @var $typeAttribute TypeAttributeModel
|
||||
*/
|
||||
$attributesData[] = get_object_vars($typeAttribute->getData());
|
||||
}
|
||||
}
|
||||
return Util::arrayGetBy($attributesData, 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterInsertEvent($self, $pkeys){
|
||||
$self->syncDogmaAttributes();
|
||||
|
||||
return parent::afterInsertEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterUpdateEvent($self, $pkeys){
|
||||
$self->syncDogmaAttributes();
|
||||
|
||||
return parent::afterUpdateEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* sync existing 'dogma' typeAttributes data with "new/updated" typeAttributes
|
||||
* -> $this->dogmaAttributes must be set before calling this method
|
||||
*/
|
||||
protected function syncDogmaAttributes(){
|
||||
if(
|
||||
$this->storeDogmaAttributes &&
|
||||
!empty($dogmaAttributesData = (array)$this->dogmaAttributes)
|
||||
){
|
||||
foreach((array)$this->attributes as $typeAttribute){
|
||||
$key = array_search($typeAttribute->get('attributeId', true), array_column($dogmaAttributesData, 'attributeId'));
|
||||
if($key !== false){
|
||||
// attribute still belongs to this 'type' -> update value
|
||||
$typeAttribute->copyfrom($dogmaAttributesData[$key], ['value']);
|
||||
$typeAttribute->save();
|
||||
|
||||
unset($dogmaAttributesData[$key]);
|
||||
$dogmaAttributesData = array_values($dogmaAttributesData);
|
||||
}else{
|
||||
// attribute no longer belongs to this 'type'
|
||||
$typeAttribute->erase();
|
||||
}
|
||||
}
|
||||
|
||||
// add new dogmaTypes
|
||||
foreach($dogmaAttributesData as $dogmaAttributeData){
|
||||
/**
|
||||
* @var $typeAttribute TypeAttributeModel
|
||||
* @var $dogmaAttribute DogmaAttributeModel
|
||||
*/
|
||||
$typeAttribute = $this->rel('attributes');
|
||||
$dogmaAttribute = $typeAttribute->rel('attributeId');
|
||||
$dogmaAttribute->loadById($dogmaAttributeData['attributeId']);
|
||||
if($dogmaAttribute->valid()){
|
||||
$typeAttribute->typeId = $this;
|
||||
$typeAttribute->attributeId = $dogmaAttribute;
|
||||
$typeAttribute->value = $dogmaAttributeData['value'];
|
||||
$typeAttribute->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* manipulate 'dogma_attributes' array be reference
|
||||
* -> used to inject custom attributes (not available from ESI)
|
||||
* @param array $data
|
||||
*/
|
||||
private function manipulateDogmaAttributes(array &$data){
|
||||
if(!$this->storeDogmaAttributes){
|
||||
// attributes should not get saved
|
||||
unset($data['dogma_attributes']);
|
||||
}elseif(!empty($data['dogma_attributes'])){
|
||||
switch($data['groupId']){
|
||||
case Config::ESI_GROUP_WORMHOLE_ID:
|
||||
if(
|
||||
!empty($wormholesCSVData = static::getCSVData('wormhole', 'name')) &&
|
||||
!empty($wormholeCSVData = $wormholesCSVData[self::formatWormholeName($data['name'])])
|
||||
){
|
||||
// found relevant wormhole data in *.csv for current type
|
||||
if(!empty($scanWormholeStrength = (float)$wormholeCSVData['scanWormholeStrength'])){
|
||||
$data['dogma_attributes'][] = [
|
||||
'attributeId' => Config::ESI_DOGMA_ATTRIBUTE_SCANWHSTRENGTH_ID,
|
||||
'value' => $scanWormholeStrength
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from API into $this and save $this
|
||||
* @param int $id
|
||||
@@ -138,6 +354,8 @@ class TypeModel extends AbstractUniverseModel {
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseTypesData($id);
|
||||
if(!empty($data)){
|
||||
$this->manipulateDogmaAttributes($data);
|
||||
|
||||
/**
|
||||
* @var $group GroupModel
|
||||
*/
|
||||
@@ -149,4 +367,12 @@ class TypeModel extends AbstractUniverseModel {
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $name
|
||||
* @return string|null
|
||||
*/
|
||||
public static function formatWormholeName(?string $name) : ?string {
|
||||
return (!empty($name) && !empty($format = @end(explode(' ', $name)))) ? $format : null;
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus 4D
|
||||
* Date: 13.05.2018
|
||||
* Time: 18:36
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class WormholeModel extends AbstractUniverseModel {
|
||||
|
||||
protected $table = 'wormhole';
|
||||
|
||||
public static $enableDataExport = true;
|
||||
public static $enableDataImport = true;
|
||||
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => '',
|
||||
'index' => true,
|
||||
'unique' => true
|
||||
],
|
||||
'typeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\TypeModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'type',
|
||||
'on-delete' => 'SET NULL'
|
||||
]
|
||||
],
|
||||
'validate' => 'notDry'
|
||||
],
|
||||
'static' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'security' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'massTotal' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'massIndividual' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'massRegeneration' => [
|
||||
'type' => Schema::DT_BIGINT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'maxStableTime' => [
|
||||
'type' => Schema::DT_TINYINT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'signatureStrength' => [
|
||||
'type' => Schema::DT_FLOAT,
|
||||
'nullable' => true,
|
||||
'default' => null
|
||||
],
|
||||
'systems' => [
|
||||
'has-many' => ['Model\Universe\SystemStaticModel', 'wormholeId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get wormhole data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData(){
|
||||
|
||||
$wormholeData = (object) [];
|
||||
$wormholeData->name = $this->name;
|
||||
$wormholeData->static = $this->static;
|
||||
$wormholeData->security = $this->security;
|
||||
$wormholeData->massTotal = $this->massTotal;
|
||||
$wormholeData->massIndividual = $this->massIndividual;
|
||||
|
||||
if($this->massRegeneration){
|
||||
$wormholeData->massRegeneration = $this->massRegeneration;
|
||||
}
|
||||
|
||||
$wormholeData->maxStableTime = $this->maxStableTime;
|
||||
|
||||
// signature strength as defined by http://wiki.eve-inspiracy.com/index.php?title=Wormhole_Signature_Strength_List
|
||||
if($this->signatureStrength){
|
||||
$wormholeData->signatureStrength = $this->signatureStrength;
|
||||
}
|
||||
|
||||
return $wormholeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for typeId
|
||||
* @param string $typeId
|
||||
* @return string|int|null
|
||||
*/
|
||||
public function set_typeId($typeId){
|
||||
if(!is_object($typeId)){
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
*/
|
||||
$type = $this->rel('typeId');
|
||||
$type->loadById((int)$typeId);
|
||||
$typeId = $type->dry() ? null : $type->_id;
|
||||
}
|
||||
return $typeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for massTotal
|
||||
* @param string $mass
|
||||
* @return int|null
|
||||
*/
|
||||
public function set_massTotal($mass){
|
||||
$mass = (int)$mass;
|
||||
return $mass ? : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for massIndividual
|
||||
* @param string $mass
|
||||
* @return string|null
|
||||
*/
|
||||
public function set_massIndividual($mass){
|
||||
$mass = (int)$mass;
|
||||
return $mass ? : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for massRegeneration
|
||||
* @param $mass
|
||||
* @return int|null
|
||||
*/
|
||||
public function set_massRegeneration($mass){
|
||||
$mass = (int)$mass;
|
||||
return $mass ? : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for maxStableTime
|
||||
* @param string $hours
|
||||
* @return int|null
|
||||
*/
|
||||
public function set_maxStableTime($hours){
|
||||
$hours = (int)$hours;
|
||||
return $hours ? : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for signatureStrength
|
||||
* @param string $strength
|
||||
* @return float|null
|
||||
*/
|
||||
public function set_signatureStrength($strength){
|
||||
$strength = (float)$strength;
|
||||
return $strength ? : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
* @return bool
|
||||
*/
|
||||
public function exportData(array $fields = [
|
||||
'id', 'name', 'typeId', 'static', 'security', 'massTotal', 'massIndividual',
|
||||
'massRegeneration', 'maxStableTime', 'signatureStrength']
|
||||
) : bool {
|
||||
return parent::exportData($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){}
|
||||
|
||||
}
|
||||
@@ -13,8 +13,8 @@ NAME = Pathfinder
|
||||
; Version is used for CSS/JS cache busting and is part of the URL for static resources:
|
||||
; e.g. public/js/vX.X.X/app.js
|
||||
; Syntax: String (current version)
|
||||
; Default: v1.5.0
|
||||
VERSION = v1.5.3
|
||||
; Default: v1.5.4
|
||||
VERSION = v1.5.4
|
||||
|
||||
; Contact information [optional]
|
||||
; Shown on 'licence', 'contact' page.
|
||||
@@ -377,6 +377,9 @@ LOG_LINES = 1000
|
||||
[PATHFINDER.API]
|
||||
CCP_IMAGE_SERVER = https://image.eveonline.com
|
||||
Z_KILLBOARD = https://zkillboard.com/api
|
||||
EVEEYE = https://eveeye.com
|
||||
DOTLAN = http://evemaps.dotlan.net
|
||||
ANOIK = http://anoik.is
|
||||
; GitHub Developer API
|
||||
GIT_HUB = https://api.github.com
|
||||
|
||||
|
||||
@@ -56,12 +56,13 @@ PDO_TIMEOUT = 2
|
||||
; MySql variables. Values are auto. set as 'SESSION' vars
|
||||
; https://dev.mysql.com/doc/refman/5.5/en/show-variables.html
|
||||
DEFAULT_STORAGE_ENGINE = InnoDB
|
||||
CHARACTER_SET_DATABASE = utf8
|
||||
CHARACTER_SET_CLIENT = utf8
|
||||
CHARACTER_SET_RESULTS = utf8
|
||||
CHARACTER_SET_CONNECTION = utf8
|
||||
COLLATION_DATABASE = utf8_general_ci
|
||||
COLLATION_CONNECTION = utf8_general_ci
|
||||
CHARACTER_SET_SERVER = utf8mb4
|
||||
CHARACTER_SET_DATABASE = utf8mb4
|
||||
CHARACTER_SET_CLIENT = utf8mb4
|
||||
CHARACTER_SET_RESULTS = utf8mb4
|
||||
CHARACTER_SET_CONNECTION = utf8mb4
|
||||
COLLATION_DATABASE = utf8mb4_unicode_ci
|
||||
COLLATION_CONNECTION = utf8mb4_unicode_ci
|
||||
FOREIGN_KEY_CHECKS = ON
|
||||
INNODB_FILE_PER_TABLE = ON
|
||||
WAIT_TIMEOUT = 28800
|
||||
@@ -80,6 +81,4 @@ NODE = 6.0
|
||||
NPM = 3.10.0
|
||||
|
||||
[REQUIREMENTS.DATA]
|
||||
STRUCTURES = 33
|
||||
SHIPS = 491
|
||||
NEIGHBOURS = 5201
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"react/socket": "1.2.*",
|
||||
"react/promise-stream": "1.1.*",
|
||||
"clue/ndjson-react": "1.0.*",
|
||||
"exodus4d/pathfinder_esi": "v1.3.1"
|
||||
"exodus4d/pathfinder_esi": "v1.3.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-redis": "Redis can be used as cache backend."
|
||||
|
||||
169
composer.lock
generated
169
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ad512ee5d1242b7e46b3620b1b05a2a2",
|
||||
"content-hash": "cd6689b64084cbe1bdbf74b1165fd472",
|
||||
"packages": [
|
||||
{
|
||||
"name": "cache/adapter-common",
|
||||
@@ -55,7 +55,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "Common classes for PSR-6 adapters",
|
||||
@@ -123,7 +123,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "A PSR-6 cache implementation using a php array. This implementation supports tags",
|
||||
@@ -191,7 +191,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "A PSR-6 cache implementation using filesystem. This implementation supports tags",
|
||||
@@ -253,7 +253,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "A helper trait and interface to your PSR-6 cache to support hierarchical keys.",
|
||||
@@ -311,7 +311,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "A decorator that makes your cache support namespaces",
|
||||
@@ -381,7 +381,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "A PSR-6 cache implementation using Redis (PhpRedis). This implementation supports tags",
|
||||
@@ -432,7 +432,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
@@ -505,7 +505,7 @@
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/nyholm"
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
}
|
||||
],
|
||||
"description": "A PSR-6 cache implementation using Void. This implementation supports tags",
|
||||
@@ -629,28 +629,30 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/lexer.git",
|
||||
"reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8"
|
||||
"reference": "e17f069ede36f7534b95adec71910ed1b49c74ea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/1febd6c3ef84253d7c815bed85fc622ad207a9f8",
|
||||
"reference": "1febd6c3ef84253d7c815bed85fc622ad207a9f8",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/e17f069ede36f7534b95adec71910ed1b49c74ea",
|
||||
"reference": "e17f069ede36f7534b95adec71910ed1b49c74ea",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
"php": "^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.5"
|
||||
"doctrine/coding-standard": "^6.0",
|
||||
"phpstan/phpstan": "^0.11.8",
|
||||
"phpunit/phpunit": "^8.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -663,14 +665,14 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
@@ -685,20 +687,20 @@
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"time": "2019-06-08T11:03:04+00:00"
|
||||
"time": "2019-07-30T19:33:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "egulias/email-validator",
|
||||
"version": "2.1.9",
|
||||
"version": "2.1.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/egulias/EmailValidator.git",
|
||||
"reference": "128cc721d771ec2c46ce59698f4ca42b73f71b25"
|
||||
"reference": "92dd169c32f6f55ba570c309d83f5209cefb5e23"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/128cc721d771ec2c46ce59698f4ca42b73f71b25",
|
||||
"reference": "128cc721d771ec2c46ce59698f4ca42b73f71b25",
|
||||
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/92dd169c32f6f55ba570c309d83f5209cefb5e23",
|
||||
"reference": "92dd169c32f6f55ba570c309d83f5209cefb5e23",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -708,7 +710,8 @@
|
||||
"require-dev": {
|
||||
"dominicsayers/isemail": "dev-master",
|
||||
"phpunit/phpunit": "^4.8.35||^5.7||^6.0",
|
||||
"satooshi/php-coveralls": "^1.0.1"
|
||||
"satooshi/php-coveralls": "^1.0.1",
|
||||
"symfony/phpunit-bridge": "^4.4@dev"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
|
||||
@@ -716,7 +719,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -742,7 +745,7 @@
|
||||
"validation",
|
||||
"validator"
|
||||
],
|
||||
"time": "2019-06-23T10:14:27+00:00"
|
||||
"time": "2019-08-13T17:33:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "evenement/evenement",
|
||||
@@ -789,16 +792,16 @@
|
||||
},
|
||||
{
|
||||
"name": "exodus4d/pathfinder_esi",
|
||||
"version": "v1.3.1",
|
||||
"version": "v1.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/exodus4d/pathfinder_esi.git",
|
||||
"reference": "392cb81f1efbd9bf69d7d943f4aefdcf3f0a617c"
|
||||
"reference": "7eecfe27bb15fab5142aceeee30e07355d660773"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/exodus4d/pathfinder_esi/zipball/392cb81f1efbd9bf69d7d943f4aefdcf3f0a617c",
|
||||
"reference": "392cb81f1efbd9bf69d7d943f4aefdcf3f0a617c",
|
||||
"url": "https://api.github.com/repos/exodus4d/pathfinder_esi/zipball/7eecfe27bb15fab5142aceeee30e07355d660773",
|
||||
"reference": "7eecfe27bb15fab5142aceeee30e07355d660773",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -824,9 +827,9 @@
|
||||
],
|
||||
"description": "ESI API library for Pathfinder",
|
||||
"support": {
|
||||
"source": "https://github.com/exodus4d/pathfinder_esi/tree/v1.3.1"
|
||||
"source": "https://github.com/exodus4d/pathfinder_esi/tree/v1.3.2"
|
||||
},
|
||||
"time": "2019-05-07T11:53:44+00:00"
|
||||
"time": "2019-10-08T10:20:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
@@ -1017,16 +1020,16 @@
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
"version": "1.0.53",
|
||||
"version": "1.0.55",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem.git",
|
||||
"reference": "08e12b7628f035600634a5e76d95b5eb66cea674"
|
||||
"reference": "33c91155537c6dc899eacdc54a13ac6303f156e6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/08e12b7628f035600634a5e76d95b5eb66cea674",
|
||||
"reference": "08e12b7628f035600634a5e76d95b5eb66cea674",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/33c91155537c6dc899eacdc54a13ac6303f156e6",
|
||||
"reference": "33c91155537c6dc899eacdc54a13ac6303f156e6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1097,20 +1100,20 @@
|
||||
"sftp",
|
||||
"storage"
|
||||
],
|
||||
"time": "2019-06-18T20:09:29+00:00"
|
||||
"time": "2019-08-24T11:17:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/html-to-markdown",
|
||||
"version": "4.8.1",
|
||||
"version": "4.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1"
|
||||
"reference": "e747489191f8e9144a7270eb61f8b9516e99e413"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"reference": "250d1bf45f80d15594fb6b316df777d6d4c97ad1",
|
||||
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/e747489191f8e9144a7270eb61f8b9516e99e413",
|
||||
"reference": "e747489191f8e9144a7270eb61f8b9516e99e413",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1142,17 +1145,17 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nick Cernis",
|
||||
"email": "nick@cern.is",
|
||||
"homepage": "http://modernnerd.net",
|
||||
"role": "Original Author"
|
||||
},
|
||||
{
|
||||
"name": "Colin O'Dell",
|
||||
"email": "colinodell@gmail.com",
|
||||
"homepage": "https://www.colinodell.com",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Nick Cernis",
|
||||
"email": "nick@cern.is",
|
||||
"homepage": "http://modernnerd.net",
|
||||
"role": "Original Author"
|
||||
}
|
||||
],
|
||||
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||
@@ -1161,20 +1164,20 @@
|
||||
"html",
|
||||
"markdown"
|
||||
],
|
||||
"time": "2018-12-24T17:21:44+00:00"
|
||||
"time": "2019-08-02T11:57:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.24.0",
|
||||
"version": "1.25.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266"
|
||||
"reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266",
|
||||
"reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/70e65a5470a42cfec1a7da00d30edb6e617e8dcf",
|
||||
"reference": "70e65a5470a42cfec1a7da00d30edb6e617e8dcf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1239,7 +1242,7 @@
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2018-11-05T09:00:11+00:00"
|
||||
"time": "2019-09-06T13:49:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
@@ -1911,16 +1914,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-iconv",
|
||||
"version": "v1.11.0",
|
||||
"version": "v1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-iconv.git",
|
||||
"reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7"
|
||||
"reference": "685968b11e61a347c18bf25db32effa478be610f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f037ea22acfaee983e271dd9c3b8bb4150bd8ad7",
|
||||
"reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/685968b11e61a347c18bf25db32effa478be610f",
|
||||
"reference": "685968b11e61a347c18bf25db32effa478be610f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1932,7 +1935,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.11-dev"
|
||||
"dev-master": "1.12-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1966,20 +1969,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
"time": "2019-08-06T08:03:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-idn",
|
||||
"version": "v1.11.0",
|
||||
"version": "v1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||
"reference": "c766e95bec706cdd89903b1eda8afab7d7a6b7af"
|
||||
"reference": "6af626ae6fa37d396dc90a399c0ff08e5cfc45b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c766e95bec706cdd89903b1eda8afab7d7a6b7af",
|
||||
"reference": "c766e95bec706cdd89903b1eda8afab7d7a6b7af",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6af626ae6fa37d396dc90a399c0ff08e5cfc45b2",
|
||||
"reference": "6af626ae6fa37d396dc90a399c0ff08e5cfc45b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1993,7 +1996,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.12-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2009,13 +2012,13 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Laurent Bassin",
|
||||
"email": "laurent@bassin.info"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
|
||||
@@ -2028,20 +2031,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2019-03-04T13:44:35+00:00"
|
||||
"time": "2019-08-06T08:03:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.11.0",
|
||||
"version": "v1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
|
||||
"reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17",
|
||||
"reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2053,7 +2056,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.11-dev"
|
||||
"dev-master": "1.12-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2087,20 +2090,20 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
"time": "2019-08-06T08:03:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
"version": "v1.11.0",
|
||||
"version": "v1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||
"reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c"
|
||||
"reference": "04ce3335667451138df4307d6a9b61565560199e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c",
|
||||
"reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/04ce3335667451138df4307d6a9b61565560199e",
|
||||
"reference": "04ce3335667451138df4307d6a9b61565560199e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2109,7 +2112,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.11-dev"
|
||||
"dev-master": "1.12-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2142,7 +2145,7 @@
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2019-02-06T07:57:58+00:00"
|
||||
"time": "2019-08-06T08:03:45+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
||||
3773
export/csv/system_static.csv
Normal file
3773
export/csv/system_static.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,90 +1,90 @@
|
||||
"Id";"Name";"Security";"MassTotal";"MassIndividual";"MassRegeneration";"MaxStableTime";"SignatureStrength";
|
||||
"1";"A009";"C13";"500000000";"5000000";"3000000000";"16";;
|
||||
"2";"A239";"L";"2000000000";"300000000";;"24";"5";
|
||||
"3";"A641";"H";"2000000000";"1000000000";;"16";"10";
|
||||
"4";"A982";"C6";"3000000000";"300000000";;"24";"2.22";
|
||||
"5";"B041";"C6";"3000000000";"300000000";"500000000";"48";;
|
||||
"6";"B274";"H";"2000000000";"300000000";;"24";"10";
|
||||
"7";"B449";"H";"2000000000";"1000000000";;"16";"2.5";
|
||||
"8";"B520";"H";"3000000000";"300000000";"500000000";"24";;
|
||||
"9";"C008";"C5";"1000000000";"5000000";"3000000000";"16";;
|
||||
"10";"C125";"C2";"1000000000";"20000000";;"16";"6.67";
|
||||
"11";"C140";"L";"3000000000";"1350000000";;"24";"5";
|
||||
"12";"C247";"C3";"2000000000";"300000000";;"16";"10";
|
||||
"13";"C248";"0.0";"3000000000";"1350000000";"500000000";"24";;
|
||||
"14";"C391";"L";"3000000000";"1000000000";"500000000";"24";;
|
||||
"15";"D364";"C2";"1000000000";"300000000";;"16";"1.25";
|
||||
"16";"D382";"C2";"2000000000";"300000000";;"16";"6.67";
|
||||
"17";"D792";"H";"3000000000";"1000000000";;"24";"2.5";
|
||||
"18";"D845";"H";"5000000000";"300000000";"500000000";"24";"5";
|
||||
"19";"E004";"C1";"1000000000";"5000000";"3000000000";"16";;
|
||||
"20";"E175";"C4";"2000000000";"300000000";;"16";"5";
|
||||
"21";"E545";"0.0";"2000000000";"300000000";;"24";"2.5";
|
||||
"23";"G024";"C2";"2000000000";"300000000";;"16";"1.25";
|
||||
"24";"H121";"C1";"500000000";"20000000";;"16";"10";
|
||||
"25";"H296";"C5";"3000000000";"1350000000";;"24";"10";
|
||||
"26";"H900";"C5";"3000000000";"300000000";;"24";"2.5";
|
||||
"27";"I182";"C2";"2000000000";"300000000";;"16";"4";
|
||||
"28";"J244";"L";"1000000000";"20000000";;"24";"5";
|
||||
"29";"K329";"0.0";"5000000000";"1800000000";"500000000";"24";;
|
||||
"30";"K346";"0.0";"3000000000";"300000000";;"24";"2.5";
|
||||
"31";"L005";"C2";"1000000000";"5000000";"3000000000";"16";;
|
||||
"32";"L477";"C3";"2000000000";"300000000";;"16";"5";
|
||||
"33";"L614";"C5";"1000000000";"20000000";;"24";"2.5";
|
||||
"35";"M267";"C3";"1000000000";"300000000";;"16";"1.25";
|
||||
"36";"M555";"C5";"3000000000";"1000000000";;"24";"2.5";
|
||||
"37";"M609";"C4";"1000000000";"20000000";;"16";"4";
|
||||
"38";"N062";"C5";"3000000000";"300000000";;"24";"2.5";
|
||||
"39";"N110";"H";"1000000000";"20000000";;"24";"10";
|
||||
"40";"N290";"L";"3000000000";"1350000000";"500000000";"24";;
|
||||
"41";"N432";"C5";"3000000000";"1350000000";;"24";"10";
|
||||
"42";"N766";"C2";"2000000000";"300000000";;"16";"4";
|
||||
"43";"N770";"C5";"3000000000";"300000000";;"24";"2.5";
|
||||
"44";"N944";"L";"3000000000";"1350000000";;"24";"10";
|
||||
"45";"N968";"C3";"2000000000";"300000000";;"16";"10";
|
||||
"46";"O128";"C4";"1000000000";"300000000";"100000000";"24";;
|
||||
"47";"O477";"C3";"2000000000";"300000000";;"16";"5";
|
||||
"48";"O883";"C3";"1000000000";"20000000";;"16";"5";
|
||||
"49";"P060";"C1";"500000000";"20000000";;"16";"5";
|
||||
"50";"Q003";"0.0";"1000000000";"5000000";"3000000000";"16";;
|
||||
"51";"Q317";"C1";"500000000";"20000000";;"16";"2.5";
|
||||
"52";"R051";"L";"3000000000";"1000000000";;"16";"5";
|
||||
"53";"R474";"C6";"3000000000";"300000000";;"24";"2.22";
|
||||
"54";"R943";"C2";"750000000";"300000000";;"16";"6.67";
|
||||
"55";"S047";"H";"3000000000";"300000000";;"24";;
|
||||
"56";"S199";"0.0";"3000000000";"1350000000";;"24";"10";
|
||||
"57";"S804";"C6";"1000000000";"20000000";;"24";"1.25";
|
||||
"58";"T405";"C4";"2000000000";"300000000";;"16";"6.67";
|
||||
"59";"U210";"L";"3000000000";"300000000";;"24";"10";
|
||||
"60";"U319";"C6";"3000000000";"1350000000";"500000000";"48";;
|
||||
"61";"U574";"C6";"3000000000";"300000000";;"24";"1.25";
|
||||
"62";"V283";"0.0";"3000000000";"1000000000";;"24";"2.5";
|
||||
"63";"V301";"C1";"500000000";"20000000";;"16";"5";
|
||||
"64";"V753";"C6";"3000000000";"1350000000";;"24";"6.67";
|
||||
"65";"V911";"C5";"3000000000";"1350000000";;"24";"10";
|
||||
"66";"W237";"C6";"3000000000";"1350000000";;"24";"6.67";
|
||||
"67";"X702";"C3";"1000000000";"300000000";;"24";"10";
|
||||
"68";"X877";"C4";"2000000000";"300000000";;"16";"6.67";
|
||||
"69";"Y683";"C4";"2000000000";"300000000";;"16";"4";
|
||||
"70";"Y790";"C1";"500000000";"20000000";;"16";"2.5";
|
||||
"71";"Z006";"C3";"1000000000";"5000000";"3000000000";"16";;
|
||||
"72";"Z060";"0.0";"1000000000";"20000000";;"24";"2.5";
|
||||
"73";"Z142";"0.0";"3000000000";"1350000000";;"24";"10";
|
||||
"74";"Z457";"C4";"2000000000";"300000000";;"16";"4";
|
||||
"75";"Z647";"C1";"500000000";"20000000";;"16";"10";
|
||||
"76";"Z971";"C1";"100000000";"20000000";;"16";"10";
|
||||
"80";"M001";"C4";"1000000000";"5000000";"3000000000";"16";;
|
||||
"81";"E587";"0.0";"3000000000";"1000000000";;"16";;
|
||||
"82";"V898";"L";"2000000000";"300000000";;"16";;
|
||||
"83";"Q063";"H";"500000000";"20000000";;"16";;
|
||||
"84";"G008";"C6";"1000000000";"5000000";"3000000000";"16";;
|
||||
"85";"F353";"C12";"100000000";"20000000";;"16";;
|
||||
"86";"F135";"C12";"750000000";"300000000";;"16";;
|
||||
"87";"T458";"C12";"500000000";"20000000";;"16";;
|
||||
"88";"M164";"C12";"2000000000";"300000000";;"16";;
|
||||
"89";"L031";"C12";"3000000000";"1000000000";;"16";;
|
||||
"90";"S877";"C14";"750000000";"300000000";;"16";;
|
||||
"91";"B735";"C15";"750000000";"300000000";;"16";;
|
||||
"92";"V928";"C16";"750000000";"300000000";;"16";;
|
||||
"93";"C414";"C17";"750000000";"300000000";;"16";;
|
||||
"94";"R259";"C18";"750000000";"300000000";;"16";;
|
||||
Id;Name;scanWormholeStrength
|
||||
1;A009;
|
||||
2;A239;5
|
||||
3;A641;10
|
||||
4;A982;2.22
|
||||
5;B041;
|
||||
6;B274;10
|
||||
7;B449;2.5
|
||||
8;B520;
|
||||
9;C008;
|
||||
10;C125;6.67
|
||||
11;C140;5
|
||||
12;C247;10
|
||||
13;C248;
|
||||
14;C391;
|
||||
15;D364;1.25
|
||||
16;D382;6.67
|
||||
17;D792;2.5
|
||||
18;D845;5
|
||||
19;E004;
|
||||
20;E175;5
|
||||
21;E545;2.5
|
||||
23;G024;1.25
|
||||
24;H121;10
|
||||
25;H296;10
|
||||
26;H900;2.5
|
||||
27;I182;4
|
||||
28;J244;5
|
||||
29;K329;
|
||||
30;K346;2.5
|
||||
31;L005;
|
||||
32;L477;5
|
||||
33;L614;2.5
|
||||
35;M267;1.25
|
||||
36;M555;2.5
|
||||
37;M609;4
|
||||
38;N062;2.5
|
||||
39;N110;10
|
||||
40;N290;
|
||||
41;N432;10
|
||||
42;N766;4
|
||||
43;N770;2.5
|
||||
44;N944;10
|
||||
45;N968;10
|
||||
46;O128;
|
||||
47;O477;5
|
||||
48;O883;5
|
||||
49;P060;5
|
||||
50;Q003;
|
||||
51;Q317;2.5
|
||||
52;R051;5
|
||||
53;R474;2.22
|
||||
54;R943;6.67
|
||||
55;S047;
|
||||
56;S199;10
|
||||
57;S804;1.25
|
||||
58;T405;6.67
|
||||
59;U210;10
|
||||
60;U319;
|
||||
61;U574;1.25
|
||||
62;V283;2.5
|
||||
63;V301;5
|
||||
64;V753;6.67
|
||||
65;V911;10
|
||||
66;W237;6.67
|
||||
67;X702;10
|
||||
68;X877;6.67
|
||||
69;Y683;4
|
||||
70;Y790;2.5
|
||||
71;Z006;
|
||||
72;Z060;2.5
|
||||
73;Z142;10
|
||||
74;Z457;4
|
||||
75;Z647;10
|
||||
76;Z971;10
|
||||
80;M001;
|
||||
81;E587;
|
||||
82;V898;
|
||||
83;Q063;
|
||||
84;G008;
|
||||
85;F353;
|
||||
86;F135;
|
||||
87;T458;
|
||||
88;M164;
|
||||
89;L031;
|
||||
90;S877;
|
||||
91;B735;
|
||||
92;V928;
|
||||
93;C414;
|
||||
94;R259;
|
||||
|
Binary file not shown.
@@ -27,7 +27,7 @@ requirejs.config({
|
||||
admin: './app/admin', // initial start "admin page" view
|
||||
notification: './app/notification', // "notification" view
|
||||
|
||||
jquery: 'lib/jquery-3.3.1.min', // v3.3.1 jQuery
|
||||
jquery: 'lib/jquery-3.4.1.min', // v3.4.1 jQuery
|
||||
bootstrap: 'lib/bootstrap.min', // v3.3.0 Bootstrap js code - http://getbootstrap.com/javascript
|
||||
text: 'lib/requirejs/text', // v2.0.12 A RequireJS/AMD loader plugin for loading text resources.
|
||||
mustache: 'lib/mustache.min', // v3.0.1 Javascript template engine - http://mustache.github.io
|
||||
@@ -42,11 +42,11 @@ requirejs.config({
|
||||
xEditable: 'lib/bootstrap-editable.min', // v1.5.1 X-editable - in placed editing
|
||||
morris: 'lib/morris.min', // v0.5.1 Morris.js - graphs and charts
|
||||
raphael: 'lib/raphael.min', // v2.2.8 Raphaël - required for morris - https://dmitrybaranovskiy.github.io/raphael
|
||||
bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com
|
||||
bootbox: 'lib/bootbox.min', // v5.2.0 Bootbox.js - custom dialogs - http://bootboxjs.com
|
||||
easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart
|
||||
peityInlineChart: 'lib/jquery.peity.min', // v3.2.1 Inline Chart - http://benpickles.github.io/peity/
|
||||
dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select
|
||||
hoverIntent: 'lib/jquery.hoverIntent.min', // v1.9.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
|
||||
hoverIntent: 'lib/jquery.hoverIntent.min', // v1.10.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
|
||||
select2: 'lib/select2.min', // v4.0.3 Drop Down customization - https://select2.github.io
|
||||
validator: 'lib/validator.min', // v0.10.1 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
|
||||
lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info
|
||||
|
||||
@@ -383,6 +383,51 @@ define(['jquery'], ($) => {
|
||||
30: 'K346 - 0.0',
|
||||
31: 'Z060 - 0.0'
|
||||
}
|
||||
},
|
||||
14: { // Drifter Sentinel WH
|
||||
1: { // Combat
|
||||
1: 'Monolith',
|
||||
2: 'Wormhole in Rock Circle',
|
||||
3: 'Opposing Spatial Rifts',
|
||||
4: 'Sleeper Enclave Debris',
|
||||
5: 'Crystal Resource'
|
||||
}
|
||||
},
|
||||
15: { // Drifter Barbican WH
|
||||
1: { // Combat
|
||||
1: 'Wrecked Ships',
|
||||
2: 'Unstable Wormhole',
|
||||
3: 'Spatial Rift',
|
||||
4: 'Heavily Guarded Spatial Rift',
|
||||
5: 'Crystals'
|
||||
}
|
||||
},
|
||||
16: { // Drifter Vidette WH
|
||||
1: { // Combat
|
||||
1: 'Ship Graveyard',
|
||||
2: 'Sleeper Engineering Station',
|
||||
3: 'Spatial Rift',
|
||||
4: 'Sleeper Enclave in Coral Rock',
|
||||
5: 'Crystals and Stone Circle'
|
||||
}
|
||||
},
|
||||
17: { // Drifter Conflux WH
|
||||
1: { // Combat
|
||||
1: 'Monolith',
|
||||
2: 'Caged Wormhole',
|
||||
3: 'Rock Formation and Wormhole',
|
||||
4: 'Particle Acceleration Array',
|
||||
5: 'Guarded Asteroid Station'
|
||||
}
|
||||
},
|
||||
18: { // Drifter Redoubt WH
|
||||
1: { // Combat
|
||||
1: 'Ship Graveyard',
|
||||
2: 'Caged Wormhole',
|
||||
3: 'Spatial Rift Generator',
|
||||
4: 'Sleeper Enclave',
|
||||
5: 'Hollow Asteroid'
|
||||
}
|
||||
}
|
||||
}, // system type (k-space)
|
||||
2: {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -137,7 +137,8 @@ define([
|
||||
|
||||
// mark as init
|
||||
tableElement.attr('data-counter', 'init');
|
||||
let refreshIntervalId = window.setInterval(() => {
|
||||
|
||||
let updateTableCount = () => {
|
||||
tableApi.cells(null, columnSelector).every(function(rowIndex, colIndex, tableLoopCount, cellLoopCount){
|
||||
let cell = this;
|
||||
let node = cell.node();
|
||||
@@ -148,7 +149,9 @@ define([
|
||||
updateDateDiff( cell.nodes().to$(), date, round);
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
};
|
||||
|
||||
let refreshIntervalId = window.setInterval(updateTableCount, 500);
|
||||
|
||||
tableElement.data('interval', refreshIntervalId);
|
||||
};
|
||||
|
||||
@@ -45,6 +45,7 @@ define([
|
||||
table.destroyTimestampCounter(true);
|
||||
});
|
||||
|
||||
// Status Plugin ==============================================================================================
|
||||
let StatusTable = function(settings){
|
||||
let me = this;
|
||||
me.statusContainer = $('<div>', {
|
||||
|
||||
@@ -244,6 +244,21 @@ define([], () => {
|
||||
},
|
||||
'C12': {
|
||||
class: 'pf-system-sec-special'
|
||||
},
|
||||
'C14': {
|
||||
class: 'pf-system-sec-drifter'
|
||||
},
|
||||
'C15': {
|
||||
class: 'pf-system-sec-drifter'
|
||||
},
|
||||
'C16': {
|
||||
class: 'pf-system-sec-drifter'
|
||||
},
|
||||
'C17': {
|
||||
class: 'pf-system-sec-drifter'
|
||||
},
|
||||
'C18': {
|
||||
class: 'pf-system-sec-drifter'
|
||||
}
|
||||
},
|
||||
// true sec
|
||||
@@ -627,6 +642,14 @@ define([], () => {
|
||||
8: 'A009 - C13'
|
||||
}
|
||||
},
|
||||
// Drifter wormholes (can only appear in k-space)
|
||||
drifterWormholes: {
|
||||
1: 'S877 - C14 Sentinel',
|
||||
2: 'B735 - C15 Barbican',
|
||||
3: 'V928 - C16 Vidette',
|
||||
4: 'C414 - C17 Conflux',
|
||||
5: 'R259 - C18 Redoubt'
|
||||
},
|
||||
// incoming wormholes
|
||||
incomingWormholes: {
|
||||
1: 'K162 - C1/2/3 (unknown)',
|
||||
|
||||
@@ -141,15 +141,14 @@ define([
|
||||
|
||||
// show Cookie accept hint on SSO login button
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'bottom',
|
||||
btnOkClass: 'btn btn-sm btn-default',
|
||||
btnOkLabel: 'dismiss',
|
||||
btnOkIcon: 'fas fa-fw fa-sign-in-alt',
|
||||
title: 'Accept cookies',
|
||||
btnCancelClass: 'btn btn-sm btn-success',
|
||||
btnCancelLabel: 'accept',
|
||||
btnCancelIcon: 'fas fa-fw fa-check',
|
||||
btnOkClass: 'btn btn-sm btn-default',
|
||||
btnOkLabel: 'dismiss',
|
||||
btnOkIcon: 'fas fa-fw fa-sign-in-alt',
|
||||
onCancel: function(e, target){
|
||||
// "Accept cookies"
|
||||
setAcceptCookie();
|
||||
@@ -314,7 +313,6 @@ define([
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -406,13 +404,13 @@ define([
|
||||
* init scrollSpy for navigation bar
|
||||
*/
|
||||
let initScrollSpy = () => {
|
||||
// init scrollspy
|
||||
let scrollElement = window;
|
||||
let timeout;
|
||||
|
||||
// show elements that are currently in the viewport
|
||||
let showVisibleElements = () => {
|
||||
// find all elements that should be animated
|
||||
let visibleElements = $('.' + config.animateElementClass).isInViewport();
|
||||
|
||||
let visibleElements = Util.findInViewport($('.' + config.animateElementClass));
|
||||
$(visibleElements).removeClass( config.animateElementClass );
|
||||
|
||||
$(visibleElements).velocity('transition.flipXIn', {
|
||||
@@ -431,16 +429,23 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
$( window ).scroll(() => {
|
||||
// check for new visible elements
|
||||
showVisibleElements();
|
||||
});
|
||||
let scrollHandler = () => {
|
||||
// If there's a timer, cancel it
|
||||
if(timeout){
|
||||
window.cancelAnimationFrame(timeout);
|
||||
}
|
||||
timeout = window.requestAnimationFrame(showVisibleElements);
|
||||
};
|
||||
|
||||
scrollElement.addEventListener('scroll', scrollHandler, false);
|
||||
|
||||
// initial check for visible elements
|
||||
showVisibleElements();
|
||||
|
||||
// event listener for navigation links
|
||||
Util.initPageScroll('#' + config.navigationElementId);
|
||||
|
||||
Util.initScrollSpy(document.getElementById(config.navigationElementId), scrollElement, {
|
||||
offset: 150
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -449,11 +454,18 @@ define([
|
||||
*/
|
||||
let initServerStatus = () => {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
type: 'GET',
|
||||
url: Init.path.getServerStatus,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData, textStatus, request){
|
||||
|
||||
let dateLastModified = new Date(request.getResponseHeader('Last-Modified') || Date.now());
|
||||
let dateExpires = new Date(request.getResponseHeader('Expires') || Date.now());
|
||||
|
||||
var options = { hour: '2-digit', minute: '2-digit', hour12: false, timeZone: 'UTC', timeZoneName: 'short' };
|
||||
responseData.api.cache = dateLastModified.toLocaleTimeString('en-US', options);
|
||||
responseData.api.cacheExpire = 'TTL ' + (dateExpires - dateLastModified) / 1000 + 's';
|
||||
|
||||
let data = {
|
||||
stickyPanelServerId: config.stickyPanelServerId,
|
||||
stickyPanelClass: config.stickyPanelClass,
|
||||
@@ -466,7 +478,8 @@ define([
|
||||
case 'online':
|
||||
case 'green': return 'txt-color-green';
|
||||
case 'vip':
|
||||
case 'yellow': return 'txt-color-orange';
|
||||
case 'yellow': return 'txt-color-yellow';
|
||||
case 'orange': return 'txt-color-orange';
|
||||
case 'offline':
|
||||
case 'red': return 'txt-color-red';
|
||||
default: return '';
|
||||
|
||||
@@ -163,7 +163,7 @@ define([
|
||||
{icon: 'fa-route', action: 'find_route', text: 'find route'},
|
||||
{icon: 'fa-object-group', action: 'select_connections', text: 'select connections'},
|
||||
{icon: 'fa-reply fa-rotate-180', text: 'waypoints', subitems: [
|
||||
{subIcon: 'fa-flag-checkered', subAction: 'set_destination', subText: 'set destination'},
|
||||
{subIcon: 'fa-flag', subAction: 'set_destination', subText: 'set destination'},
|
||||
{subDivider: true, action: ''},
|
||||
{subIcon: 'fa-step-backward', subAction: 'add_first_waypoint', subText: 'add new [start]'},
|
||||
{subIcon: 'fa-step-forward', subAction: 'add_last_waypoint', subText: 'add new [end]'}
|
||||
|
||||
@@ -6,41 +6,50 @@ define(() => {
|
||||
constructor(config){
|
||||
this._defaultConfig = {
|
||||
container: null, // parent DOM container element
|
||||
center: null, // DOM elements that works as center
|
||||
center: null, // DOM element OR [x,y] coordinates that works as center
|
||||
elementClass: 'pf-system', // class for all elements
|
||||
defaultSteps: 8, // how many potential dimensions are checked on en ellipsis around the center
|
||||
defaultGapX: 50,
|
||||
defaultGapY: 50,
|
||||
gapX: 50, // leave gap between elements (x-axis)
|
||||
gapY: 50, // leave gap between elements (y-axis)
|
||||
minX: 0, // min x for valid elements
|
||||
minY: 0, // min y for valid elements
|
||||
spacingX: 20, // spacing x between elements
|
||||
spacingY: 10, // spacing y between elements
|
||||
loops: 2, // max loops around "center" for search
|
||||
grid: false, // set to [20, 20] to force grid snapping
|
||||
newElementWidth: 100, // width for new element
|
||||
newElementHeight: 22, // height for new element
|
||||
mirrorSearch: false, // if true coordinates are "mirrored" for an "alternating" search
|
||||
debug: false, // render debug elements
|
||||
debugOk: false, // if true, only not overlapped dimensions are rendered for debug
|
||||
debugElementClass: 'pf-system-debug' // class for debug elements
|
||||
};
|
||||
|
||||
this._config = Object.assign({}, this._defaultConfig, config);
|
||||
|
||||
this._config.dimensionCache = {};
|
||||
|
||||
this._cacheKey = (dim, depth) => ['dim', dim.left, dim.top, dim.width, dim.height, depth].join('_');
|
||||
|
||||
/**
|
||||
* convert degree into radial unit
|
||||
* @param deg
|
||||
* @returns {number}
|
||||
* @private
|
||||
*/
|
||||
this._degToRad = (deg) => {
|
||||
return deg * Math.PI / 180;
|
||||
};
|
||||
this._degToRad = deg => deg * Math.PI / 180;
|
||||
|
||||
/**
|
||||
* get element dimension/position of a DOM element
|
||||
* @param element
|
||||
* @returns {*}
|
||||
* @param spacingX
|
||||
* @param spacingY
|
||||
* @returns {{a: *, b: *, top: *, left: *, width: *, height: *}}
|
||||
* @private
|
||||
*/
|
||||
this._getElementDimension = element => {
|
||||
let dim = null;
|
||||
|
||||
this._getElementDimension = (element, spacingX = 0, spacingY = 0) => {
|
||||
let left = 0;
|
||||
let top = 0;
|
||||
let a = 0;
|
||||
@@ -49,7 +58,7 @@ define(() => {
|
||||
let height = this._config.newElementHeight;
|
||||
|
||||
if(Array.isArray(element)){
|
||||
// xy coordinates
|
||||
// x/y coordinates
|
||||
let point = [
|
||||
element[0] ? parseInt(element[0], 10) : 0,
|
||||
element[1] ? parseInt(element[1], 10) : 0
|
||||
@@ -63,14 +72,21 @@ define(() => {
|
||||
top = point[1];
|
||||
a = this._config.gapX;
|
||||
b = this._config.gapY;
|
||||
}else if(element){
|
||||
}else if(element instanceof Element){
|
||||
// DOM element
|
||||
left = element.style.left ? parseInt(element.style.left, 10) : 0;
|
||||
top = element.style.top ? parseInt(element.style.top, 10) : 0;
|
||||
a = parseInt((element.offsetWidth / 2).toString(), 10) + this._config.gapX;
|
||||
b = parseInt((element.offsetHeight / 2).toString(), 10) + this._config.gapY;
|
||||
width = element.offsetWidth;
|
||||
height = element.offsetHeight;
|
||||
left = (element.style.left ? parseInt(element.style.left, 10) : 0) - spacingX;
|
||||
top = (element.style.top ? parseInt(element.style.top, 10) : 0) - spacingY;
|
||||
a = parseInt((element.offsetWidth / 2).toString(), 10) + spacingX + this._config.gapX;
|
||||
b = parseInt((element.offsetHeight / 2).toString(), 10) + spacingY + this._config.gapY;
|
||||
width = element.offsetWidth + 2 * spacingX;
|
||||
height = element.offsetHeight + 2 * spacingY;
|
||||
}else if(element instanceof Object){
|
||||
left = element.left - spacingX;
|
||||
top = element.top - spacingY;
|
||||
a = parseInt((element.width / 2).toString(), 10) + spacingX + this._config.gapX;
|
||||
b = parseInt((element.height / 2).toString(), 10) + spacingY + this._config.gapY;
|
||||
width = element.width + 2 * spacingX;
|
||||
height = element.height + 2 * spacingY;
|
||||
}
|
||||
|
||||
// add "gap" to a and b in order to have some space around elements
|
||||
@@ -121,7 +137,7 @@ define(() => {
|
||||
let dimensions = [];
|
||||
let surroundingElements = this._getContainer().getElementsByClassName(this._config.elementClass);
|
||||
for(let element of surroundingElements){
|
||||
dimensions.push(this._getElementDimension(element));
|
||||
dimensions.push(this._getElementDimension(element, this._config.spacingX, this._config.spacingY));
|
||||
}
|
||||
return dimensions;
|
||||
};
|
||||
@@ -132,7 +148,7 @@ define(() => {
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
this._transformPointToGrid = (point) => {
|
||||
this._transformPointToGrid = point => {
|
||||
point[0] = Math.floor(point[0] / this._config.grid[0]) * this._config.grid[0];
|
||||
point[1] = Math.floor(point[1] / this._config.grid[1]) * this._config.grid[1];
|
||||
return point;
|
||||
@@ -231,31 +247,44 @@ define(() => {
|
||||
return percent;
|
||||
};
|
||||
|
||||
/**
|
||||
* checks whether dim11 has valid x/y coordinate
|
||||
* -> coordinates are >= "minX/Y" limit
|
||||
* @param dim1
|
||||
* @returns {*|boolean}
|
||||
* @private
|
||||
*/
|
||||
this._valid = dim1 => dim1 && dim1.left >= this._config.minX && dim1.top >= this._config.minY;
|
||||
|
||||
/**
|
||||
* checks whether dim1 is partially overlapped by any other element
|
||||
* @param dim1
|
||||
* @param dimensionContainer
|
||||
* @param allDimensions
|
||||
* @param depth
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
this._isOverlapping = (dim1, dimensionContainer, allDimensions) => {
|
||||
this._isOverlapping = (dim1, dimensionContainer, allDimensions, depth) => {
|
||||
let isOverlapping = false;
|
||||
if(dim1){
|
||||
if(this._percentCovered(dimensionContainer, dim1 ) === 100){
|
||||
let cacheKey = this._cacheKey(dim1, depth);
|
||||
// check cache first (e.g. if grid is active some dimensions would be checked multiple times)
|
||||
if(this._config.dimensionCache[cacheKey]){
|
||||
return true;
|
||||
}else if(this._percentCovered(dimensionContainer, dim1) === 100){
|
||||
// element is within parent container
|
||||
for(let dim2 of allDimensions){
|
||||
let percentCovered = this._percentCovered(dim1, dim2);
|
||||
if(percentCovered){
|
||||
isOverlapping = true;
|
||||
// render debug element
|
||||
this._showDebugElement(dim1, percentCovered);
|
||||
this._config.dimensionCache[cacheKey] = percentCovered;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
isOverlapping = true;
|
||||
this._showDebugElement(dim1, 100);
|
||||
this._config.dimensionCache[cacheKey] = 100;
|
||||
}
|
||||
}else{
|
||||
isOverlapping = true;
|
||||
@@ -264,36 +293,63 @@ define(() => {
|
||||
return isOverlapping;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dim1
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
this._existDimension = function(dim1){
|
||||
return (
|
||||
dim1.left === this.left &&
|
||||
dim1.top === this.top &&
|
||||
dim1.width === this.width &&
|
||||
dim1.height === this.height
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* find all dimensions around a centerDimension that are not overlapped by other elements
|
||||
* @param maxResults
|
||||
* @param steps
|
||||
* @param allDimensions
|
||||
* @param depth
|
||||
* @param loops
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
this._findDimensions = (maxResults, steps, allDimensions, loops) => {
|
||||
this._findDimensions = (maxResults, steps, allDimensions, depth, loops) => {
|
||||
steps = steps || 1;
|
||||
loops = loops || 1;
|
||||
|
||||
let dimensions = [];
|
||||
let start = 0;
|
||||
let end = 360;
|
||||
let angle = end / steps;
|
||||
|
||||
// as default coordinates get checked clockwise Q4 -> Q3 -> Q2 -> Q1
|
||||
// we could also check "mirrored" coordinates Q4+Q1 -> Q3+Q2
|
||||
if(this._config.mirrorSearch){
|
||||
end /= end;
|
||||
}
|
||||
|
||||
let dimensionContainer = this._getElementDimension(this._getContainer());
|
||||
steps = steps || 1;
|
||||
loops = loops || 1;
|
||||
|
||||
if(loops === 1){
|
||||
// check center element
|
||||
let centerDimension = this._getElementDimension(this._config.center);
|
||||
if(!this._isOverlapping(centerDimension, dimensionContainer, allDimensions)){
|
||||
if(
|
||||
this._valid(centerDimension) &&
|
||||
!dimensions.some(this._existDimension, centerDimension) &&
|
||||
!this._isOverlapping(centerDimension, dimensionContainer, allDimensions, depth)
|
||||
){
|
||||
dimensions.push({
|
||||
left: centerDimension.left,
|
||||
top: centerDimension.top,
|
||||
width: centerDimension.width,
|
||||
height: centerDimension.height
|
||||
});
|
||||
// render debug element
|
||||
this._showDebugElement(centerDimension, 0);
|
||||
this._config.dimensionCache[this._cacheKey(centerDimension, depth)] = 0;
|
||||
|
||||
maxResults--;
|
||||
}
|
||||
@@ -308,27 +364,38 @@ define(() => {
|
||||
while(maxResults > 0 && start < end){
|
||||
// get all potential coordinates on an eclipse around a given "centerElementDimension"
|
||||
let coordinate = this._getEllipseCoordinates(centerDimension, end);
|
||||
// transform relative x/y coordinate into a absolute 2D area
|
||||
let checkDimension = this._transformCoordinate(centerDimension, coordinate);
|
||||
if(!this._isOverlapping(checkDimension, dimensionContainer, allDimensions)){
|
||||
dimensions.push({
|
||||
left: checkDimension.left,
|
||||
top: checkDimension.top,
|
||||
width: checkDimension.width,
|
||||
height: checkDimension.height
|
||||
});
|
||||
// render debug element
|
||||
this._showDebugElement(checkDimension, 0);
|
||||
|
||||
maxResults--;
|
||||
let coordinates = [coordinate];
|
||||
if(this._config.mirrorSearch && coordinate){
|
||||
coordinates.push({x: coordinate.x, y: coordinate.y * -1 });
|
||||
}
|
||||
|
||||
for(let coordinateTemp of coordinates){
|
||||
// transform relative x/y coordinate into a absolute 2D area
|
||||
let checkDimension = this._transformCoordinate(centerDimension, coordinateTemp);
|
||||
if(
|
||||
this._valid(checkDimension) &&
|
||||
!dimensions.some(this._existDimension, checkDimension) &&
|
||||
!this._isOverlapping(checkDimension, dimensionContainer, allDimensions, depth)
|
||||
){
|
||||
dimensions.push({
|
||||
left: checkDimension.left,
|
||||
top: checkDimension.top,
|
||||
width: checkDimension.width,
|
||||
height: checkDimension.height
|
||||
});
|
||||
this._config.dimensionCache[this._cacheKey(checkDimension, depth)] = 0;
|
||||
|
||||
maxResults--;
|
||||
}
|
||||
}
|
||||
|
||||
end -= angle;
|
||||
}
|
||||
|
||||
if(maxResults > 0 && loops < this._config.loops){
|
||||
loops++;
|
||||
steps *= 2;
|
||||
dimensions = dimensions.concat(this._findDimensions(maxResults, steps, allDimensions, loops));
|
||||
dimensions = dimensions.concat(this._findDimensions(maxResults, steps, allDimensions, depth, loops));
|
||||
}
|
||||
|
||||
return dimensions;
|
||||
@@ -346,21 +413,33 @@ define(() => {
|
||||
/**
|
||||
* render debug element into parent container
|
||||
* -> checks overlapping dimension with other elements
|
||||
* @param dimension
|
||||
* @param percentCovered
|
||||
* @private
|
||||
*/
|
||||
this._showDebugElement = (dimension, percentCovered) => {
|
||||
this._showDebugElements = () => {
|
||||
if(this._config.debug){
|
||||
let element = document.createElement('div');
|
||||
element.style.left = dimension.left + 'px';
|
||||
element.style.top = dimension.top + 'px';
|
||||
element.style.width = dimension.width + 'px';
|
||||
element.style.height = dimension.height + 'px';
|
||||
element.style.backgroundColor = Boolean(percentCovered) ? 'rgba(255,0,0,0.1)' : 'rgba(0,255,0,0.1)';
|
||||
element.innerHTML = Math.round(percentCovered * 100) / 100 + '%';
|
||||
element.classList.add(this._config.debugElementClass);
|
||||
this._getContainer().appendChild(element);
|
||||
let documentFragment = document.createDocumentFragment();
|
||||
for(let [cacheKey, percentCovered] of Object.entries(this._config.dimensionCache)){
|
||||
if(this._config.debugOk && percentCovered){
|
||||
continue;
|
||||
}
|
||||
|
||||
let element = document.createElement('div');
|
||||
let dimParts = cacheKey.split('_');
|
||||
element.style.left = dimParts[1] + 'px';
|
||||
element.style.top = dimParts[2] + 'px';
|
||||
element.style.width = dimParts[3] + 'px';
|
||||
element.style.height = dimParts[4] + 'px';
|
||||
element.style.backgroundColor = Boolean(percentCovered) ? 'rgba(255,0,0,0.1)' : 'rgba(0,255,0,0.4)';
|
||||
element.style.opacity = Boolean(percentCovered) ? 0.5 : 1;
|
||||
element.style.zIndex = Boolean(percentCovered) ? 1000 : 2000;
|
||||
element.style.border = Boolean(percentCovered) ? 'none' : '1px solid rgba(0,255,0,0.3)';
|
||||
element.innerHTML = Math.round(percentCovered * 100) / 100 + '';
|
||||
element.classList.add(this._config.debugElementClass);
|
||||
element.setAttribute('data-depth', dimParts[5]);
|
||||
documentFragment.appendChild(element);
|
||||
}
|
||||
|
||||
this._getContainer().appendChild(documentFragment);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -381,15 +460,45 @@ define(() => {
|
||||
/**
|
||||
* search for surrounding, non overlapping dimensions
|
||||
* @param maxResults
|
||||
* @param steps
|
||||
* @param findChain
|
||||
* @returns {Array}
|
||||
*/
|
||||
this.findNonOverlappingDimensions = (maxResults, steps) => {
|
||||
this.findNonOverlappingDimensions = (maxResults, findChain = false) => {
|
||||
this._hideDebugElements();
|
||||
this._config.dimensionCache = {};
|
||||
|
||||
// element dimensions that exist and should be checked for overlapping
|
||||
let allDimensions = this._getAllElementDimensions();
|
||||
let dimensions = [];
|
||||
let depth = 1;
|
||||
let maxDepth = findChain ? maxResults : 1;
|
||||
maxResults = findChain ? 1 : maxResults;
|
||||
while(depth <= maxDepth){
|
||||
let dimensionsTemp = this._findDimensions(maxResults, this._config.defaultSteps, allDimensions, depth);
|
||||
|
||||
return this._findDimensions(maxResults, steps, allDimensions);
|
||||
if(dimensionsTemp.length){
|
||||
dimensions = dimensions.concat(dimensionsTemp);
|
||||
|
||||
if(findChain){
|
||||
// if depth > 0 we have 2D dimension as "center" (not a x/y coordinate)
|
||||
// -> increase the gap
|
||||
this._config.defaultGapX = 10;
|
||||
this._config.defaultGapY = 10;
|
||||
this._config.gapX = 50;
|
||||
this._config.gapY = 50;
|
||||
this._config.center = dimensionsTemp[0];
|
||||
allDimensions = allDimensions.concat([this._getElementDimension(dimensionsTemp[0], this._config.spacingX, this._config.spacingY)]);
|
||||
}
|
||||
|
||||
depth++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._showDebugElements();
|
||||
|
||||
return dimensions;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ define([
|
||||
_: (data, type, row, meta) => {
|
||||
let value = data.typeName;
|
||||
if(type === 'display'){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Render/' + data.typeId + '_32.png"/>';
|
||||
value = '<img src="' + Util.eveImageUrl('render', data.typeId) + '"/>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -546,13 +546,16 @@ define([
|
||||
system.data('region', data.region.name);
|
||||
system.data('constellationId', parseInt(data.constellation.id));
|
||||
system.data('constellation', data.constellation.name);
|
||||
system.data('faction', data.faction);
|
||||
system.data('planets', data.planets);
|
||||
system.data('shattered', data.shattered);
|
||||
system.data('drifter', data.drifter);
|
||||
system.data('statics', data.statics);
|
||||
system.data('updated', parseInt(data.updated.updated));
|
||||
system.data('changed', false);
|
||||
system.attr('data-mapid', parseInt(mapContainer.data('id')));
|
||||
if(data.sovereignty){
|
||||
system.data('sovereignty', data.sovereignty);
|
||||
}
|
||||
|
||||
// locked system
|
||||
if( Boolean(system.data('locked')) !== data.locked ){
|
||||
@@ -660,20 +663,10 @@ define([
|
||||
case 'add_system':
|
||||
// add new system dialog
|
||||
let position = Layout.getEventCoordinates(e);
|
||||
|
||||
let grid = [MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension];
|
||||
let positionFinder = new Layout.Position({
|
||||
container: mapElement[0],
|
||||
center: [position.x, position.y],
|
||||
loops: 5,
|
||||
defaultGapX: 10,
|
||||
defaultGapY: 10,
|
||||
grid: mapElement.hasClass(MapUtil.config.mapGridClass) ? grid : false,
|
||||
debug: false
|
||||
let dimensions = MapUtil.newSystemPositionByCoordinates(mapElement, {
|
||||
center: [position.x, position.y]
|
||||
});
|
||||
|
||||
let dimensions = positionFinder.findNonOverlappingDimensions(1, 8);
|
||||
|
||||
if(dimensions.length){
|
||||
position.x = dimensions[0].left;
|
||||
position.y = dimensions[0].top;
|
||||
@@ -1212,7 +1205,7 @@ define([
|
||||
mapConfig.map.setContainer(mapContainer);
|
||||
|
||||
// init custom scrollbars and add overlay
|
||||
parentElement.initMapScrollbar();
|
||||
initMapScrollbar(mapWrapper);
|
||||
|
||||
// set map observer
|
||||
setMapObserver(mapConfig.map);
|
||||
@@ -2708,7 +2701,7 @@ define([
|
||||
|
||||
if(select){
|
||||
let mapWrapper = mapContainer.closest('.' + config.mapWrapperClass);
|
||||
Scrollbar.scrollToSystem(mapWrapper, MapUtil.getSystemPosition(system));
|
||||
Scrollbar.scrollToCenter(mapWrapper, system);
|
||||
// select system
|
||||
MapUtil.showSystemInfo(map, system);
|
||||
}
|
||||
@@ -3046,47 +3039,59 @@ define([
|
||||
*/
|
||||
$.fn.getSystemData = function(minimal = false){
|
||||
let system = $(this);
|
||||
let data = system.data();
|
||||
|
||||
let systemData = {
|
||||
id: parseInt(system.data('id')),
|
||||
id: parseInt(data.id),
|
||||
updated: {
|
||||
updated: parseInt(system.data('updated'))
|
||||
updated: parseInt(data.updated)
|
||||
}
|
||||
};
|
||||
|
||||
if(!minimal){
|
||||
systemData = Object.assign(systemData, {
|
||||
systemId: parseInt(system.data('systemId')),
|
||||
name: system.data('name'),
|
||||
let systemDataComplete = {
|
||||
systemId: parseInt(data.systemId),
|
||||
name: data.name,
|
||||
alias: system.getSystemInfo(['alias']),
|
||||
effect: system.data('effect'),
|
||||
effect: data.effect,
|
||||
type: {
|
||||
id: system.data('typeId')
|
||||
id: data.typeId
|
||||
},
|
||||
security: system.data('security'),
|
||||
trueSec: system.data('trueSec'),
|
||||
security: data.security,
|
||||
trueSec: data.trueSec,
|
||||
region: {
|
||||
id: system.data('regionId'),
|
||||
name: system.data('region')
|
||||
id: data.regionId,
|
||||
name: data.region
|
||||
},
|
||||
constellation: {
|
||||
id: system.data('constellationId'),
|
||||
name: system.data('constellation')
|
||||
id: data.constellationId,
|
||||
name: data.constellation
|
||||
},
|
||||
status: {
|
||||
id: system.data('statusId')
|
||||
id: data.statusId
|
||||
},
|
||||
locked: system.data('locked') ? 1 : 0,
|
||||
rallyUpdated: system.data('rallyUpdated') || 0,
|
||||
rallyPoke: system.data('rallyPoke') ? 1 : 0,
|
||||
currentUser: system.data('currentUser'), // if user is currently in this system
|
||||
faction: system.data('faction'),
|
||||
planets: system.data('planets'),
|
||||
shattered: system.data('shattered') ? 1 : 0,
|
||||
statics: system.data('statics'),
|
||||
userCount: (system.data('userCount') ? parseInt(system.data('userCount')) : 0),
|
||||
locked: data.locked ? 1 : 0,
|
||||
rallyUpdated: data.rallyUpdated || 0,
|
||||
rallyPoke: data.rallyPoke ? 1 : 0,
|
||||
currentUser: data.currentUser, // if user is currently in this system
|
||||
planets: data.planets,
|
||||
shattered: data.shattered ? 1 : 0,
|
||||
drifter: data.drifter ? 1 : 0,
|
||||
statics: data.statics,
|
||||
userCount: parseInt(data.userCount) || 0,
|
||||
position: MapUtil.getSystemPosition(system)
|
||||
});
|
||||
};
|
||||
|
||||
let optionalDataKeys = ['sovereignty'];
|
||||
|
||||
for(let dataKey of optionalDataKeys){
|
||||
let value = system.data(dataKey);
|
||||
if(value !== null && value !== undefined){
|
||||
systemDataComplete[dataKey] = value;
|
||||
}
|
||||
}
|
||||
|
||||
systemData = Object.assign(systemData, systemDataComplete);
|
||||
}
|
||||
|
||||
return systemData;
|
||||
@@ -3166,15 +3171,13 @@ define([
|
||||
|
||||
/**
|
||||
* init scrollbar for Map element
|
||||
* @param mapWrapper
|
||||
*/
|
||||
$.fn.initMapScrollbar = function(){
|
||||
// get Map Scrollbar
|
||||
let mapTabContentElement = $(this);
|
||||
let mapWrapperElement = mapTabContentElement.find('.' + config.mapWrapperClass);
|
||||
let mapElement = mapTabContentElement.find('.' + config.mapClass);
|
||||
let initMapScrollbar = mapWrapper => {
|
||||
let mapElement = mapWrapper.find('.' + config.mapClass);
|
||||
let mapId = mapElement.data('id');
|
||||
|
||||
mapWrapperElement.initCustomScrollbar({
|
||||
Scrollbar.initScrollbar(mapWrapper, {
|
||||
callbacks: {
|
||||
onInit: function(){
|
||||
// init 'space' key + 'mouse' down for map scroll -------------------------------------------------
|
||||
@@ -3291,8 +3294,8 @@ define([
|
||||
// ------------------------------------------------------------------------------------------------------------
|
||||
// add map overlays after scrollbar is initialized
|
||||
// because of its absolute position
|
||||
mapWrapperElement.initMapOverlays();
|
||||
mapWrapperElement.initLocalOverlay(mapId);
|
||||
mapWrapper.initMapOverlays();
|
||||
mapWrapper.initLocalOverlay(mapId);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -370,15 +370,16 @@ define([
|
||||
// init popover if not already exists
|
||||
if(!systemHead.data('bs.popover')){
|
||||
let system = systemHead.parent();
|
||||
let systemData = system.data();
|
||||
systemHead.popover({
|
||||
placement: 'right',
|
||||
placement: 'bottom',
|
||||
html: true,
|
||||
trigger: 'manual',
|
||||
container: mapElement,
|
||||
title: false,
|
||||
content: Util.getSystemRegionTable(
|
||||
system.data('region'),
|
||||
system.data('faction') || null
|
||||
Util.getObjVal(systemData, 'region'),
|
||||
Util.getObjVal(systemData, 'sovereignty')
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,73 +1,129 @@
|
||||
/**
|
||||
* Created by Exodus on 26.06.2016.
|
||||
*/
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'mousewheel',
|
||||
'customScrollbar'
|
||||
], ($, Init, Util) => {
|
||||
], ($) => {
|
||||
'use strict';
|
||||
|
||||
let defaultConfig = {
|
||||
axis: 'yx',
|
||||
theme: 'light-3' ,
|
||||
scrollInertia: 200,
|
||||
autoExpandScrollbar: false,
|
||||
scrollButtons:{
|
||||
enable: true,
|
||||
scrollAmount: 30,
|
||||
scrollType: 'stepless'
|
||||
},
|
||||
callbacks: {
|
||||
onTotalScrollOffset: 0,
|
||||
onTotalScrollBackOffset: 0,
|
||||
alwaysTriggerOffsets: true
|
||||
},
|
||||
|
||||
advanced: {
|
||||
autoUpdateTimeout: 120, // auto-update timeout (default: 60)
|
||||
updateOnContentResize: true,
|
||||
autoExpandHorizontalScroll: false, // on resize css scale() scroll content should not change
|
||||
//autoExpandHorizontalScroll: 2,
|
||||
autoScrollOnFocus: 'div',
|
||||
},
|
||||
mouseWheel: {
|
||||
enable: false, // scroll wheel currently disabled
|
||||
scrollAmount: 'auto',
|
||||
axis: 'x',
|
||||
preventDefault: true
|
||||
},
|
||||
keyboard: {
|
||||
enable: false, // not working with pathfinder "shortcuts"
|
||||
scrollType: 'stepless',
|
||||
scrollAmount: 'auto'
|
||||
},
|
||||
scrollbarPosition: 'inside',
|
||||
autoDraggerLength: true,
|
||||
autoHideScrollbar: false
|
||||
};
|
||||
|
||||
/**
|
||||
* init map scrollbar
|
||||
* @param scrollWrapper
|
||||
* @param config
|
||||
*/
|
||||
$.fn.initCustomScrollbar = function(config){
|
||||
|
||||
// default config -------------------------------------------------------------------------
|
||||
let defaultConfig = {
|
||||
axis: 'yx',
|
||||
theme: 'light-3' ,
|
||||
scrollInertia: 300,
|
||||
autoExpandScrollbar: false,
|
||||
scrollButtons:{
|
||||
enable: true,
|
||||
scrollAmount: 30,
|
||||
scrollType: 'stepless'
|
||||
},
|
||||
callbacks: {
|
||||
onTotalScrollOffset: 0,
|
||||
onTotalScrollBackOffset: 0,
|
||||
alwaysTriggerOffsets: true
|
||||
},
|
||||
|
||||
advanced: {
|
||||
autoUpdateTimeout: 120, // auto-update timeout (default: 60)
|
||||
updateOnContentResize: true,
|
||||
autoExpandHorizontalScroll: false, // on resize css scale() scroll content should not change
|
||||
//autoExpandHorizontalScroll: 2,
|
||||
autoScrollOnFocus: 'div',
|
||||
},
|
||||
mouseWheel: {
|
||||
enable: false, // scroll wheel currently disabled
|
||||
scrollAmount: 'auto',
|
||||
axis: 'x',
|
||||
preventDefault: true
|
||||
},
|
||||
keyboard: {
|
||||
enable: false, // not working with pathfinder "shortcuts"
|
||||
scrollType: 'stepless',
|
||||
scrollAmount: 'auto'
|
||||
},
|
||||
scrollbarPosition: 'inside',
|
||||
autoDraggerLength: true,
|
||||
autoHideScrollbar: false
|
||||
};
|
||||
|
||||
// init -----------------------------------------------------------------------------------
|
||||
let initScrollbar = (scrollWrapper, config) => {
|
||||
config = $.extend(true, {}, defaultConfig, config);
|
||||
|
||||
return this.each(function(){
|
||||
let mapWrapperElement = $(this);
|
||||
scrollWrapper.mCustomScrollbar(config);
|
||||
};
|
||||
|
||||
// prevent multiple initialization
|
||||
mapWrapperElement.mCustomScrollbar('destroy');
|
||||
/**
|
||||
* get mCustomScrollbar container
|
||||
* @param element
|
||||
* @returns {*|[]}
|
||||
*/
|
||||
let getContainer = element => element.parents('.mCSB_container');
|
||||
|
||||
// init custom scrollbars
|
||||
mapWrapperElement.mCustomScrollbar(config);
|
||||
});
|
||||
/**
|
||||
*
|
||||
* @param container
|
||||
* @param element
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
let getElementPos = (container, element) => {
|
||||
return {
|
||||
x: element.offset().left - container.offset().left,
|
||||
y: element.offset().top - container.offset().top
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @param element
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
let getElementDim = element => {
|
||||
return {
|
||||
x: element.outerWidth(false),
|
||||
y: element.outerHeight(false)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* check if an element is 100% visible
|
||||
* -> scrolled into viewport
|
||||
* @param element
|
||||
* @returns {boolean}
|
||||
*/
|
||||
let isInView = element => {
|
||||
let container = getContainer(element);
|
||||
let wrapper = container.parent();
|
||||
let cPos = {x: container[0].offsetLeft, y: container[0].offsetTop};
|
||||
let ePos = getElementPos(container, element);
|
||||
let eDim = getElementDim(element);
|
||||
|
||||
return cPos.y + ePos.y >= 0 &&
|
||||
cPos.y + ePos.y < wrapper.height() - eDim.y &&
|
||||
cPos.x + ePos.x >= 0 &&
|
||||
cPos.x + ePos.x < wrapper.width() - eDim.x;
|
||||
};
|
||||
|
||||
/**
|
||||
* get new scrollTo coordinates to center element in viewport
|
||||
* @param element
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
let getCenterScrollPosition = element => {
|
||||
let container = getContainer(element);
|
||||
let wrapper = container.parent();
|
||||
let cDim = getElementDim(container);
|
||||
let wDim = {x: wrapper.width(), y: wrapper.height()};
|
||||
let eDim = getElementDim(element);
|
||||
let ePos = getElementPos(container, element);
|
||||
|
||||
let eOff = {
|
||||
x: (-wDim.x / 2) + (eDim.x / 2),
|
||||
y: (-wDim.y / 2) + (eDim.y / 2)
|
||||
};
|
||||
|
||||
return adjustPos(addOffset(ePos, eOff), cDim);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -82,33 +138,55 @@ define([
|
||||
};
|
||||
|
||||
/**
|
||||
* scroll to a specific system on map
|
||||
* scroll to center an element
|
||||
* -> subtract some offset for tooltips/connections
|
||||
* @param scrollWrapper
|
||||
* @param position
|
||||
* @param options
|
||||
* @param element
|
||||
*/
|
||||
let scrollToSystem = (scrollWrapper, position, options) => {
|
||||
position = getOffsetPosition(position, {x: -15, y: -35});
|
||||
scrollToPosition(scrollWrapper, position, options);
|
||||
let scrollToCenter = (scrollWrapper, element) => {
|
||||
// no scroll if element is already FULL visible in scrollable viewport
|
||||
if(!isInView(element)){
|
||||
// get scrollTo position for centered element
|
||||
scrollToPosition(scrollWrapper, getCenterScrollPosition(element));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* add/subtract offset coordinates from position
|
||||
* -> no negative values returned
|
||||
* @param position
|
||||
* @param offset
|
||||
* @param {{x: number, y: number}} position
|
||||
* @param {{x: number, y: number}} offset
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
let getOffsetPosition = (position, offset) => {
|
||||
return {
|
||||
x: Math.max(0, position.x + offset.x),
|
||||
y: Math.max(0, position.y + offset.y)
|
||||
};
|
||||
};
|
||||
let addOffset = (position, offset) => mapObject(position, (v, k) => v + offset[k]);
|
||||
|
||||
/**
|
||||
* round position
|
||||
* @param {{x: number, y: number}} position
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
let roundPos = position => mapObject(position, Math.round);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{x: number, y: number}} position
|
||||
* @param {{x: number, y: number}} dimension
|
||||
* @returns {{x: number, y: number}}
|
||||
*/
|
||||
let adjustPos = (position, dimension) => mapObject(roundPos(position), (v, k) => Math.max(1, Math.min(dimension[k], v)) );
|
||||
|
||||
/**
|
||||
* like Array.map() for objects
|
||||
* -> callback f is called for each property
|
||||
* @see https://stackoverflow.com/a/38829074/4329969
|
||||
* @param o
|
||||
* @param f
|
||||
* @returns {Object}
|
||||
*/
|
||||
let mapObject = (o, f) => Object.assign(...Object.entries(o).map(([k, v]) => ({[k]: f(v, k) })));
|
||||
|
||||
return {
|
||||
initScrollbar: initScrollbar,
|
||||
scrollToPosition: scrollToPosition,
|
||||
scrollToSystem: scrollToSystem
|
||||
scrollToCenter: scrollToCenter
|
||||
};
|
||||
});
|
||||
@@ -9,9 +9,8 @@ define([
|
||||
'app/util',
|
||||
'bootbox',
|
||||
'app/map/util',
|
||||
'app/map/layout',
|
||||
'app/map/magnetizing'
|
||||
], ($, Init, Util, bootbox, MapUtil, Layout, Magnetizer) => {
|
||||
], ($, Init, Util, bootbox, MapUtil, Magnetizer) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -245,7 +244,7 @@ define([
|
||||
sourceSystem = options.sourceSystem;
|
||||
|
||||
// get new position
|
||||
newPosition = calculateNewSystemPosition(sourceSystem);
|
||||
newPosition = newSystemPositionBySystem(sourceSystem);
|
||||
}else if(options.position){
|
||||
// check mouse cursor position (add system to map)
|
||||
newPosition = {
|
||||
@@ -730,25 +729,16 @@ define([
|
||||
};
|
||||
|
||||
/**
|
||||
* calculate the x/y coordinates for a new system - relativ to a source system
|
||||
* calculate the x/y coordinates for a new system - relative to a source system
|
||||
* -> in case no coordinates found -> return default calculated coordinates
|
||||
* @param sourceSystem
|
||||
* @returns {{x: *, y: *}}
|
||||
*/
|
||||
let calculateNewSystemPosition = sourceSystem => {
|
||||
let mapContainer = sourceSystem.parent();
|
||||
let grid = [MapUtil.config.mapSnapToGridDimension, MapUtil.config.mapSnapToGridDimension];
|
||||
let newSystemPositionBySystem = sourceSystem => {
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
let positionFinder = new Layout.Position({
|
||||
container: mapContainer[0],
|
||||
center: sourceSystem[0],
|
||||
loops: 4,
|
||||
grid: mapContainer.hasClass(MapUtil.config.mapGridClass) ? grid : false,
|
||||
debug: false
|
||||
});
|
||||
|
||||
let dimensions = positionFinder.findNonOverlappingDimensions(1, 16);
|
||||
let dimensions = MapUtil.newSystemPositionBySystem(sourceSystem);
|
||||
if(dimensions.length){
|
||||
//... empty map space found
|
||||
x = dimensions[0].left;
|
||||
@@ -780,8 +770,12 @@ define([
|
||||
let headInfoLeft = [];
|
||||
let headInfoRight = [];
|
||||
|
||||
if(data.drifter){
|
||||
headInfoLeft.push('<i class="fas fa-fw fa-wave-square ' + Util.getSecurityClassForSystem(data.security) + '" title="drifter"></i>');
|
||||
}
|
||||
|
||||
if(data.shattered){
|
||||
headInfoLeft.push('<i class="fas fa-fw fa-skull ' + Util.getSecurityClassForSystem('SH') + '" title="shattered"></i>');
|
||||
headInfoLeft.push('<i class="fas fa-fw fa-chart-pie ' + Util.getSecurityClassForSystem('SH') + '" title="shattered"></i>');
|
||||
}
|
||||
|
||||
// check systemData if headInfo element is needed
|
||||
|
||||
@@ -6,9 +6,10 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/layout',
|
||||
'app/map/scrollbar',
|
||||
'app/map/overlay/util'
|
||||
], ($, Init, Util, Scrollbar, MapOverlayUtil) => {
|
||||
], ($, Init, Util, Layout, Scrollbar, MapOverlayUtil) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -806,10 +807,9 @@ define([
|
||||
|
||||
// collect all required data from map module to update the info element
|
||||
// store them global and assessable for each module
|
||||
Util.setCurrentSystemData({
|
||||
systemData: system.getSystemData(),
|
||||
mapId: parseInt( system.attr('data-mapid') )
|
||||
});
|
||||
let systemData = system.getSystemData();
|
||||
systemData.mapId = parseInt(system.attr('data-mapid')) || 0;
|
||||
Util.setCurrentSystemData(systemData);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1764,6 +1764,91 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* add station services tooltip
|
||||
* @param services
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.addStationServiceTooltip = function(services, options){
|
||||
let getServiceIcon = service => {
|
||||
switch(service){
|
||||
case 'bounty-missions': return false;
|
||||
case 'assasination-missions': return false;
|
||||
case 'courier-missions': return false;
|
||||
case 'interbus': return false;
|
||||
case 'reprocessing-plant': return 'reprocess';
|
||||
case 'refinery': return false;
|
||||
case 'market': return 'market';
|
||||
case 'black-market': return false;
|
||||
case 'stock-exchange': return false;
|
||||
case 'cloning': return 'clonebay';
|
||||
case 'surgery': return false;
|
||||
case 'dna-therapy': return false;
|
||||
case 'repair-facilities': return 'repairshop';
|
||||
case 'factory': return 'industry';
|
||||
case 'labratory': return 'research';
|
||||
case 'gambling': return false;
|
||||
case 'fitting': return 'fitting';
|
||||
case 'paintshop': return 'skins';
|
||||
case 'news': return false;
|
||||
case 'storage': return false;
|
||||
case 'insurance': return 'insurance';
|
||||
case 'docking': return 'docking';
|
||||
case 'office-rental': return false;
|
||||
case 'jump-clone-facility': return 'jumpclones';
|
||||
case 'loyalty-point-store': return 'lpstore';
|
||||
case 'navy-offices': return 'factionalwarfare';
|
||||
case 'security-offices': return 'concord';
|
||||
default: return false;
|
||||
}
|
||||
};
|
||||
|
||||
let getStationServicesTable = services => {
|
||||
let content = '';
|
||||
for(let i = 0; i < services.length; i++){
|
||||
let icon = getServiceIcon(services[i]);
|
||||
if(icon){
|
||||
content += '<img class="' + Util.config.popoverListIconClass + '" src="/public/img/icons/client/ui/window/' + icon + '.png" alt="' + services[i] + '">';
|
||||
}
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
let content = getStationServicesTable(services);
|
||||
|
||||
let title = '<i class="fas fa-tools fa-fw"></i> Services';
|
||||
|
||||
let defaultOptions = {
|
||||
placement: 'top',
|
||||
html: true,
|
||||
trigger: 'hover',
|
||||
container: 'body',
|
||||
title: title,
|
||||
content: '',
|
||||
delay: {
|
||||
show: 150,
|
||||
hide: 0
|
||||
},
|
||||
};
|
||||
|
||||
options = $.extend({}, defaultOptions, options);
|
||||
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
element.popover(options);
|
||||
|
||||
// set new popover content
|
||||
let popover = element.data('bs.popover');
|
||||
popover.options.content = content;
|
||||
popover.tip().addClass(Util.config.popoverClass);
|
||||
|
||||
if(options.show){
|
||||
element.popover('show');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* add system effect tooltip
|
||||
* @param security
|
||||
@@ -1774,9 +1859,11 @@ define([
|
||||
$.fn.addSystemEffectTooltip = function(security, effect, options){
|
||||
let effectClass = getEffectInfoForSystem(effect, 'class');
|
||||
let systemEffectData = Util.getSystemEffectData(security, effect);
|
||||
let areaId = Util.getAreaIdBySecurity(security);
|
||||
|
||||
let title = '<i class="fas fa-square fa-fw ' + effectClass + '"></i> ' +
|
||||
getEffectInfoForSystem(effect, 'name') +
|
||||
getEffectInfoForSystem(effect, 'name') + ' ' +
|
||||
'<kbd>' + Util.getSystemEffectMultiplierByAreaId(parseInt(areaId)) + 'x' + '</kbd>' +
|
||||
'<span class="pull-right ' + Util.getSecurityClassForSystem(security) + '">' + security + '</span>';
|
||||
|
||||
let content = Util.getSystemEffectTable(systemEffectData);
|
||||
@@ -1808,7 +1895,6 @@ define([
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.addSystemPlanetsTooltip = function(planets, options){
|
||||
|
||||
let content = Util.getSystemPlanetsTable(planets);
|
||||
|
||||
let defaultOptions = {
|
||||
@@ -1869,10 +1955,10 @@ define([
|
||||
if(tooltipData.maxStableTime){
|
||||
data.maxStableTime = tooltipData.maxStableTime + ' h';
|
||||
}
|
||||
if(tooltipData.signatureStrength){
|
||||
data.signatureStrength = parseFloat(tooltipData.signatureStrength).toLocaleString() + ' %';
|
||||
if(tooltipData.scanWormholeStrength){
|
||||
data.scanWormholeStrength = parseFloat(tooltipData.scanWormholeStrength).toLocaleString() + ' %';
|
||||
}else{
|
||||
data.signatureStrength = '<span class="txt-color txt-color-grayLight">unknown</span>';
|
||||
data.scanWormholeStrength = '<span class="txt-color txt-color-grayLight">unknown</span>';
|
||||
}
|
||||
|
||||
let title = tooltipData.name;
|
||||
@@ -2029,6 +2115,132 @@ define([
|
||||
return hasAccess;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param options
|
||||
* @param maxResults
|
||||
* @param findChain
|
||||
* @returns {Array}
|
||||
*/
|
||||
let findNonOverlappingDimensions = (options = {}, maxResults = 1, findChain = false) => {
|
||||
let defaultOptions = {
|
||||
center: [0, 30],
|
||||
loops: 4,
|
||||
debug: false
|
||||
};
|
||||
|
||||
options = Object.assign({}, defaultOptions, options);
|
||||
let positionFinder = new Layout.Position(Object.assign({}, defaultOptions, options));
|
||||
|
||||
return positionFinder.findNonOverlappingDimensions(maxResults, findChain);
|
||||
};
|
||||
|
||||
/**
|
||||
* calculate the x/y coordinates for a new system - relative to a source system
|
||||
* @param sourceSystem
|
||||
* @returns {Array}
|
||||
*/
|
||||
let newSystemPositionBySystem = sourceSystem => {
|
||||
let mapContainer = sourceSystem.parent();
|
||||
let grid = [config.mapSnapToGridDimension, config.mapSnapToGridDimension];
|
||||
|
||||
let options = {
|
||||
container: mapContainer[0],
|
||||
center: sourceSystem[0],
|
||||
grid: mapContainer.hasClass(config.mapGridClass) ? grid : false
|
||||
};
|
||||
|
||||
return findNonOverlappingDimensions(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* calculate the x/y coordinates for a new system - relative to x/y position
|
||||
* @param mapContainer
|
||||
* @param options
|
||||
* @param maxResults
|
||||
* @param findChain
|
||||
* @returns {Array}
|
||||
*/
|
||||
let newSystemPositionByCoordinates = (mapContainer, options = {}, maxResults = 1, findChain = false) => {
|
||||
let grid = [config.mapSnapToGridDimension, config.mapSnapToGridDimension];
|
||||
|
||||
let defaultOptions = {
|
||||
container: mapContainer[0],
|
||||
center: [0, 0],
|
||||
grid: mapContainer.hasClass(config.mapGridClass) ? grid : false,
|
||||
loops: 10,
|
||||
defaultGapX: 10,
|
||||
defaultGapY: 10,
|
||||
//debugOk: true,
|
||||
//debug: true
|
||||
};
|
||||
|
||||
options = Object.assign({}, defaultOptions, options);
|
||||
|
||||
return findNonOverlappingDimensions(options, maxResults, findChain);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mapContainer
|
||||
*/
|
||||
let newSystemPositionsByMap = mapContainer => {
|
||||
let positions = {};
|
||||
|
||||
if(mapContainer){
|
||||
let mapId = mapContainer.data('id');
|
||||
let scrollPosition = {
|
||||
x: Math.abs(parseInt(mapContainer.attr('data-scroll-left')) || 0),
|
||||
y: Math.abs(parseInt(mapContainer.attr('data-scroll-top')) || 0)
|
||||
};
|
||||
|
||||
// space new positions from map top (e.g. used for tooltips)
|
||||
scrollPosition.y = Math.max(scrollPosition.y, 30);
|
||||
|
||||
// default position -> current map section top/left -------------------------------------------------------
|
||||
positions.defaults = [scrollPosition];
|
||||
|
||||
// check default position for overlapping -----------------------------------------------------------------
|
||||
let dimensions = newSystemPositionByCoordinates(mapContainer, {
|
||||
center: [scrollPosition.x, scrollPosition.y],
|
||||
minX: scrollPosition.x,
|
||||
minY: scrollPosition.y
|
||||
}, 2, true);
|
||||
|
||||
if(dimensions.length){
|
||||
positions.defaults = dimensions.map(dim => ({
|
||||
x: parseInt(dim.left) || 0,
|
||||
y: parseInt(dim.top) || 0
|
||||
}));
|
||||
}
|
||||
|
||||
// -> calc possible coordinates for new system that should be used based on current user location ---------
|
||||
let currentLocationData = Util.getCurrentLocationData();
|
||||
if(currentLocationData.id){
|
||||
// ... we need to the PF systemId for 'SelectSystem' trigger
|
||||
let systemData = getSystemData(mapId, currentLocationData.id, 'systemId');
|
||||
if(systemData){
|
||||
let currentSystem = $('#' + getSystemId(mapId, systemData.id));
|
||||
if(currentSystem.length){
|
||||
let dimensions = newSystemPositionBySystem(currentSystem);
|
||||
if(dimensions.length){
|
||||
//... empty map space found
|
||||
positions.location = {
|
||||
systemId: currentLocationData.id,
|
||||
position: {
|
||||
x: dimensions[0].left,
|
||||
y: dimensions[0].top
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(positions).length ? positions : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* get a unique map url for deeplinking
|
||||
* @param mapId
|
||||
@@ -2108,6 +2320,9 @@ define([
|
||||
initWormholeInfoTooltip: initWormholeInfoTooltip,
|
||||
getSystemId: getSystemId,
|
||||
checkRight: checkRight,
|
||||
newSystemPositionBySystem: newSystemPositionBySystem,
|
||||
newSystemPositionByCoordinates: newSystemPositionByCoordinates,
|
||||
newSystemPositionsByMap: newSystemPositionsByMap,
|
||||
getMapDeeplinkUrl: getMapDeeplinkUrl
|
||||
};
|
||||
});
|
||||
@@ -9,10 +9,11 @@ define([
|
||||
'app/logging',
|
||||
'app/page',
|
||||
'app/map/worker',
|
||||
'app/map/util',
|
||||
'app/module_map',
|
||||
'app/key',
|
||||
'app/ui/form_element'
|
||||
], ($, Init, Util, Logging, Page, MapWorker, ModuleMap) => {
|
||||
], ($, Init, Util, Logging, Page, MapWorker, MapUtil, ModuleMap) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -31,6 +32,9 @@ define([
|
||||
// set default dialog config
|
||||
Util.initDefaultBootboxConfig();
|
||||
|
||||
// set default confirmation popover config
|
||||
Util.initDefaultConfirmationConfig();
|
||||
|
||||
// set default select2 config
|
||||
Util.initDefaultSelect2Config();
|
||||
|
||||
@@ -444,7 +448,7 @@ define([
|
||||
// start user update trigger after map loaded
|
||||
updateTimeouts.userUpdate = setTimeout(() => {
|
||||
triggerUserUpdatePing();
|
||||
}, 1000);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -461,11 +465,13 @@ define([
|
||||
|
||||
// IMPORTANT: Get user data for ONE map that is currently visible
|
||||
// On later releases this can be easy changed to "full update" all maps for a user
|
||||
//
|
||||
let mapIds = [];
|
||||
let newSystemPositions = null;
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
|
||||
if(activeMap){
|
||||
mapIds = [ activeMap.data('id') ];
|
||||
mapIds = [activeMap.data('id')];
|
||||
newSystemPositions = MapUtil.newSystemPositionsByMap(activeMap);
|
||||
}
|
||||
|
||||
let updatedUserData = {
|
||||
@@ -475,6 +481,10 @@ define([
|
||||
systemData: Util.getCurrentSystemData()
|
||||
};
|
||||
|
||||
if(newSystemPositions){
|
||||
updatedUserData.newSystemPositions = newSystemPositions;
|
||||
}
|
||||
|
||||
Util.timeStart(logKeyServerUserData);
|
||||
|
||||
$.ajax({
|
||||
|
||||
@@ -353,7 +353,7 @@ define([
|
||||
|
||||
// request "additional" system data (e.g. Structures, Description)
|
||||
// -> this is used to update some modules after initial draw
|
||||
let promiseRequestData = Util.request('GET', 'system', currentSystemData.systemData.id, {mapId: currentSystemData.mapId});
|
||||
let promiseRequestData = Util.request('GET', 'system', currentSystemData.id, {mapId: currentSystemData.mapId});
|
||||
|
||||
// draw modules -------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -361,22 +361,22 @@ define([
|
||||
let secondCell = tabContentElement.find('.' + config.mapTabContentCellSecond);
|
||||
|
||||
// draw system info module
|
||||
let promiseInfo = drawModule(firstCell, SystemInfoModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
let promiseInfo = drawModule(firstCell, SystemInfoModule, currentSystemData.mapId, currentSystemData);
|
||||
|
||||
// draw system graph module
|
||||
drawModule(firstCell, SystemGraphModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
drawModule(firstCell, SystemGraphModule, currentSystemData.mapId, currentSystemData);
|
||||
|
||||
// draw signature table module
|
||||
let promiseSignature = drawModule(firstCell, SystemSignatureModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
let promiseSignature = drawModule(firstCell, SystemSignatureModule, currentSystemData.mapId, currentSystemData);
|
||||
|
||||
// draw system routes module
|
||||
drawModule(secondCell, SystemRouteModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
drawModule(secondCell, SystemRouteModule, currentSystemData.mapId, currentSystemData);
|
||||
|
||||
// draw system intel module
|
||||
let promiseIntel = drawModule(secondCell, SystemIntelModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
let promiseIntel = drawModule(secondCell, SystemIntelModule, currentSystemData.mapId, currentSystemData);
|
||||
|
||||
// draw system killboard module
|
||||
drawModule(secondCell, SystemKillboardModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
drawModule(secondCell, SystemKillboardModule, currentSystemData.mapId, currentSystemData);
|
||||
|
||||
// update some modules ------------------------------------------------------------------------------------
|
||||
promiseDrawAll.push(promiseRequestData, promiseInfo, promiseSignature, promiseIntel);
|
||||
@@ -479,7 +479,7 @@ define([
|
||||
|
||||
if(
|
||||
currentSystemData &&
|
||||
systemData.id === currentSystemData.systemData.id
|
||||
systemData.id === currentSystemData.id
|
||||
){
|
||||
// trigger system update events
|
||||
let tabContentElement = $('#' + config.mapTabIdPrefix + systemData.mapId + '.' + config.mapTabContentClass);
|
||||
|
||||
@@ -11,7 +11,6 @@ define([
|
||||
'app/map/util',
|
||||
'app/map/contextmenu',
|
||||
'slidebars',
|
||||
'text!img/logo.svg!strip',
|
||||
'text!templates/layout/header_map.html',
|
||||
'text!templates/layout/footer_map.html',
|
||||
'dialog/notification',
|
||||
@@ -27,7 +26,7 @@ define([
|
||||
'dialog/credit',
|
||||
'xEditable',
|
||||
'app/module_map'
|
||||
], ($, Init, Util, Logging, Mustache, MapUtil, MapContextMenu, SlideBars, TplLogo, TplHead, TplFooter) => {
|
||||
], ($, Init, Util, Logging, Mustache, MapUtil, MapContextMenu, SlideBars, TplHead, TplFooter) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -152,6 +151,7 @@ define([
|
||||
loadFooter(pageElement),
|
||||
loadLeftMenu(pageMenuLeftElement),
|
||||
loadRightMenu(pageMenuRightElement),
|
||||
loadSVGs()
|
||||
]).then(payload => Promise.all([
|
||||
setMenuObserver(payload[2].data),
|
||||
setMenuObserver(payload[3].data),
|
||||
@@ -413,6 +413,35 @@ define([
|
||||
return new Promise(executor);
|
||||
};
|
||||
|
||||
/**
|
||||
* load standalone <svg>´s into DOM
|
||||
* -> SVGs can be used by referencing its ID e.g.:
|
||||
* <svg width="12px" height="12px"><use xlink:href="#pf-svg-swords"/></svg>
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let loadSVGs = () => {
|
||||
|
||||
let executor = resolve => {
|
||||
let parentElement = $('body');
|
||||
|
||||
let svgPaths = [
|
||||
'img/svg/logo.svg',
|
||||
'img/svg/swords.svg'
|
||||
].map(path => 'text!' + path + '!strip');
|
||||
|
||||
requirejs(svgPaths, (...SVGs) => {
|
||||
parentElement.append.apply(parentElement, SVGs);
|
||||
|
||||
resolve({
|
||||
action: 'loadSVGs',
|
||||
data: {}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(executor);
|
||||
};
|
||||
|
||||
/**
|
||||
* load page header
|
||||
* @param pageElement
|
||||
@@ -423,7 +452,6 @@ define([
|
||||
let executor = resolve => {
|
||||
let moduleData = {
|
||||
id: config.pageHeaderId,
|
||||
logo: () => Mustache.render(TplLogo, {}),
|
||||
brandLogo: config.menuHeadMenuLogoClass,
|
||||
popoverTriggerClass: Util.config.popoverTriggerClass,
|
||||
userCharacterClass: config.headUserCharacterClass,
|
||||
@@ -853,6 +881,10 @@ define([
|
||||
let modalElement = $(e.target);
|
||||
modalElement.destroyTimestampCounter(true);
|
||||
|
||||
// destroy all form validators
|
||||
// -> does not work properly. validation functions still used (js error) after 'destroy'
|
||||
//modalElement.find('form').filter((i, form) => $(form).data('bs.validator')).validator('destroy');
|
||||
|
||||
// destroy all popovers
|
||||
modalElement.find('.' + Util.config.popoverTriggerClass).popover('destroy');
|
||||
|
||||
@@ -980,7 +1012,13 @@ define([
|
||||
if(changes.charactersIds){
|
||||
updateTasks.push(updateHeaderCharacterSwitch(userData, changes.characterId));
|
||||
}
|
||||
if(changes.characterSystemId || changes.characterShipType || changes.characterLogHistory){
|
||||
if(
|
||||
changes.characterSystemId ||
|
||||
changes.characterShipType ||
|
||||
changes.characterStationId ||
|
||||
changes.characterStructureId ||
|
||||
changes.characterLogHistory
|
||||
){
|
||||
updateTasks.push(updateHeaderCharacterLocation(userData, changes.characterShipType));
|
||||
}
|
||||
|
||||
@@ -1022,7 +1060,7 @@ define([
|
||||
if(changedCharacter){
|
||||
// current character changed
|
||||
userInfoElement.find('span').text(Util.getObjVal(userData, 'character.name'));
|
||||
userInfoElement.find('img').attr('src', Init.url.ccpImageServer + '/Character/' + Util.getObjVal(userData, 'character.id') + '_32.jpg');
|
||||
userInfoElement.find('img').attr('src', Util.eveImageUrl('character', Util.getObjVal(userData, 'character.id')));
|
||||
}
|
||||
// init "character switch" popover
|
||||
userInfoElement.initCharacterSwitchPopover(userData);
|
||||
@@ -1055,6 +1093,16 @@ define([
|
||||
let shipTypeId = Util.getObjVal(shipData, 'typeId') || 0;
|
||||
let shipTypeName = Util.getObjVal(shipData, 'typeName') || '';
|
||||
|
||||
let stationData = Util.getObjVal(userData, 'character.log.station');
|
||||
let stationId = Util.getObjVal(stationData, 'id') || 0;
|
||||
let stationName = Util.getObjVal(stationData, 'name') || '';
|
||||
|
||||
let structureData = Util.getObjVal(userData, 'character.log.structure');
|
||||
let structureTypeId = Util.getObjVal(structureData, 'type.id') || 0;
|
||||
let structureTypeName = Util.getObjVal(structureData, 'type.name') || '';
|
||||
let structureId = Util.getObjVal(structureData, 'id') || 0;
|
||||
let structureName = Util.getObjVal(structureData, 'name') || '';
|
||||
|
||||
logDataAll.push(logData);
|
||||
|
||||
// check for log history data as well
|
||||
@@ -1084,15 +1132,20 @@ define([
|
||||
|
||||
if(isCurrentLocation){
|
||||
breadcrumbHtml += '<i class="fas fa-fw fa-map-marker-alt" title="current location"></i>';
|
||||
|
||||
if(stationId > 0){
|
||||
breadcrumbHtml += '<i class="fas fa-home" title="' + stationName + '"></i>';
|
||||
}else if(structureId > 0){
|
||||
breadcrumbHtml += '<i class="fas fa-industry" title="' + structureTypeName + ' "' + structureName + '""></i>';
|
||||
}
|
||||
}
|
||||
|
||||
breadcrumbHtml += systemName;
|
||||
|
||||
if(isCurrentLocation && shipTypeId){
|
||||
// show ship image
|
||||
let shipSrc = Init.url.ccpImageServer + '/Render/' + shipTypeId + '_32.png';
|
||||
breadcrumbHtml += '<img class="pf-head-image --right" ';
|
||||
breadcrumbHtml += 'src="' + shipSrc + '" ';
|
||||
breadcrumbHtml += 'src="' + Util.eveImageUrl('render', shipTypeId) + '" ';
|
||||
breadcrumbHtml += 'title="' + shipTypeName + '" ';
|
||||
breadcrumbHtml += '>';
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ define([
|
||||
|
||||
let config = {
|
||||
splashOverlayClass: 'pf-splash', // class for "splash" overlay
|
||||
|
||||
// navigation
|
||||
navigationElementId: 'pf-navbar', // id for navbar element
|
||||
|
||||
webSocketStatsId: 'pf-setup-webSocket-stats', // id for webSocket "stats" panel
|
||||
webSocketRefreshStatsId: 'pf-setup-webSocket-stats-refresh' // class for "reload stats" button
|
||||
};
|
||||
@@ -64,7 +68,9 @@ define([
|
||||
let body = $('body');
|
||||
|
||||
// navigation (scroll) ----------------------------------------------------------------------------------------
|
||||
Util.initPageScroll(body);
|
||||
Util.initScrollSpy(document.getElementById(config.navigationElementId), window, {
|
||||
offset: 300
|
||||
});
|
||||
|
||||
// collapse ---------------------------------------------------------------------------------------------------
|
||||
setCollapseObserver(body, '[data-toggle="collapse"]');
|
||||
@@ -87,6 +93,7 @@ define([
|
||||
let url = '/api/setup/' + element.attr('data-action');
|
||||
sendRequest(url, {
|
||||
type: element.attr('data-type'),
|
||||
countAll: element.attr('data-countall'),
|
||||
count: 0,
|
||||
offset: 0
|
||||
}, {
|
||||
@@ -110,10 +117,10 @@ define([
|
||||
* @param responseData
|
||||
*/
|
||||
let updateIndexCount = (context, responseData) => {
|
||||
let countElement = context.target.closest('.row').children().eq(1).find('kbd');
|
||||
let countElement = context.target.closest('tr').children().eq(1).find('kbd');
|
||||
countElement.text(responseData.countBuildAll + '/' + responseData.countAll);
|
||||
countElement.removeClass('txt-color-success txt-color-danger txt-color-warning');
|
||||
if(responseData.countBuildAll >=responseData.countAll){
|
||||
if(responseData.countBuildAll >= responseData.countAll){
|
||||
countElement.addClass('txt-color-success');
|
||||
}else if(responseData.countBuildAll > 0){
|
||||
countElement.addClass('txt-color-warning');
|
||||
@@ -121,6 +128,12 @@ define([
|
||||
countElement.addClass('txt-color-danger');
|
||||
}
|
||||
|
||||
// update 'subCount' element (shows e.g. invType count)
|
||||
if(responseData.subCount){
|
||||
let subCountElement = context.target.closest('tr').children().eq(2).find('kbd');
|
||||
subCountElement.text(responseData.subCount.countBuildAll + '/' + subCountElement.attr('data-countall'));
|
||||
}
|
||||
|
||||
context.target.find('.btn-progress').html(' ' + responseData.progress + '%').css('width', responseData.progress + '%');
|
||||
|
||||
// send next chunk of rows -> import only
|
||||
@@ -130,6 +143,7 @@ define([
|
||||
){
|
||||
sendRequest(context.url, {
|
||||
type: responseData.type,
|
||||
countAll: responseData.countAll,
|
||||
count: responseData.count,
|
||||
offset: responseData.offset
|
||||
}, {
|
||||
@@ -188,8 +202,8 @@ define([
|
||||
* @param data
|
||||
*/
|
||||
let updateWebSocketPanel = (data) => {
|
||||
let badgeSocketWarning = $('.navbar a[data-anchor="#pf-setup-socket"] .txt-color-warning');
|
||||
let badgeSocketDanger = $('.navbar a[data-anchor="#pf-setup-socket"] .txt-color-danger');
|
||||
let badgeSocketWarning = $('.navbar a[data-target="pf-setup-socket"] .txt-color-warning');
|
||||
let badgeSocketDanger = $('.navbar a[data-target="pf-setup-socket"] .txt-color-danger');
|
||||
let socketWarningCount = parseInt(badgeSocketWarning.text()) || 0;
|
||||
let socketDangerCount = parseInt(badgeSocketDanger.text()) || 0;
|
||||
|
||||
|
||||
@@ -77,11 +77,9 @@ define([
|
||||
|
||||
// show "discard" changes confirmation
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'top',
|
||||
btnCancelClass: 'btn btn-sm btn-default',
|
||||
btnCancelLabel: 'cancel',
|
||||
title: 'discard changes',
|
||||
btnCancelIcon: '',
|
||||
btnOkClass: 'btn btn-sm btn-warning',
|
||||
btnOkLabel: 'discard',
|
||||
btnOkIcon: 'fas fa-fw fa-ban',
|
||||
|
||||
@@ -38,7 +38,8 @@ define([
|
||||
switch(render(val)){
|
||||
case 'green': return 'ok';
|
||||
case 'yellow': return 'degraded: Slow or potentially dropping requests';
|
||||
case 'red': return 'bad: Most requests are not succeeding and/or are very slow (5s+) on average';
|
||||
case 'orange': return 'bad: Most requests are not succeeding and/or are very slow (5s+) on average';
|
||||
case 'red': return 'error: Status data not available. Either offline or any other fatal error';
|
||||
default: return 'unknown';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,12 +29,39 @@ define([
|
||||
*/
|
||||
$.fn.showJumpInfoDialog = function(){
|
||||
requirejs(['text!templates/dialog/jump_info.html', 'mustache', 'datatables.loader'], (template, Mustache) => {
|
||||
let iconShattered = '<i class="fas fa-fw fa-chart-pie pf-system-sec-unknown"></i>';
|
||||
let iconDrifter = '<i class="fas fa-fw fa-wave-square pf-system-sec-drifter"></i>';
|
||||
|
||||
let staticsMatrixHead = [
|
||||
let formatTableBodyData = (head, matrixBody) => {
|
||||
return matrixBody.map((row, rowIndex) => {
|
||||
return row.map((label, colIndex) => {
|
||||
// get security name from "matrix Head" data if NOT first column
|
||||
let secName = colIndex ? head[0][colIndex] : label;
|
||||
return {
|
||||
label: label,
|
||||
class: Util.getSecurityClassForSystem(secName),
|
||||
hasPopover: colIndex && label.length
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Statics table first ------------------------------------------------------------------------------------
|
||||
let headGroupFirst = [
|
||||
[
|
||||
{label: '', class: 'separator-right', style: 'width: 55px;'},
|
||||
{colspan: 6, label: 'W-space', class: 'separator-right'},
|
||||
{colspan: 3, label: 'K-space', class: 'separator-right'},
|
||||
{label: 'Thera', class: 'separator-right'},
|
||||
{label: iconShattered}
|
||||
]
|
||||
];
|
||||
|
||||
let headFirst = [
|
||||
['From╲To', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'H', 'L', '0.0', 'C12', 'C13']
|
||||
];
|
||||
|
||||
let staticsMatrixBody = [
|
||||
let matrixBodyFirst = [
|
||||
['C1', 'H121', 'C125', 'O883', 'M609', 'L614', 'S804', 'N110', 'J244', 'Z060', 'F353', ''],
|
||||
['C2', 'Z647', 'D382', 'O477', 'Y683', 'N062', 'R474', 'B274', 'A239', 'E545', 'F135', ''],
|
||||
['C3', 'V301', 'I182', 'N968', 'T405', 'N770', 'A982', 'D845', 'U210', 'K346', 'F135', ''],
|
||||
@@ -48,22 +75,48 @@ define([
|
||||
['?', 'E004', 'L005', 'Z006', 'M001', 'C008', 'G008', '' , '' , 'Q003', '' , 'A009']
|
||||
];
|
||||
|
||||
|
||||
let staticsTableDataFirst = {
|
||||
headGroup: headGroupFirst,
|
||||
head: headFirst,
|
||||
body: formatTableBodyData(headFirst, matrixBodyFirst)
|
||||
};
|
||||
|
||||
// Statics table second -----------------------------------------------------------------------------------
|
||||
|
||||
let headGroupSecond = [
|
||||
[
|
||||
{label: '', class: 'separator-right', style: 'width: 55px;'},
|
||||
{label: iconDrifter + ' ' + 'Sentinel', class: 'separator-right'},
|
||||
{label: iconDrifter + ' ' + 'Barbican', class: 'separator-right'},
|
||||
{label: iconDrifter + ' ' + 'Vidette', class: 'separator-right'},
|
||||
{label: iconDrifter + ' ' + 'Conflux', class: 'separator-right'},
|
||||
{label: iconDrifter + ' ' + 'Redoubt'}
|
||||
]
|
||||
];
|
||||
|
||||
let headSecond = [
|
||||
['From╲To', 'C14', 'C15', 'C16', 'C17', 'C18']
|
||||
];
|
||||
|
||||
let matrixBodySecond = [
|
||||
['?', 'S877', 'B735', 'V928', 'C414', 'R259']
|
||||
];
|
||||
|
||||
let staticsTableDataSecond = {
|
||||
headline: 'Drifter W-space',
|
||||
headGroup: headGroupSecond,
|
||||
head: headSecond,
|
||||
body: formatTableBodyData(headSecond, matrixBodySecond)
|
||||
};
|
||||
|
||||
let staticsTablesData = [staticsTableDataFirst, staticsTableDataSecond];
|
||||
|
||||
let data = {
|
||||
config: config,
|
||||
popoverTriggerClass: Util.config.popoverTriggerClass,
|
||||
wormholes: Object.keys(Init.wormholes).map(function(k){ return Init.wormholes[k]; }), // convert Json to array
|
||||
staticsMatrixHead: staticsMatrixHead,
|
||||
staticsMatrixBody: staticsMatrixBody.map((row, rowIndex) => {
|
||||
return row.map((label, colIndex) => {
|
||||
// get security name from "matrix Head" data if NOT first column
|
||||
let secName = colIndex ? staticsMatrixHead[0][colIndex] : label;
|
||||
return {
|
||||
label: label,
|
||||
class: Util.getSecurityClassForSystem(secName),
|
||||
hasPopover: colIndex && label.length
|
||||
};
|
||||
});
|
||||
}),
|
||||
staticsTablesData: staticsTablesData,
|
||||
massValue: function(){
|
||||
return function(value, render){
|
||||
let mass = render(value);
|
||||
|
||||
@@ -26,7 +26,6 @@ define([
|
||||
$.fn.showMapManual = function(){
|
||||
|
||||
requirejs(['text!templates/dialog/map_manual.html', 'mustache'], (template, Mustache) => {
|
||||
|
||||
let data = {
|
||||
dialogNavigationClass: config.dialogNavigationClass,
|
||||
dialogNavLiClass: config.dialogNavigationListItemClass,
|
||||
@@ -67,8 +66,7 @@ define([
|
||||
|
||||
let scrollspyElement = $('#' + config.mapManualScrollspyId);
|
||||
|
||||
let whileScrolling = function(){
|
||||
|
||||
let whileScrolling = () => {
|
||||
if(disableOnScrollEvent === false){
|
||||
for(let i = 0; i < scrollBreakpointElements.length; i++){
|
||||
let offset = $(scrollBreakpointElements[i]).offset().top;
|
||||
@@ -124,11 +122,9 @@ define([
|
||||
|
||||
let mainNavigationLiElement = $(this).parent('.' + config.dialogNavigationListItemClass);
|
||||
|
||||
|
||||
whileScrolling();
|
||||
|
||||
// if link is a main navigation link (not an anchor link)
|
||||
|
||||
if(mainNavigationLiElement.length > 0){
|
||||
// remove all active classes
|
||||
scrollNavLiElements.removeClass('active');
|
||||
@@ -138,7 +134,6 @@ define([
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
onScroll: function(){
|
||||
disableOnScrollEvent = false;
|
||||
|
||||
@@ -56,18 +56,6 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
// confirmation dialog settings (e.g. delete row)
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'left',
|
||||
btnCancelClass: 'btn btn-sm btn-default',
|
||||
btnCancelLabel: 'cancel',
|
||||
btnCancelIcon: 'fas fa-fw fa-ban',
|
||||
btnOkClass: 'btn btn-sm btn-danger',
|
||||
btnOkLabel: 'delete',
|
||||
btnOkIcon: 'fas fa-fw fa-times'
|
||||
};
|
||||
|
||||
/**
|
||||
* get icon that marks a table cell as clickable
|
||||
* @returns {string}
|
||||
@@ -217,7 +205,7 @@ define([
|
||||
let systemsElement = $(this).empty();
|
||||
|
||||
let systemTable = $('<table>', {
|
||||
id: Util.getTableId(config.tableId, mapData.config.id, '', 'systems'),
|
||||
id: Util.getTableId(config.tableId, 'systems', mapData.config.id, ''),
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ')
|
||||
});
|
||||
systemsElement.append(systemTable);
|
||||
@@ -237,7 +225,7 @@ define([
|
||||
paging: true,
|
||||
lengthMenu: [[5, 10, 20, 50, -1], [5, 10, 20, 50, 'All']],
|
||||
ordering: true,
|
||||
order: [14, 'desc'],
|
||||
order: [15, 'desc'],
|
||||
hover: false,
|
||||
data: mapData.data.systems,
|
||||
columnDefs: [],
|
||||
@@ -285,7 +273,7 @@ define([
|
||||
}
|
||||
},{
|
||||
name: 'shattered',
|
||||
title: '<i class="fas fa-skull" title="shattered" data-toggle="tooltip"></i>',
|
||||
title: '<i class="fas fa-chart-pie" title="shattered" data-toggle="tooltip"></i>',
|
||||
width: 10,
|
||||
className: ['text-center', 'min-screen-l'].join(' '),
|
||||
searchable: false,
|
||||
@@ -294,7 +282,7 @@ define([
|
||||
display: (cellData, type, rowData, meta) => {
|
||||
let value = '';
|
||||
if(cellData){
|
||||
value = '<i class="fas fa-skull fa-fw ' + Util.getSecurityClassForSystem('SH') + '"></i>';
|
||||
value = '<i class="fas fa-chart-pie fa-fw ' + Util.getSecurityClassForSystem('SH') + '"></i>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -324,6 +312,22 @@ define([
|
||||
title: 'region',
|
||||
data: 'region.name',
|
||||
className: 'min-screen-l',
|
||||
},{
|
||||
name: 'sovereignty',
|
||||
title: 'sov.',
|
||||
width: 30,
|
||||
className: 'text-center',
|
||||
data: 'sovereignty.alliance.ticker',
|
||||
defaultContent: '',
|
||||
render: {
|
||||
display: (cellData, type, rowData, meta) => {
|
||||
let value = '';
|
||||
if(cellData){
|
||||
value = '<' + cellData + '>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},{
|
||||
name: 'planets',
|
||||
title: '<i class="fas fa-circle" title="planets" data-toggle="tooltip"></i>',
|
||||
@@ -456,44 +460,49 @@ define([
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let tempTableElement = this;
|
||||
|
||||
let tempConfirmationSettings = confirmationSettings;
|
||||
tempConfirmationSettings.title = 'Delete system';
|
||||
tempConfirmationSettings.onConfirm = function(e, target){
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
let confirmationSettings = {
|
||||
placement: 'left',
|
||||
title: 'Delete system',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
}),
|
||||
onConfirm: function(e, target){
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
let systemElement = $('#' + MapUtil.getSystemId(mapData.config.id, rowData.id) );
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
let systemElement = $('#' + MapUtil.getSystemId(mapData.config.id, rowData.id) );
|
||||
|
||||
if(systemElement.length){
|
||||
// trigger system delete event
|
||||
activeMap.trigger('pf:deleteSystems', [{
|
||||
systems: [systemElement[0]],
|
||||
callback: function(deletedSystems){
|
||||
// callback function after ajax "delete" success
|
||||
// check if system was deleted
|
||||
if(deletedSystems.length === 1){
|
||||
// remove table row
|
||||
tempTableElement.DataTable().rows(deleteRowElement).remove().draw();
|
||||
if(systemElement.length){
|
||||
// trigger system delete event
|
||||
activeMap.trigger('pf:deleteSystems', [{
|
||||
systems: [systemElement[0]],
|
||||
callback: function(deletedSystems){
|
||||
// callback function after ajax "delete" success
|
||||
// check if system was deleted
|
||||
if(deletedSystems.length === 1){
|
||||
// remove table row
|
||||
tempTableElement.DataTable().rows(deleteRowElement).remove().draw();
|
||||
|
||||
Util.showNotify({title: 'System deleted', text: rowData.name, type: 'success'});
|
||||
Util.showNotify({title: 'System deleted', text: rowData.name, type: 'success'});
|
||||
|
||||
// refresh connection table (connections might have changed) --------------
|
||||
let connectionsElement = $('#' + config.mapInfoConnectionsId);
|
||||
let mapDataNew = activeMap.getMapDataFromClient(['hasId']);
|
||||
// refresh connection table (connections might have changed) --------------
|
||||
let connectionsElement = $('#' + config.mapInfoConnectionsId);
|
||||
let mapDataNew = activeMap.getMapDataFromClient(['hasId']);
|
||||
|
||||
connectionsElement.initConnectionInfoTable(mapDataNew);
|
||||
}else{
|
||||
// error
|
||||
Util.showNotify({title: 'Failed to delete system', text: rowData.name, type: 'error'});
|
||||
connectionsElement.initConnectionInfoTable(mapDataNew);
|
||||
}else{
|
||||
// error
|
||||
Util.showNotify({title: 'Failed to delete system', text: rowData.name, type: 'error'});
|
||||
}
|
||||
}
|
||||
}
|
||||
}]);
|
||||
}]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// init confirmation dialog
|
||||
$(cell).confirmation(tempConfirmationSettings);
|
||||
|
||||
$(cell).confirmation(confirmationSettings);
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -652,23 +661,29 @@ define([
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let tempTableElement = this;
|
||||
|
||||
let tempConfirmationSettings = confirmationSettings;
|
||||
tempConfirmationSettings.title = 'Delete connection';
|
||||
tempConfirmationSettings.onConfirm = function(e, target){
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
let confirmationSettings = {
|
||||
placement: 'left',
|
||||
title: 'Delete connection',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
}),
|
||||
onConfirm: function(e, target){
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
|
||||
// deleteSignatures(row);
|
||||
let connection = $().getConnectionById(mapData.config.id, rowData.id);
|
||||
// deleteSignatures(row);
|
||||
let connection = $().getConnectionById(mapData.config.id, rowData.id);
|
||||
|
||||
MapUtil.deleteConnections([connection], () => {
|
||||
// callback function after ajax "delete" success
|
||||
// remove table row
|
||||
tempTableElement.DataTable().rows(deleteRowElement).remove().draw();
|
||||
});
|
||||
MapUtil.deleteConnections([connection], () => {
|
||||
// callback function after ajax "delete" success
|
||||
// remove table row
|
||||
tempTableElement.DataTable().rows(deleteRowElement).remove().draw();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// init confirmation dialog
|
||||
$(cell).confirmation(tempConfirmationSettings);
|
||||
$(cell).confirmation(confirmationSettings);
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -749,7 +764,7 @@ define([
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(data && type === 'display'){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Render/' + value.typeId + '_32.png" title="' + value.typeName + '" data-toggle="tooltip" />';
|
||||
value = '<img src="' + Util.eveImageUrl('render', value.typeId) + '" title="' + value.typeName + '" data-toggle="tooltip" />';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -787,7 +802,7 @@ define([
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display'){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Character/' + value + '_32.jpg" />';
|
||||
value = '<img src="' + Util.eveImageUrl('character', value) + '"/>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -827,7 +842,7 @@ define([
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display'){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Corporation/' + value.id + '_32.png" />';
|
||||
value = '<img src="' + Util.eveImageUrl('corporation', value.id) + '"/>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -849,7 +864,7 @@ define([
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
// open character information window (ingame)
|
||||
// open corporation information window (ingame)
|
||||
$(cell).on('click', { tableApi: this.api() }, function(e){
|
||||
let cellData = e.data.tableApi.cell(this).data();
|
||||
Util.openIngameWindow(cellData.id);
|
||||
@@ -1110,7 +1125,7 @@ define([
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display'){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Character/' + value + '_32.jpg" />';
|
||||
value = '<img src="' + Util.eveImageUrl('character', value) + '"/>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ define([
|
||||
deleteEolConnectionsId: 'pf-map-dialog-delete-connections-eol', // id for "deleteEOLConnections" checkbox
|
||||
persistentAliasesId: 'pf-map-dialog-persistent-aliases', // id for "persistentAliases" checkbox
|
||||
persistentSignaturesId: 'pf-map-dialog-persistent-signatures', // id for "persistentSignatures" checkbox
|
||||
trackAbyssalJumpsId: 'pf-map-dialog-track-abyss-jumps', // id for "trackAbyssalJumps" checkbox
|
||||
|
||||
logHistoryId: 'pf-map-dialog-history', // id for "history logging" checkbox
|
||||
logActivityId: 'pf-map-dialog-activity', // id for "activity" checkbox
|
||||
@@ -159,6 +160,7 @@ define([
|
||||
let deleteEolConnections = true;
|
||||
let persistentAliases = true;
|
||||
let persistentSignatures = true;
|
||||
let trackAbyssalJumps = true;
|
||||
|
||||
let logActivity = true;
|
||||
let logHistory = true;
|
||||
@@ -197,6 +199,7 @@ define([
|
||||
deleteEolConnections = mapData.config.deleteEolConnections;
|
||||
persistentAliases = mapData.config.persistentAliases;
|
||||
persistentSignatures = mapData.config.persistentSignatures;
|
||||
trackAbyssalJumps = mapData.config.trackAbyssalJumps;
|
||||
|
||||
logActivity = mapData.config.logging.activity;
|
||||
logHistory = mapData.config.logging.history;
|
||||
@@ -255,10 +258,12 @@ define([
|
||||
deleteEolConnectionsId : config.deleteEolConnectionsId,
|
||||
persistentAliasesId : config.persistentAliasesId,
|
||||
persistentSignaturesId : config.persistentSignaturesId,
|
||||
trackAbyssalJumpsId : config.trackAbyssalJumpsId,
|
||||
deleteExpiredConnections: deleteExpiredConnections,
|
||||
deleteEolConnections: deleteEolConnections,
|
||||
persistentAliases: persistentAliases,
|
||||
persistentSignatures: persistentSignatures,
|
||||
trackAbyssalJumps: trackAbyssalJumps,
|
||||
|
||||
logHistoryId: config.logHistoryId,
|
||||
logActivityId: config.logActivityId,
|
||||
@@ -398,6 +403,9 @@ define([
|
||||
if( form.find('#' + config.persistentSignaturesId).length ){
|
||||
formData.persistentSignatures = formData.hasOwnProperty('persistentSignatures') ? parseInt( formData.persistentSignatures ) : 0;
|
||||
}
|
||||
if( form.find('#' + config.trackAbyssalJumpsId).length ){
|
||||
formData.trackAbyssalJumps = formData.hasOwnProperty('trackAbyssalJumps') ? parseInt( formData.trackAbyssalJumps ) : 0;
|
||||
}
|
||||
if( form.find('#' + config.logHistoryId).length ){
|
||||
formData.logHistory = formData.hasOwnProperty('logHistory') ? parseInt( formData.logHistory ) : 0;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ define([
|
||||
data: 'character',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
return '<img src="' + Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg" />';
|
||||
return '<img src="' + Util.eveImageUrl('character', parseInt(data.id)) + '"/>';
|
||||
}
|
||||
}
|
||||
},{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user