- New "Sovereignty" and "Faction warfare" data added, closed #853

- New ESI data import for wormhole type data from _ESI_, closed #852
- New ESI data import static wormholes, closed #852
- Improved performance for character authorization (PHP). Reduced number of _SQL_ queries.
- Improved HTTP cache header for `api/map/initData`, 'api/user/getEveServerStatus' ajax requests
This commit is contained in:
Mark Friedrich
2019-09-10 18:14:53 +02:00
parent a16d5c1c2b
commit d45fa9b527
108 changed files with 6946 additions and 1226 deletions

View File

@@ -61,6 +61,7 @@ truncateMapHistoryLogFiles = Cron\MapHistory->truncateFiles, @halfHou
; updates small amount of static system data from CCP API
;updateUniverseSystems = Cron\Universe->updateUniverseSystems, @instant
;updateSovereigntyData = Cron\Universe->updateSovereigntyData, @instant
; setup universe DB with static data from ESI
;setup = Cron\Universe->setup, @instant

View File

@@ -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);

View File

@@ -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';

View File

@@ -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;
}
}

View File

@@ -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 = [];
@@ -199,29 +196,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 +232,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 +258,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);
@@ -906,14 +910,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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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 ====================================================================================
@@ -150,6 +165,7 @@ class Universe extends Controller {
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) {

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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,25 @@ 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\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 +1670,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 +1789,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'
]
];
}

View File

@@ -193,12 +193,39 @@ class Universe extends AbstractCron {
$model->loadStargatesData();
};
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;
@@ -242,6 +269,34 @@ class Universe extends AbstractCron {
$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();
$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): [];
foreach($ids as $id){
if($system->getById($id)){
$system->updateSovereigntyData($sovData[$id]);
if(is_array($fwSystems[$id])){
$system->updateFactionWarData($fwSystems[$id]);
}
$system->reset();
}
}
}
/**
* update static universe system data from ESI
* -> updates small chunk of systems at once
@@ -251,9 +306,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();

View File

@@ -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);
}
@@ -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;
}
}
}

View File

@@ -51,6 +51,24 @@ 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

View File

@@ -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
*/
@@ -658,6 +684,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 +760,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;
}
@@ -1019,6 +1098,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

View File

@@ -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();
}

View File

@@ -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;
}
/**

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,

View File

@@ -563,41 +563,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 +646,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 +671,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 +814,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 +829,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 +837,7 @@ class MapModel extends AbstractMapTrackingModel {
if($this->mapCorporations){
foreach($this->mapCorporations as $mapCorporation){
$corporations[] = $mapCorporation->corporationId;
$corporations[$mapCorporation->corporationId->_id] = $mapCorporation->corporationId;
}
}
}

View File

@@ -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,

View File

@@ -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
*/

View File

@@ -161,80 +161,78 @@ 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->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;
}
/**
@@ -435,10 +433,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 +457,14 @@ class SystemModel extends AbstractMapTrackingModel {
return $this->getStaticSystemValue('planets');
}
public function get_sovereignty(){
return $this->getStaticSystemValue('sovereignty');
}
public function get_factionWar(){
return $this->getStaticSystemValue('factionWar');
}
/**
* Event "Hook" function
* @param self $self
@@ -652,7 +654,7 @@ class SystemModel extends AbstractMapTrackingModel {
* @return \stdClass[]
*/
public function getStructuresData() : array {
return $this->getMap()->getStructuresData([$this->systemId]);
return $this->getMap()->getStructuresData($this->systemId);
}
/**

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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
@@ -46,7 +46,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 +59,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 +110,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 +151,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 +197,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);
}
}

View File

@@ -0,0 +1,87 @@
<?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;
}
/**
* 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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -55,6 +55,9 @@ class ConstellationModel extends AbstractUniverseModel {
],
'systems' => [
'has-many' => ['Model\Universe\SystemModel', 'constellationId']
],
'systemNeighbours' => [
'has-many' => ['Model\Universe\SystemNeighbourModel', 'constellationId']
]
];

View File

@@ -0,0 +1,116 @@
<?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']
]
];
/**
* get data
* @return \stdClass
*/
public function getData(){
$data = (object) [];
$data->id = $this->_id;
$data->name = $this->name;
return $data;
}
/**
* 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 $faction 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();
}
}
}

View 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)){
$this->copyfrom($data, ['id', 'name', 'displayName', 'description', 'published', 'stackable', 'highIsGood', 'defaultValue', 'iconId', 'unitId']);
$this->save();
}
}
}

View File

@@ -46,8 +46,20 @@ class FactionModel extends AbstractUniverseModel {
'nullable' => false,
'default' => 0
],
'systems' => [
'has-many' => ['Model\Universe\SystemModel', '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']
]
];

View 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 = []){}
}

View File

@@ -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'];
}
}

View File

@@ -66,13 +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;
return $data;
}
/**

View File

@@ -32,6 +32,9 @@ class RegionModel extends AbstractUniverseModel {
],
'constellations' => [
'has-many' => ['Model\Universe\ConstellationModel', 'regionId']
],
'systemNeighbours' => [
'has-many' => ['Model\Universe\SystemNeighbourModel', 'regionId']
]
];

View 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 = []){}
}

View File

@@ -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,

View File

@@ -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,18 @@ class SystemModel extends AbstractUniverseModel {
],
'stargates' => [
'has-many' => ['Model\Universe\StargateModel', '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 +113,48 @@ 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;
return $data;
}
/**
@@ -185,11 +186,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';
@@ -235,15 +243,120 @@ class SystemModel extends AbstractUniverseModel {
}
/**
* setter for static systems (wormholes)
* -> comma separated string or array
* @param $staticNames
* @return null
* @param array $sovData
*/
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 updateSovereigntyData(array $sovData = []){
$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']);
$sovereignty->save();
}elseif($this->sovereignty){
// delete existing sov data
// -> hint: WH - systems never have sovereignty data
$this->sovereignty->erase();
}
}
}
}
/**
* @param array $fwData
*/
public function updateFactionWarData(array $fwData = []){
$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']);
$factionWar->save();
}
}
}
/**
@@ -253,38 +366,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,7 +375,7 @@ class SystemModel extends AbstractUniverseModel {
* get data from all planets
* @return array
*/
protected function getPlanetsData(){
protected function getPlanetsData() : array {
$planetsData = [];
if($this->planets){
@@ -310,7 +393,7 @@ class SystemModel extends AbstractUniverseModel {
* get data from all static wormholes
* @return array
*/
protected function getStaticsData(){
protected function getStaticsData() : array {
$staticsData = [];
if($this->statics){
@@ -328,7 +411,7 @@ class SystemModel extends AbstractUniverseModel {
* get data from all stargates
* @return array
*/
protected function getStargatesData(){
protected function getStargatesData() : array {
$stargatesData = [];
if($this->stargates){
@@ -346,7 +429,7 @@ class SystemModel extends AbstractUniverseModel {
* update system from ESI
*/
public function updateModel(){
if( !$this->dry() ){
if($this->valid()){
$this->loadData($this->_id);
$this->loadPlanetsData();
}
@@ -387,7 +470,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 +491,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

View 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 = []){}
}

View File

@@ -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;
}

View 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;
}
}

View File

@@ -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,
@@ -92,11 +112,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,16 +159,62 @@ 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
@@ -121,7 +222,7 @@ class TypeModel extends AbstractUniverseModel {
*/
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 +230,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 +351,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 +364,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;
}
}

View File

@@ -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 = []){}
}

View File

@@ -80,6 +80,4 @@ NODE = 6.0
NPM = 3.10.0
[REQUIREMENTS.DATA]
STRUCTURES = 33
SHIPS = 491
NEIGHBOURS = 5201

3773
export/csv/system_static.csv Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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;
1 Id Name Security SignatureStrength scanWormholeStrength MassTotal MassIndividual MassRegeneration MaxStableTime
2 1 A009 C13 500000000 5000000 3000000000 16
3 2 A239 L 5 2000000000 300000000 24
4 3 A641 H 10 2000000000 1000000000 16
5 4 A982 C6 2.22 3000000000 300000000 24
6 5 B041 C6 3000000000 300000000 500000000 48
7 6 B274 H 10 2000000000 300000000 24
8 7 B449 H 2.5 2000000000 1000000000 16
9 8 B520 H 3000000000 300000000 500000000 24
10 9 C008 C5 1000000000 5000000 3000000000 16
11 10 C125 C2 6.67 1000000000 20000000 16
12 11 C140 L 5 3000000000 1350000000 24
13 12 C247 C3 10 2000000000 300000000 16
14 13 C248 0.0 3000000000 1350000000 500000000 24
15 14 C391 L 3000000000 1000000000 500000000 24
16 15 D364 C2 1.25 1000000000 300000000 16
17 16 D382 C2 6.67 2000000000 300000000 16
18 17 D792 H 2.5 3000000000 1000000000 24
19 18 D845 H 5 5000000000 300000000 500000000 24
20 19 E004 C1 1000000000 5000000 3000000000 16
21 20 E175 C4 5 2000000000 300000000 16
22 21 E545 0.0 2.5 2000000000 300000000 24
23 23 G024 C2 1.25 2000000000 300000000 16
24 24 H121 C1 10 500000000 20000000 16
25 25 H296 C5 10 3000000000 1350000000 24
26 26 H900 C5 2.5 3000000000 300000000 24
27 27 I182 C2 4 2000000000 300000000 16
28 28 J244 L 5 1000000000 20000000 24
29 29 K329 0.0 5000000000 1800000000 500000000 24
30 30 K346 0.0 2.5 3000000000 300000000 24
31 31 L005 C2 1000000000 5000000 3000000000 16
32 32 L477 C3 5 2000000000 300000000 16
33 33 L614 C5 2.5 1000000000 20000000 24
34 35 M267 C3 1.25 1000000000 300000000 16
35 36 M555 C5 2.5 3000000000 1000000000 24
36 37 M609 C4 4 1000000000 20000000 16
37 38 N062 C5 2.5 3000000000 300000000 24
38 39 N110 H 10 1000000000 20000000 24
39 40 N290 L 3000000000 1350000000 500000000 24
40 41 N432 C5 10 3000000000 1350000000 24
41 42 N766 C2 4 2000000000 300000000 16
42 43 N770 C5 2.5 3000000000 300000000 24
43 44 N944 L 10 3000000000 1350000000 24
44 45 N968 C3 10 2000000000 300000000 16
45 46 O128 C4 1000000000 300000000 100000000 24
46 47 O477 C3 5 2000000000 300000000 16
47 48 O883 C3 5 1000000000 20000000 16
48 49 P060 C1 5 500000000 20000000 16
49 50 Q003 0.0 1000000000 5000000 3000000000 16
50 51 Q317 C1 2.5 500000000 20000000 16
51 52 R051 L 5 3000000000 1000000000 16
52 53 R474 C6 2.22 3000000000 300000000 24
53 54 R943 C2 6.67 750000000 300000000 16
54 55 S047 H 3000000000 300000000 24
55 56 S199 0.0 10 3000000000 1350000000 24
56 57 S804 C6 1.25 1000000000 20000000 24
57 58 T405 C4 6.67 2000000000 300000000 16
58 59 U210 L 10 3000000000 300000000 24
59 60 U319 C6 3000000000 1350000000 500000000 48
60 61 U574 C6 1.25 3000000000 300000000 24
61 62 V283 0.0 2.5 3000000000 1000000000 24
62 63 V301 C1 5 500000000 20000000 16
63 64 V753 C6 6.67 3000000000 1350000000 24
64 65 V911 C5 10 3000000000 1350000000 24
65 66 W237 C6 6.67 3000000000 1350000000 24
66 67 X702 C3 10 1000000000 300000000 24
67 68 X877 C4 6.67 2000000000 300000000 16
68 69 Y683 C4 4 2000000000 300000000 16
69 70 Y790 C1 2.5 500000000 20000000 16
70 71 Z006 C3 1000000000 5000000 3000000000 16
71 72 Z060 0.0 2.5 1000000000 20000000 24
72 73 Z142 0.0 10 3000000000 1350000000 24
73 74 Z457 C4 4 2000000000 300000000 16
74 75 Z647 C1 10 500000000 20000000 16
75 76 Z971 C1 10 100000000 20000000 16
76 80 M001 C4 1000000000 5000000 3000000000 16
77 81 E587 0.0 3000000000 1000000000 16
78 82 V898 L 2000000000 300000000 16
79 83 Q063 H 500000000 20000000 16
80 84 G008 C6 1000000000 5000000 3000000000 16
81 85 F353 C12 100000000 20000000 16
82 86 F135 C12 750000000 300000000 16
83 87 T458 C12 500000000 20000000 16
84 88 M164 C12 2000000000 300000000 16
85 89 L031 C12 3000000000 1000000000 16
86 90 S877 C14 750000000 300000000 16
87 91 B735 C15 750000000 300000000 16
88 92 V928 C16 750000000 300000000 16
89 93 C414 C17 750000000 300000000 16
90 94 R259 C18 750000000 300000000 16

Binary file not shown.

View File

@@ -454,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,
@@ -471,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 '';

View File

@@ -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) + '_32.png"/>';
}
return value;
}

View File

@@ -546,13 +546,15 @@ 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('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 ){
@@ -3046,47 +3048,58 @@ 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,
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;

View File

@@ -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')
)
});
}

View File

@@ -806,10 +806,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);
};
/**
@@ -1869,10 +1868,10 @@ define([
if(tooltipData.maxStableTime){
data.maxStableTime = tooltipData.maxStableTime + ' h';
}
if(tooltipData.signatureStrength){
data.signatureStrength = parseFloat(tooltipData.signatureStrength).toLocaleString() + '&nbsp;&#37;';
if(tooltipData.scanWormholeStrength){
data.scanWormholeStrength = parseFloat(tooltipData.scanWormholeStrength).toLocaleString() + '&nbsp;&#37;';
}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;

View File

@@ -447,7 +447,7 @@ define([
// start user update trigger after map loaded
updateTimeouts.userUpdate = setTimeout(() => {
triggerUserUpdatePing();
}, 1000);
}, 500);
}
});
}

View File

@@ -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);

View File

@@ -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,
@@ -1026,7 +1054,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);
@@ -1094,9 +1122,8 @@ define([
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 += '>';
}

View File

@@ -93,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
}, {
@@ -116,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');
@@ -127,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('&nbsp;&nbsp;' + responseData.progress + '%').css('width', responseData.progress + '%');
// send next chunk of rows -> import only
@@ -136,6 +143,7 @@ define([
){
sendRequest(context.url, {
type: responseData.type,
countAll: responseData.countAll,
count: responseData.count,
offset: responseData.offset
}, {

View File

@@ -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';
}
};

View File

@@ -225,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: [],
@@ -312,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 = '&lt;' + cellData + '&gt;';
}
return value;
}
}
},{
name: 'planets',
title: '<i class="fas fa-circle" title="planets" data-toggle="tooltip"></i>',
@@ -748,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;
}
@@ -786,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;
}
@@ -826,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;
}
@@ -1109,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;
}

View File

@@ -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)) + '"/>';
}
}
},{

View File

@@ -38,19 +38,19 @@ define([
switch(data.categoryType){
case 'character':
imagePath = Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg';
imagePath = Util.eveImageUrl('character', data.id);
break;
case 'corporation':
imagePath = Init.url.ccpImageServer + '/Corporation/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('corporation', data.id);
break;
case 'alliance':
imagePath = Init.url.ccpImageServer + '/Alliance/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('alliance', data.id);
break;
case 'inventoryType':
imagePath = Init.url.ccpImageServer + '/Type/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('type', data.id);
break;
case 'render':
imagePath = Init.url.ccpImageServer + '/Render/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('render', data.id);
break;
case 'station':
iconName = 'fa-home';

View File

@@ -774,7 +774,7 @@ define([
_: function(data, type, row){
let value = data.typeId;
if(type === 'display'){
value = '<img src="' + Init.url.ccpImageServer + '/Render/' + value + '_32.png" title="' + data.typeName + '" data-toggle="tooltip" />';
value = '<img src="' + Util.eveImageUrl('render', value) + '" title="' + data.typeName + '" data-toggle="tooltip" />';
}
return value;
}
@@ -794,7 +794,7 @@ define([
_: (cellData, type, rowData, meta) => {
let value = cellData.name;
if(type === 'display'){
value = '<img src="' + Init.url.ccpImageServer + '/Character/' + cellData.id + '_32.jpg" title="' + value + '" data-toggle="tooltip" />';
value = '<img src="' + Util.eveImageUrl('character', cellData.id) + '" title="' + value + '" data-toggle="tooltip" />';
}
return value;
}

View File

@@ -265,7 +265,7 @@ define([
for(let [graphKey, graphConfig] of Object.entries(config.systemGraphs)){
rowElement.append(
$('<div>', {
class: ['col-xs-12', 'col-sm-6', 'col-md-4'].join(' ')
class: ['col-xs-12', 'col-sm-4'].join(' ')
}).append(
$('<div>', {
class: config.moduleHeadClass

View File

@@ -27,7 +27,8 @@ define([
typeLinkClass: 'pf-system-info-type', // class for "type" name
urlLinkClass: 'pf-system-info-url', // class for "url" copy link
// info table
// info col/table
systemInfoSectionClass: 'pf-system-info-section', // class for system info section
systemInfoTableClass: 'pf-module-table', // class for system info table
systemInfoNameClass: 'pf-system-info-name', // class for "name" information element
systemInfoEffectClass: 'pf-system-info-effect', // class for "effect" information element
@@ -37,9 +38,21 @@ define([
systemInfoWormholeClass: 'pf-system-info-wormhole-', // class prefix for static wormhole element
// description field
descriptionAreaClass: 'pf-system-info-description-area', // class for "description" area
descriptionSectionClass: 'pf-system-description-section', // class for system description section
descriptionAreaClass: 'pf-system-info-description-area', // class for description area
addDescriptionButtonClass: 'pf-system-info-description-button', // class for "add description" button
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (Summernote)
descriptionTextareaElementClass: 'pf-system-info-description', // class for description textarea element (Summernote)
// sovereignty col/table
systemSovSectionClass: 'pf-system-sov-section', // class for system sov. section
systemSovTableClass: 'pf-module-table', // class for system sov. table
systemSovFwContestedRowClass: 'pf-system-sov-fw-contested-row', // class for "contested" sov. table row
systemSovFwOccupationRowClass: 'pf-system-sov-fw-occupation-row', // class for "-occupation" sov. table row
systemSovFwContestedClass: 'pf-system-sov-fw-contested',
systemSovFwPercentageClass: 'pf-system-sov-fw-percentage',
systemSovFwOccupationClass: 'pf-system-sov-fw-occupation',
systemSovFwOccupationImageClass: 'pf-system-sov-fw-occupation-image',
systemSovFwStatusIconClass: 'pf-system-sov-fw-status-icon',
// fonts
fontTriglivianClass: 'pf-triglivian', // class for "Triglivian" names (e.g. Abyssal systems)
@@ -115,12 +128,64 @@ define([
}
}
// update faction warfare rows ----------------------------------------------------------------------------
let fwContestedRow = moduleElement.find('.' + config.systemSovFwContestedRowClass);
let fwOccupationRow = moduleElement.find('.' + config.systemSovFwOccupationRowClass);
if(systemData.factionWar){
let contested = String(Util.getObjVal(systemData.factionWar, 'contested') || '');
let percentage = parseInt(Util.getObjVal(systemData.factionWar, 'victoryPercentage')) || 0;
let occupierFaction = Util.getObjVal(systemData.factionWar, 'occupierFaction');
let statusColor = 'red';
if(occupierFaction){
// system is "occupied" by hostile "occupierFaction" (stable)
// -> hide percent
statusColor = '#d9534f';
percentage += '%';
}else if('uncontested' === contested){
// system is "uncontested" and owned by default ownerFaction (stable)
// -> hide percent
statusColor = '#4f9e4f';
percentage = 'stable';
}else if('contested' === contested){
// system is "contested", 0%-99% percentage
statusColor = '#e28a0d';
percentage += '%';
}else if(
'vulnerable' === contested ||
'captured' === contested
){
// system is "vulnerable", 100% percentage
// -> "captured" state is might be the same?!
statusColor = '#d747d6';
percentage = '100%';
}
fwContestedRow.find('.' + config.systemSovFwStatusIconClass)[0].style.setProperty('--color', statusColor);
fwContestedRow.find('.' + config.systemSovFwContestedClass).text(contested);
fwContestedRow.find('.' + config.systemSovFwPercentageClass).text(percentage);
fwContestedRow.show();
let occupierFactionImage = Util.eveImageUrl('alliance', (occupierFaction ? occupierFaction.id : 0), 64);
let occupierFactionName = occupierFaction ? occupierFaction.name : '';
fwOccupationRow.find('.' + config.systemSovFwOccupationImageClass)[0].style.setProperty('--bg-image', 'url(\'' + occupierFactionImage + '\')');
fwOccupationRow.find('.' + config.systemSovFwOccupationClass).text(occupierFactionName);
if(occupierFaction){
fwOccupationRow.show();
}
}else{
fwContestedRow.hide();
fwOccupationRow.hide();
}
if(setUpdated){
moduleElement.data('updated', systemData.updated.updated);
}
}
moduleElement.find('.' + config.descriptionAreaClass).hideLoadingAnimation();
moduleElement.find('.' + config.systemSovSectionClass + ' .' + Util.config.dynamicAreaClass).hideLoadingAnimation();
};
/**
@@ -135,6 +200,56 @@ define([
// store systemId -> module can be updated with the correct data
moduleElement.data('id', systemData.id);
// system "sovereignty" data
// "primary" data is eigther "alliance" -> 0.0 space
// or "faction" -> Empire Regions (LS, HS)
let sovereigntyDefault = {
row1Label: 'Sov.',
row1Val: '???',
row1Img: undefined,
row1ImgTitle: undefined,
row2Label: undefined,
row2Val: undefined,
row3Label: undefined,
row3Val: undefined
};
let sovereigntyPrimary;
let sovereigntySecondary;
if(systemData.sovereignty){
let sovDataFact = Util.getObjVal(systemData.sovereignty, 'faction');
let sovDataAlly = Util.getObjVal(systemData.sovereignty, 'alliance');
let sovDataCorp = Util.getObjVal(systemData.sovereignty, 'corporation');
if(sovDataFact){
sovereigntyPrimary = {
row1Val: 'Faction',
row1Img: Util.eveImageUrl('alliance', sovDataFact.id, 64),
row1ImgTitle: sovDataFact.name,
row2Val: sovDataFact.name
};
}else{
if(sovDataAlly){
sovereigntyPrimary = {
row1Val: 'Alliance',
row1Img: Util.eveImageUrl('alliance', sovDataAlly.id, 64),
row1ImgTitle: sovDataAlly.name,
row2Val: '<' + sovDataAlly.ticker + '>',
row3Label: 'Ally',
row3Val: sovDataAlly.name
};
}
if(sovDataCorp){
sovereigntySecondary = {
row1Label: 'Corp',
row1Val: sovDataCorp.name,
row1Img: Util.eveImageUrl('corporation', sovDataCorp.id, 64)
};
}
}
}
// system "static" wh data
let staticsData = [];
if(
@@ -152,9 +267,15 @@ define([
let data = {
system: systemData,
sovereigntyPrimary: sovereigntyPrimary ? Object.assign({}, sovereigntyDefault, sovereigntyPrimary) : undefined,
sovereigntySecondary: sovereigntySecondary ? Object.assign({}, sovereigntyDefault, sovereigntySecondary) : undefined,
static: staticsData,
moduleHeadlineIconClass: config.moduleHeadlineIconClass,
tableClass: config.systemInfoTableClass,
infoSectionClass: config.systemInfoSectionClass,
descriptionSectionClass: config.descriptionSectionClass,
sovSectionClass: config.systemSovSectionClass,
infoTableClass: config.systemInfoTableClass,
sovTableClass: config.systemSovTableClass,
nameInfoClass: config.systemInfoNameClass,
effectInfoClass: config.systemInfoEffectClass,
planetsInfoClass: config.systemInfoPlanetsClass,
@@ -162,6 +283,15 @@ define([
statusInfoClass: config.systemInfoStatusLabelClass,
popoverTriggerClass: Util.config.popoverTriggerClass,
// sovereignty table
sovFwContestedRowClass: config.systemSovFwContestedRowClass,
sovFwOccupationRowClass: config.systemSovFwOccupationRowClass,
sovFwContestedInfoClass: config.systemSovFwContestedClass,
sovFwPercentageInfoClass: config.systemSovFwPercentageClass,
sovFwOccupationInfoClass: config.systemSovFwOccupationClass,
sovFwOccupationImageClass: config.systemSovFwOccupationImageClass,
sovFwStatusIconClass: config.systemSovFwStatusIconClass,
systemUrl: MapUtil.getMapDeeplinkUrl(mapId, systemData.id),
systemTypeName: MapUtil.getSystemTypeInfo(systemData.type.id, 'name'),
systemIsWormhole: MapUtil.getSystemTypeInfo(systemData.type.id, 'name') === 'w-space',
@@ -194,19 +324,22 @@ define([
systemConstellationLinkClass: config.constellationLinkClass,
systemRegionLinkClass: config.regionLinkClass,
systemTypeLinkClass: config.typeLinkClass,
systemUrlLinkClass: config.urlLinkClass
systemUrlLinkClass: config.urlLinkClass,
ccpImageServerUrl: Init.url.ccpImageServer,
};
requirejs(['text!templates/modules/system_info.html', 'mustache', 'summernote.loader'], (template, Mustache, Summernote) => {
let content = Mustache.render(template, data);
moduleElement.append(content);
let sovSectionArea = moduleElement.find('.' + config.systemSovSectionClass + ' .' + Util.config.dynamicAreaClass);
let descriptionArea = moduleElement.find('.' + config.descriptionAreaClass);
let descriptionButton = moduleElement.find('.' + config.addDescriptionButtonClass);
let descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
// lock "description" field until first update
descriptionArea.showLoadingAnimation();
sovSectionArea.showLoadingAnimation();
// WYSIWYG init on button click ---------------------------------------------------------------------------
descriptionButton.on('click', function(e){

View File

@@ -452,7 +452,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
value = '<img src="' + Init.url.ccpImageServer + '/Type/' + value + '_32.png" />';
value = '<img src="' + Util.eveImageUrl('type', value) +'"/>';
}
return value;
}
@@ -486,7 +486,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '<a href="https://zkillboard.com/corporation/' + data + '/" target="_blank" rel="noopener">';
value += '<img src="' + Init.url.ccpImageServer + '/Corporation/' + data + '_32.png" />';
value += '<img src="' + Util.eveImageUrl('corporation', data) + '"/>';
value += '</a>';
}
return value;
@@ -625,7 +625,7 @@ define([
'<tr class="group">' +
'<td></td>' +
'<td class="' + config.tableCellImageClass + '">' +
'<img src="' + Init.url.ccpImageServer + '/Corporation/' + group.id + '_32.png" />' +
'<img src="' + Util.eveImageUrl('corporation', group.id) + '"/>' +
'</td>' +
'<td colspan="' + (columnCount - 2 ) + '">' + group.name + '</td>' +
'</tr>'

View File

@@ -552,7 +552,7 @@ define([
userData: userData,
otherCharacters: () => {
return userData.characters.filter((character, i) => {
let characterImage = Init.url.ccpImageServer + '/Character/' + character.id + '_32.jpg';
let characterImage = eveImageUrl('character', character.id);
// preload image (prevent UI flicker
let img= new Image();
img.src = characterImage;
@@ -852,6 +852,23 @@ define([
*/
let showVersionInfo = () => Con.showVersionInfo(getVersion());
/**
* get CCP image URLs for
* @param type 'alliance'|'corporation'|'character'|'type'|'render'
* @param id
* @param size
* @returns {boolean}
*/
let eveImageUrl = (type, id, size = 32) => {
let url = false;
if(typeof type === 'string' && typeof id === 'number' && typeof size === 'number'){
type = type.capitalize();
let format = type === 'Character' ? 'jpg' : 'png';
url = Init.url.ccpImageServer + '/' + type + '/' + id + '_' + size + '.' + format;
}
return url;
};
/**
* polyfill for "passive" events
* -> see https://github.com/zzarcon/default-passive-events
@@ -2303,26 +2320,28 @@ define([
* get a HTML table with universe region information
* e.g. for popover
* @param regionName
* @param faction
* @param sovereignty
* @returns {string}
*/
let getSystemRegionTable = (regionName, faction) => {
let getSystemRegionTable = (regionName, sovereignty) => {
let data = [{label: 'Region', value: regionName}];
if(sovereignty){
if(sovereignty.faction){
data.push({label: 'Sov. Faction', value: sovereignty.faction.name});
}
if(sovereignty.alliance){
data.push({label: 'Sov. Ally', value: sovereignty.alliance.name});
}
}
let table = '<table>';
table += '<tr>';
table += '<td>';
table += 'Region';
table += '</td>';
table += '<td class="text-right">';
table += regionName;
table += '</td>';
table += '</tr>';
table += '<tr>';
if(faction){
for(let rowData of data){
table += '<tr>';
table += '<td>';
table += 'Faction';
table += rowData.label;
table += '</td>';
table += '<td class="text-right">';
table += faction.name;
table += rowData.value;
table += '</td>';
table += '</tr>';
}
@@ -3425,6 +3444,7 @@ define([
config: config,
getVersion: getVersion,
showVersionInfo: showVersionInfo,
eveImageUrl: eveImageUrl,
initPrototypes: initPrototypes,
initDefaultBootboxConfig: initDefaultBootboxConfig,
initDefaultConfirmationConfig: initDefaultConfirmationConfig,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +1,11 @@
<svg id="pf-logo-wrapper" xmlns="http://www.w3.org/2000/svg" version="1.2" width="0" height="0" shape-rendering="geometricPrecision">
<svg class="pf-logo-wrapper" xmlns="http://www.w3.org/2000/svg" version="1.2" width="0" height="0" shape-rendering="geometricPrecision">
<filter id="LogoFilterShadow" width="150%" height="150%">
<feOffset result="offOut" in="SourceAlpha" dx="-3" dy="3"/>
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="3"/>
<feBlend in="SourceGraphic" in2="blurOut" mode="normal"/>
</filter>
<symbol id="pf-logo" viewBox="0 0 355 370" >
<symbol id="pf-svg-logo" viewBox="0 0 355 370" >
<!-- comment this for filter within the use-tag -->
<!-- <g filter="url(#LogoFilterShadow)"> -->
<g>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,8 @@
<svg class="pf-logo-wrapper" xmlns="http://www.w3.org/2000/svg" version="1.2" width="0" height="0" shape-rendering="geometricPrecision">
<symbol id="pf-svg-swords" viewBox="0 0 512 512">
<g>
<path fill="currentColor"
d="M309.37 389.38l80-80L93.33 13.33 15.22.14C6.42-1.12-1.12 6.42.14 15.22l13.2 78.11 296.03 296.05zm197.94 72.68L448 402.75l31.64-59.03c3.33-6.22 2.2-13.88-2.79-18.87l-17.54-17.53c-6.25-6.25-16.38-6.25-22.63 0L307.31 436.69c-6.25 6.25-6.25 16.38 0 22.62l17.53 17.54a16 16 0 0 0 18.87 2.79L402.75 448l59.31 59.31c6.25 6.25 16.38 6.25 22.63 0l22.62-22.62c6.25-6.25 6.25-16.38 0-22.63zm-8.64-368.73l13.2-78.11c1.26-8.8-6.29-16.34-15.08-15.08l-78.11 13.2-140.05 140.03 80 80L498.67 93.33zm-345.3 185.3L100 332l-24.69-24.69c-6.25-6.25-16.38-6.25-22.62 0l-17.54 17.53a15.998 15.998 0 0 0-2.79 18.87L64 402.75 4.69 462.06c-6.25 6.25-6.25 16.38 0 22.63l22.62 22.62c6.25 6.25 16.38 6.25 22.63 0L109.25 448l59.03 31.64c6.22 3.33 13.88 2.2 18.87-2.79l17.53-17.54c6.25-6.25 6.25-16.38 0-22.62L180 412l53.37-53.37-80-80z"/>
</g>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -454,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,
@@ -471,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 '';

View File

@@ -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) + '_32.png"/>';
}
return value;
}

View File

@@ -546,13 +546,15 @@ 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('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 ){
@@ -3046,47 +3048,58 @@ 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,
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;

View File

@@ -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')
)
});
}

View File

@@ -806,10 +806,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);
};
/**
@@ -1869,10 +1868,10 @@ define([
if(tooltipData.maxStableTime){
data.maxStableTime = tooltipData.maxStableTime + ' h';
}
if(tooltipData.signatureStrength){
data.signatureStrength = parseFloat(tooltipData.signatureStrength).toLocaleString() + '&nbsp;&#37;';
if(tooltipData.scanWormholeStrength){
data.scanWormholeStrength = parseFloat(tooltipData.scanWormholeStrength).toLocaleString() + '&nbsp;&#37;';
}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;

View File

@@ -447,7 +447,7 @@ define([
// start user update trigger after map loaded
updateTimeouts.userUpdate = setTimeout(() => {
triggerUserUpdatePing();
}, 1000);
}, 500);
}
});
}

View File

@@ -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);

View File

@@ -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,
@@ -1026,7 +1054,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);
@@ -1094,9 +1122,8 @@ define([
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 += '>';
}

View File

@@ -93,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
}, {
@@ -116,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');
@@ -127,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('&nbsp;&nbsp;' + responseData.progress + '%').css('width', responseData.progress + '%');
// send next chunk of rows -> import only
@@ -136,6 +143,7 @@ define([
){
sendRequest(context.url, {
type: responseData.type,
countAll: responseData.countAll,
count: responseData.count,
offset: responseData.offset
}, {

View File

@@ -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';
}
};

View File

@@ -225,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: [],
@@ -312,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 = '&lt;' + cellData + '&gt;';
}
return value;
}
}
},{
name: 'planets',
title: '<i class="fas fa-circle" title="planets" data-toggle="tooltip"></i>',
@@ -748,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;
}
@@ -786,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;
}
@@ -826,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;
}
@@ -1109,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;
}

View File

@@ -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)) + '"/>';
}
}
},{

View File

@@ -38,19 +38,19 @@ define([
switch(data.categoryType){
case 'character':
imagePath = Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg';
imagePath = Util.eveImageUrl('character', data.id);
break;
case 'corporation':
imagePath = Init.url.ccpImageServer + '/Corporation/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('corporation', data.id);
break;
case 'alliance':
imagePath = Init.url.ccpImageServer + '/Alliance/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('alliance', data.id);
break;
case 'inventoryType':
imagePath = Init.url.ccpImageServer + '/Type/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('type', data.id);
break;
case 'render':
imagePath = Init.url.ccpImageServer + '/Render/' + data.id + '_32.png';
imagePath = Util.eveImageUrl('render', data.id);
break;
case 'station':
iconName = 'fa-home';

View File

@@ -774,7 +774,7 @@ define([
_: function(data, type, row){
let value = data.typeId;
if(type === 'display'){
value = '<img src="' + Init.url.ccpImageServer + '/Render/' + value + '_32.png" title="' + data.typeName + '" data-toggle="tooltip" />';
value = '<img src="' + Util.eveImageUrl('render', value) + '" title="' + data.typeName + '" data-toggle="tooltip" />';
}
return value;
}
@@ -794,7 +794,7 @@ define([
_: (cellData, type, rowData, meta) => {
let value = cellData.name;
if(type === 'display'){
value = '<img src="' + Init.url.ccpImageServer + '/Character/' + cellData.id + '_32.jpg" title="' + value + '" data-toggle="tooltip" />';
value = '<img src="' + Util.eveImageUrl('character', cellData.id) + '" title="' + value + '" data-toggle="tooltip" />';
}
return value;
}

View File

@@ -265,7 +265,7 @@ define([
for(let [graphKey, graphConfig] of Object.entries(config.systemGraphs)){
rowElement.append(
$('<div>', {
class: ['col-xs-12', 'col-sm-6', 'col-md-4'].join(' ')
class: ['col-xs-12', 'col-sm-4'].join(' ')
}).append(
$('<div>', {
class: config.moduleHeadClass

View File

@@ -27,7 +27,8 @@ define([
typeLinkClass: 'pf-system-info-type', // class for "type" name
urlLinkClass: 'pf-system-info-url', // class for "url" copy link
// info table
// info col/table
systemInfoSectionClass: 'pf-system-info-section', // class for system info section
systemInfoTableClass: 'pf-module-table', // class for system info table
systemInfoNameClass: 'pf-system-info-name', // class for "name" information element
systemInfoEffectClass: 'pf-system-info-effect', // class for "effect" information element
@@ -37,9 +38,21 @@ define([
systemInfoWormholeClass: 'pf-system-info-wormhole-', // class prefix for static wormhole element
// description field
descriptionAreaClass: 'pf-system-info-description-area', // class for "description" area
descriptionSectionClass: 'pf-system-description-section', // class for system description section
descriptionAreaClass: 'pf-system-info-description-area', // class for description area
addDescriptionButtonClass: 'pf-system-info-description-button', // class for "add description" button
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (Summernote)
descriptionTextareaElementClass: 'pf-system-info-description', // class for description textarea element (Summernote)
// sovereignty col/table
systemSovSectionClass: 'pf-system-sov-section', // class for system sov. section
systemSovTableClass: 'pf-module-table', // class for system sov. table
systemSovFwContestedRowClass: 'pf-system-sov-fw-contested-row', // class for "contested" sov. table row
systemSovFwOccupationRowClass: 'pf-system-sov-fw-occupation-row', // class for "-occupation" sov. table row
systemSovFwContestedClass: 'pf-system-sov-fw-contested',
systemSovFwPercentageClass: 'pf-system-sov-fw-percentage',
systemSovFwOccupationClass: 'pf-system-sov-fw-occupation',
systemSovFwOccupationImageClass: 'pf-system-sov-fw-occupation-image',
systemSovFwStatusIconClass: 'pf-system-sov-fw-status-icon',
// fonts
fontTriglivianClass: 'pf-triglivian', // class for "Triglivian" names (e.g. Abyssal systems)
@@ -115,12 +128,64 @@ define([
}
}
// update faction warfare rows ----------------------------------------------------------------------------
let fwContestedRow = moduleElement.find('.' + config.systemSovFwContestedRowClass);
let fwOccupationRow = moduleElement.find('.' + config.systemSovFwOccupationRowClass);
if(systemData.factionWar){
let contested = String(Util.getObjVal(systemData.factionWar, 'contested') || '');
let percentage = parseInt(Util.getObjVal(systemData.factionWar, 'victoryPercentage')) || 0;
let occupierFaction = Util.getObjVal(systemData.factionWar, 'occupierFaction');
let statusColor = 'red';
if(occupierFaction){
// system is "occupied" by hostile "occupierFaction" (stable)
// -> hide percent
statusColor = '#d9534f';
percentage += '%';
}else if('uncontested' === contested){
// system is "uncontested" and owned by default ownerFaction (stable)
// -> hide percent
statusColor = '#4f9e4f';
percentage = 'stable';
}else if('contested' === contested){
// system is "contested", 0%-99% percentage
statusColor = '#e28a0d';
percentage += '%';
}else if(
'vulnerable' === contested ||
'captured' === contested
){
// system is "vulnerable", 100% percentage
// -> "captured" state is might be the same?!
statusColor = '#d747d6';
percentage = '100%';
}
fwContestedRow.find('.' + config.systemSovFwStatusIconClass)[0].style.setProperty('--color', statusColor);
fwContestedRow.find('.' + config.systemSovFwContestedClass).text(contested);
fwContestedRow.find('.' + config.systemSovFwPercentageClass).text(percentage);
fwContestedRow.show();
let occupierFactionImage = Util.eveImageUrl('alliance', (occupierFaction ? occupierFaction.id : 0), 64);
let occupierFactionName = occupierFaction ? occupierFaction.name : '';
fwOccupationRow.find('.' + config.systemSovFwOccupationImageClass)[0].style.setProperty('--bg-image', 'url(\'' + occupierFactionImage + '\')');
fwOccupationRow.find('.' + config.systemSovFwOccupationClass).text(occupierFactionName);
if(occupierFaction){
fwOccupationRow.show();
}
}else{
fwContestedRow.hide();
fwOccupationRow.hide();
}
if(setUpdated){
moduleElement.data('updated', systemData.updated.updated);
}
}
moduleElement.find('.' + config.descriptionAreaClass).hideLoadingAnimation();
moduleElement.find('.' + config.systemSovSectionClass + ' .' + Util.config.dynamicAreaClass).hideLoadingAnimation();
};
/**
@@ -135,6 +200,56 @@ define([
// store systemId -> module can be updated with the correct data
moduleElement.data('id', systemData.id);
// system "sovereignty" data
// "primary" data is eigther "alliance" -> 0.0 space
// or "faction" -> Empire Regions (LS, HS)
let sovereigntyDefault = {
row1Label: 'Sov.',
row1Val: '???',
row1Img: undefined,
row1ImgTitle: undefined,
row2Label: undefined,
row2Val: undefined,
row3Label: undefined,
row3Val: undefined
};
let sovereigntyPrimary;
let sovereigntySecondary;
if(systemData.sovereignty){
let sovDataFact = Util.getObjVal(systemData.sovereignty, 'faction');
let sovDataAlly = Util.getObjVal(systemData.sovereignty, 'alliance');
let sovDataCorp = Util.getObjVal(systemData.sovereignty, 'corporation');
if(sovDataFact){
sovereigntyPrimary = {
row1Val: 'Faction',
row1Img: Util.eveImageUrl('alliance', sovDataFact.id, 64),
row1ImgTitle: sovDataFact.name,
row2Val: sovDataFact.name
};
}else{
if(sovDataAlly){
sovereigntyPrimary = {
row1Val: 'Alliance',
row1Img: Util.eveImageUrl('alliance', sovDataAlly.id, 64),
row1ImgTitle: sovDataAlly.name,
row2Val: '<' + sovDataAlly.ticker + '>',
row3Label: 'Ally',
row3Val: sovDataAlly.name
};
}
if(sovDataCorp){
sovereigntySecondary = {
row1Label: 'Corp',
row1Val: sovDataCorp.name,
row1Img: Util.eveImageUrl('corporation', sovDataCorp.id, 64)
};
}
}
}
// system "static" wh data
let staticsData = [];
if(
@@ -152,9 +267,15 @@ define([
let data = {
system: systemData,
sovereigntyPrimary: sovereigntyPrimary ? Object.assign({}, sovereigntyDefault, sovereigntyPrimary) : undefined,
sovereigntySecondary: sovereigntySecondary ? Object.assign({}, sovereigntyDefault, sovereigntySecondary) : undefined,
static: staticsData,
moduleHeadlineIconClass: config.moduleHeadlineIconClass,
tableClass: config.systemInfoTableClass,
infoSectionClass: config.systemInfoSectionClass,
descriptionSectionClass: config.descriptionSectionClass,
sovSectionClass: config.systemSovSectionClass,
infoTableClass: config.systemInfoTableClass,
sovTableClass: config.systemSovTableClass,
nameInfoClass: config.systemInfoNameClass,
effectInfoClass: config.systemInfoEffectClass,
planetsInfoClass: config.systemInfoPlanetsClass,
@@ -162,6 +283,15 @@ define([
statusInfoClass: config.systemInfoStatusLabelClass,
popoverTriggerClass: Util.config.popoverTriggerClass,
// sovereignty table
sovFwContestedRowClass: config.systemSovFwContestedRowClass,
sovFwOccupationRowClass: config.systemSovFwOccupationRowClass,
sovFwContestedInfoClass: config.systemSovFwContestedClass,
sovFwPercentageInfoClass: config.systemSovFwPercentageClass,
sovFwOccupationInfoClass: config.systemSovFwOccupationClass,
sovFwOccupationImageClass: config.systemSovFwOccupationImageClass,
sovFwStatusIconClass: config.systemSovFwStatusIconClass,
systemUrl: MapUtil.getMapDeeplinkUrl(mapId, systemData.id),
systemTypeName: MapUtil.getSystemTypeInfo(systemData.type.id, 'name'),
systemIsWormhole: MapUtil.getSystemTypeInfo(systemData.type.id, 'name') === 'w-space',
@@ -194,19 +324,22 @@ define([
systemConstellationLinkClass: config.constellationLinkClass,
systemRegionLinkClass: config.regionLinkClass,
systemTypeLinkClass: config.typeLinkClass,
systemUrlLinkClass: config.urlLinkClass
systemUrlLinkClass: config.urlLinkClass,
ccpImageServerUrl: Init.url.ccpImageServer,
};
requirejs(['text!templates/modules/system_info.html', 'mustache', 'summernote.loader'], (template, Mustache, Summernote) => {
let content = Mustache.render(template, data);
moduleElement.append(content);
let sovSectionArea = moduleElement.find('.' + config.systemSovSectionClass + ' .' + Util.config.dynamicAreaClass);
let descriptionArea = moduleElement.find('.' + config.descriptionAreaClass);
let descriptionButton = moduleElement.find('.' + config.addDescriptionButtonClass);
let descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
// lock "description" field until first update
descriptionArea.showLoadingAnimation();
sovSectionArea.showLoadingAnimation();
// WYSIWYG init on button click ---------------------------------------------------------------------------
descriptionButton.on('click', function(e){

View File

@@ -452,7 +452,7 @@ define([
_: function(data, type, row, meta){
let value = data;
if(type === 'display' && value){
value = '<img src="' + Init.url.ccpImageServer + '/Type/' + value + '_32.png" />';
value = '<img src="' + Util.eveImageUrl('type', value) +'"/>';
}
return value;
}
@@ -486,7 +486,7 @@ define([
let value = data;
if(type === 'display' && value){
value = '<a href="https://zkillboard.com/corporation/' + data + '/" target="_blank" rel="noopener">';
value += '<img src="' + Init.url.ccpImageServer + '/Corporation/' + data + '_32.png" />';
value += '<img src="' + Util.eveImageUrl('corporation', data) + '"/>';
value += '</a>';
}
return value;
@@ -625,7 +625,7 @@ define([
'<tr class="group">' +
'<td></td>' +
'<td class="' + config.tableCellImageClass + '">' +
'<img src="' + Init.url.ccpImageServer + '/Corporation/' + group.id + '_32.png" />' +
'<img src="' + Util.eveImageUrl('corporation', group.id) + '"/>' +
'</td>' +
'<td colspan="' + (columnCount - 2 ) + '">' + group.name + '</td>' +
'</tr>'

View File

@@ -552,7 +552,7 @@ define([
userData: userData,
otherCharacters: () => {
return userData.characters.filter((character, i) => {
let characterImage = Init.url.ccpImageServer + '/Character/' + character.id + '_32.jpg';
let characterImage = eveImageUrl('character', character.id);
// preload image (prevent UI flicker
let img= new Image();
img.src = characterImage;
@@ -852,6 +852,23 @@ define([
*/
let showVersionInfo = () => Con.showVersionInfo(getVersion());
/**
* get CCP image URLs for
* @param type 'alliance'|'corporation'|'character'|'type'|'render'
* @param id
* @param size
* @returns {boolean}
*/
let eveImageUrl = (type, id, size = 32) => {
let url = false;
if(typeof type === 'string' && typeof id === 'number' && typeof size === 'number'){
type = type.capitalize();
let format = type === 'Character' ? 'jpg' : 'png';
url = Init.url.ccpImageServer + '/' + type + '/' + id + '_' + size + '.' + format;
}
return url;
};
/**
* polyfill for "passive" events
* -> see https://github.com/zzarcon/default-passive-events
@@ -2303,26 +2320,28 @@ define([
* get a HTML table with universe region information
* e.g. for popover
* @param regionName
* @param faction
* @param sovereignty
* @returns {string}
*/
let getSystemRegionTable = (regionName, faction) => {
let getSystemRegionTable = (regionName, sovereignty) => {
let data = [{label: 'Region', value: regionName}];
if(sovereignty){
if(sovereignty.faction){
data.push({label: 'Sov. Faction', value: sovereignty.faction.name});
}
if(sovereignty.alliance){
data.push({label: 'Sov. Ally', value: sovereignty.alliance.name});
}
}
let table = '<table>';
table += '<tr>';
table += '<td>';
table += 'Region';
table += '</td>';
table += '<td class="text-right">';
table += regionName;
table += '</td>';
table += '</tr>';
table += '<tr>';
if(faction){
for(let rowData of data){
table += '<tr>';
table += '<td>';
table += 'Faction';
table += rowData.label;
table += '</td>';
table += '<td class="text-right">';
table += faction.name;
table += rowData.value;
table += '</td>';
table += '</tr>';
}
@@ -3425,6 +3444,7 @@ define([
config: config,
getVersion: getVersion,
showVersionInfo: showVersionInfo,
eveImageUrl: eveImageUrl,
initPrototypes: initPrototypes,
initDefaultBootboxConfig: initDefaultBootboxConfig,
initDefaultConfirmationConfig: initDefaultConfirmationConfig,

View File

@@ -1,7 +1,10 @@
<p>Shows status information for external used APIs. Provides a general health indicator per route and method.</p>
<h4 class="pf-dynamic-area">{{ apiData.name }}
<span class="pull-right" title="{{#statusTitle}}{{ apiData.statusColor }}{{/statusTitle}}"><i class="fas fa-fw fa-circle txt-color txt-color-{{ apiData.statusColor }}"></i></span>
<h4 class="pf-dynamic-area">
<span class="pf-help-default" title="{{#statusTitle}}{{ apiData.statusColor }}{{/statusTitle}}">
<i class="fas fa-fw fa-circle txt-color txt-color-{{ apiData.statusColor }}"></i>
</span>&nbsp;&nbsp;{{ apiData.name }}
<span class="pull-right pf-help-default" title="{{#apiData.cacheExpire}}{{ apiData.cacheExpire }}{{/apiData.cacheExpire}}">{{ apiData.cache }}</span>
</h4>
<dl class="dl-horizontal" style="float: left;">
@@ -42,7 +45,7 @@
<tbody>
{{#apiData.routes}}
<tr>
<td class="text-center txt-color txt-color-grayLight txt-color-{{ status }}" title="{{#statusTitle}}{{status}}{{/statusTitle}}">
<td class="text-center pf-help-default txt-color txt-color-grayLight txt-color-{{ status }}" title="{{#statusTitle}}{{status}}{{/statusTitle}}">
<i class="fas fa-fw fa-circle initialism"></i>
</td>
<td class="text-center">

View File

@@ -44,8 +44,8 @@
<td class="text-right" data-order="{{massIndividual}}">{{#massValue}}{{massIndividual}}{{/massValue}}</td>
<td class="text-right" data-order="{{massRegeneration}}">{{#massValue}}{{massRegeneration}}{{/massValue}}</td>
<td class="text-right txt-color {{^maxStableTime}}txt-color-grayLight{{/maxStableTime}}" data-order="{{maxStableTime}}">{{#formatTime}}{{maxStableTime}}{{/formatTime}}</td>
<td class="text-right txt-color {{^signatureStrength}}txt-color-grayLight{{/signatureStrength}}" data-order="{{signatureStrength}}">
{{#sigStrengthValue}}{{signatureStrength}}{{/sigStrengthValue}}
<td class="text-right txt-color {{^scanWormholeStrength}}txt-color-grayLight{{/scanWormholeStrength}}" data-order="{{scanWormholeStrength}}">
{{#sigStrengthValue}}{{scanWormholeStrength}}{{/sigStrengthValue}}
</td>
</tr>
{{/wormholes}}

View File

@@ -1,13 +1,9 @@
{{! Render the *.svg logo. So it can be used through the "use" tag}}
{{{logo}}}
<nav id="{{id}}" class="navbar navbar-default pf-head" role="navigation">
<div class="container-fluid">
<div class="navbar-header pull-left">
<a class="navbar-brand pf-head-menu" href="">
<svg class="{{brandLogo}}" width="24px" height="24px">
<use xlink:href="#pf-logo"/>
<use xlink:href="#pf-svg-logo"/>
</svg>
&nbsp;&nbsp;Menu
</a>

View File

@@ -38,7 +38,7 @@
</check>
<td
class="{{ isset(@requirement.required) ? 'text-right col-md-3 text-right' : 'text-right col-md-6 text-right' }}"
class="{{ isset(@requirement.required) ? 'text-right col-xs-2 col-md-3 text-right' : 'text-right col-xs-4 col-md-6 text-right' }}"
colspan="{{ isset(@requirement.required) ? '1' : '2' }}"
>
<check if="{{ @requirement.check }}">
@@ -55,7 +55,7 @@
<check if="{{ @requirement.task }}">
<true>
<td class="text-right col-md-2 no-padding text-right">
<td class="text-right col-xs-{{ count(@requirement.task) * 2 }} col-md-{{ count(@requirement.task) * 2 }} no-padding text-right">
<div class="btn-group btn-group-justified">
<repeat group="{{ @requirement.task }}" key="{{ @taskKey }}" value="{{ @taskData }}">
<a href="?{{ @taskData.action }}" class="btn btn-default {{ @taskData.btn }}" role="button">
@@ -67,7 +67,7 @@
</true>
<false>
{* no task data *}
<td class="text-right col-md-1">
<td class="text-right col-sm-1 col-md-1">
<check if="{{ @requirement.check }}">
<true>
{* Check ok *}

View File

@@ -35,30 +35,20 @@
<div class="row">
{{! info text ================================================================================================ }}
<div class="col-xs-12 col-sm-9">
<div class="pf-dynamic-area {{descriptionAreaClass}}">
<div class="{{descriptionTextareaClass}} {{summernoteClass}}"></div>
<i class="fas fa-fw fa-lg fa-pen pull-right {{moduleHeadlineIconClass}} {{descriptionButtonClass}}" data-toggle="tooltip" title="edit description"></i>
</div>
</div>
{{! info table ================================================================================================ }}
<div class="col-xs-12 col-sm-3">
{{! Info table ================================================================================================ }}
<div class="col-xs-6 col-sm-3 {{infoSectionClass}}">
<span data-toggle="tooltip" title="status" data-status="{{systemStatusId}}" class="label center-block {{statusInfoClass}} {{systemStatusClass}}">
{{systemStatusLabel}}
</span>
<div class="pf-dynamic-area">
<table class="table table-condensed pf-table-fixed {{tableClass}}">
<table class="table table-condensed pf-table-fixed {{infoTableClass}}">
<thead>
<tr>
<th>Name</th>
<th class="text-right pf-system-info-name-cell">
<th class="text-right pf-table-cell-ellipses-auto pf-system-info-name-cell">
{{#system.shattered}}
<i class="fas fa-fw fa-skull {{shatteredClass}}" data-toggle="tooltip" title="shattered"></i>&nbsp;
<i class="fas fa-fw fa-skull {{shatteredClass}}" data-toggle="tooltip" title="shattered"></i>&nbsp;
{{/system.shattered}}
<span class="pf-help-default {{nameInfoClass}} {{#systemNameClass}}{{system.security}}{{/systemNameClass}}">{{system.name}}</span>
</th>
@@ -102,6 +92,77 @@
</table>
</div>
</div>
{{! Sovereignty table ========================================================================================= }}
<div class="col-xs-6 col-sm-3 {{sovSectionClass}} {{^sovereigntyPrimary}}hidden{{/sovereigntyPrimary}}">
<div class="pf-dynamic-area">
<table class="table table-condensed pf-table-fixed {{sovTableClass}}">
<colgroup>
<col style="width: 40px;"/>
<col/>
<col style="width: 45px;"/>
</colgroup>
<thead>
{{#sovereigntyPrimary}}
<tr>
<th>{{row1Label}}</th>
<th class="text-right">{{row1Val}}</th>
<th class="pf-table-cell-bg-image" rowspan="2">
<div class="pf-table-cell-bg-image-wrapper pf-help-default" style="--bg-image: url('{{{row1Img}}}');" data-toggle="tooltip" title="{{row1ImgTitle}}"></div>
</th>
</tr>
<tr>
<th>{{#row2Label}}{{row2Label}}{{/row2Label}}</th>
<th class="text-right pf-table-cell-ellipses-auto">{{#row2Val}}{{row2Val}}{{/row2Val}}</th>
</tr>
{{/sovereigntyPrimary}}
</thead>
<tbody>
{{#sovereigntyPrimary.row3Val}}
<tr>
<td>{{sovereigntyPrimary.row3Label}}</td>
<td colspan="2" class="text-right pf-table-cell-ellipses-auto">{{sovereigntyPrimary.row3Val}}</td>
</tr>
{{/sovereigntyPrimary.row3Val}}
{{#sovereigntySecondary}}
<tr>
<td>{{row1Label}}</td>
<td colspan="2" class="text-right pf-table-cell-ellipses-auto">{{row1Val}}</td>
</tr>
{{/sovereigntySecondary}}
<tr class="{{sovFwContestedRowClass}}">
<td>
<svg class="pf-system-info-svg pf-help-default" width="12px" height="12px" data-toggle="tooltip" title="Faction Warfare System">
<use xlink:href="#pf-svg-swords"/>
</svg>
<i class="fas fa-flag {{sovFwStatusIconClass}}"></i>
</td>
<td class="text-right pf-table-cell-ellipses-auto {{sovFwContestedInfoClass}}"></td>
<td class="text-right {{sovFwPercentageInfoClass}}"></td>
</tr>
<tr class="{{sovFwOccupationRowClass}}">
<td></td>
<td class="text-right pf-table-cell-ellipses-auto">occupied&nbsp;by</td>
<td class="pf-table-cell-bg-image" rowspan="2">
<div class="pf-table-cell-bg-image-wrapper pf-help-default {{sovFwOccupationImageClass}}"></div>
</td>
</tr>
<tr class="{{sovFwOccupationRowClass}}">
<td colspan="2" class="text-right pf-table-cell-ellipses-auto {{sovFwOccupationInfoClass}}"></td>
</tr>
</tbody>
</table>
</div>
</div>
{{! Description editor ======================================================================================== }}
<div class="col-xs-12 col-sm-6 {{^sovereigntyPrimary}}col-sm-9{{/sovereigntyPrimary}} {{descriptionSectionClass}}">
<div class="pf-dynamic-area {{descriptionAreaClass}}">
<div class="{{descriptionTextareaClass}} {{summernoteClass}}"></div>
<i class="fas fa-fw fa-lg fa-pen pull-right {{moduleHeadlineIconClass}} {{descriptionButtonClass}}" data-toggle="tooltip" title="edit description"></i>
</div>
</div>
</div>

View File

@@ -23,11 +23,11 @@
<td class="text-right">{{maxStableTime}}</td>
</tr>
{{/maxStableTime}}
{{#signatureStrength}}
{{#scanWormholeStrength}}
<tr>
<td>Sig strength</td>
<td class="text-right">{{{signatureStrength}}}</td>
<td class="text-right">{{{scanWormholeStrength}}}</td>
</tr>
{{/signatureStrength}}
{{/scanWormholeStrength}}
</table>

View File

@@ -17,10 +17,11 @@
{{#api}}
<h4>{{ name }}</h4>
<ul class="fa-ul">
<li><i class="fa-li fas fa-hdd"></i>{{cache}}</li>
{{#status}}
<li><i class="fa-li fas fa-server"></i><span class="txt-color {{#statusFormat}}{{statusColor}}{{/statusFormat}}">{{ status }}</span></li>
{{/status}}
<li><i class="fa-li fas fa-question"></i><a class="{{ apiStatusTriggerClass }}" href="#">info</a></li>
<li><i class="fa-li fas fa-info"></i><a class="{{ apiStatusTriggerClass }}" href="#">info</a></li>
</ul>
{{/api}}
</div>

Some files were not shown because too many files have changed in this diff Show More