pathfinder-84 [Feature Request] CREST Pilot Tracking, many smaller Bugfixes
This commit is contained in:
@@ -7,25 +7,24 @@
|
||||
*/
|
||||
|
||||
namespace controller\api;
|
||||
use Controller;
|
||||
use Model;
|
||||
|
||||
class Access extends \Controller\AccessController {
|
||||
class Access extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* event handler
|
||||
* @param $f3
|
||||
* @param \Base $f3
|
||||
*/
|
||||
function beforeroute($f3) {
|
||||
|
||||
parent::beforeroute($f3);
|
||||
|
||||
function beforeroute(\Base $f3) {
|
||||
// set header for all routes
|
||||
header('Content-type: application/json');
|
||||
parent::beforeroute($f3);
|
||||
}
|
||||
|
||||
/**
|
||||
* search user/corporation or alliance by name
|
||||
* @param $f3
|
||||
* search character/corporation or alliance by name
|
||||
* @param \Base $f3
|
||||
* @param $params
|
||||
*/
|
||||
public function search($f3, $params){
|
||||
@@ -41,8 +40,8 @@ class Access extends \Controller\AccessController {
|
||||
|
||||
$accessModel = null;
|
||||
switch($searchType){
|
||||
case 'user':
|
||||
$accessModel = Model\BasicModel::getNew('UserModel');
|
||||
case 'character':
|
||||
$accessModel = Model\BasicModel::getNew('CharacterModel');
|
||||
break;
|
||||
case 'corporation':
|
||||
$accessModel = Model\BasicModel::getNew('CorporationModel');
|
||||
@@ -55,12 +54,12 @@ class Access extends \Controller\AccessController {
|
||||
if( is_object($accessModel) ){
|
||||
|
||||
// find "active" entries that have their "sharing" option activated
|
||||
$accessList = $accessModel->find( array(
|
||||
$accessList = $accessModel->find( [
|
||||
"LOWER(name) LIKE :token AND " .
|
||||
"active = 1 AND " .
|
||||
"shared = 1 ",
|
||||
':token' => '%' . $searchToken . '%'
|
||||
));
|
||||
]);
|
||||
|
||||
if($accessList){
|
||||
foreach($accessList as $accessObject){
|
||||
|
||||
@@ -40,7 +40,6 @@ class Connection extends Controller\AccessController{
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
|
||||
// get map model and check map access
|
||||
/**
|
||||
@@ -49,7 +48,7 @@ class Connection extends Controller\AccessController{
|
||||
$map = Model\BasicModel::getNew('MapModel');
|
||||
$map->getById( (int)$mapData['id'] );
|
||||
|
||||
if( $map->hasAccess($user) ){
|
||||
if( $map->hasAccess($activeCharacter) ){
|
||||
$source = $map->getSystem( (int)$connectionData['source'] );
|
||||
$target = $map->getSystem( (int)$connectionData['target'] );
|
||||
|
||||
@@ -57,6 +56,9 @@ class Connection extends Controller\AccessController{
|
||||
!is_null($source) &&
|
||||
!is_null($target)
|
||||
){
|
||||
/**
|
||||
* @var $connection Model\ConnectionModel
|
||||
*/
|
||||
$connection = Model\BasicModel::getNew('ConnectionModel');
|
||||
$connection->getById( (int)$connectionData['id'] );
|
||||
|
||||
@@ -103,17 +105,20 @@ class Connection extends Controller\AccessController{
|
||||
$connectionIds = $f3->get('POST.connectionIds');
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
/**
|
||||
* @var Model\ConnectionModel $connection
|
||||
*/
|
||||
$connection = Model\BasicModel::getNew('ConnectionModel');
|
||||
foreach($connectionIds as $connectionId){
|
||||
$connection->getById($connectionId);
|
||||
$connection->delete( $activeCharacter->getUser() );
|
||||
if($activeCharacter = $this->getCharacter()){
|
||||
/**
|
||||
* @var Model\ConnectionModel $connection
|
||||
*/
|
||||
$connection = Model\BasicModel::getNew('ConnectionModel');
|
||||
foreach($connectionIds as $connectionId){
|
||||
$connection->getById($connectionId);
|
||||
$connection->delete( $activeCharacter );
|
||||
|
||||
$connection->reset();
|
||||
$connection->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
echo json_encode([]);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,11 @@ class Map extends Controller\AccessController {
|
||||
|
||||
$f3->expire($expireTimeHead);
|
||||
|
||||
$initData = [];
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
|
||||
// static program data ------------------------------------------------
|
||||
$initData['timer'] = $f3->get('PATHFINDER.TIMER');
|
||||
$return->timer = $f3->get('PATHFINDER.TIMER');
|
||||
|
||||
// get all available map types ----------------------------------------
|
||||
$mapType = Model\BasicModel::getNew('MapTypeModel');
|
||||
@@ -59,7 +60,7 @@ class Map extends Controller\AccessController {
|
||||
$mapTypeData[$rowData->name] = $data;
|
||||
|
||||
}
|
||||
$initData['mapTypes'] = $mapTypeData;
|
||||
$return->mapTypes = $mapTypeData;
|
||||
|
||||
// get all available map scopes ---------------------------------------
|
||||
$mapScope = Model\BasicModel::getNew('MapScopeModel');
|
||||
@@ -72,7 +73,7 @@ class Map extends Controller\AccessController {
|
||||
];
|
||||
$mapScopeData[$rowData->name] = $data;
|
||||
}
|
||||
$initData['mapScopes'] = $mapScopeData;
|
||||
$return->mapScopes = $mapScopeData;
|
||||
|
||||
// get all available system status ------------------------------------
|
||||
$systemStatus = Model\BasicModel::getNew('SystemStatusModel');
|
||||
@@ -86,7 +87,7 @@ class Map extends Controller\AccessController {
|
||||
];
|
||||
$systemScopeData[$rowData->name] = $data;
|
||||
}
|
||||
$initData['systemStatus'] = $systemScopeData;
|
||||
$return->systemStatus = $systemScopeData;
|
||||
|
||||
// get all available system types -------------------------------------
|
||||
$systemType = Model\BasicModel::getNew('SystemTypeModel');
|
||||
@@ -99,7 +100,7 @@ class Map extends Controller\AccessController {
|
||||
];
|
||||
$systemTypeData[$rowData->name] = $data;
|
||||
}
|
||||
$initData['systemType'] = $systemTypeData;
|
||||
$return->systemType = $systemTypeData;
|
||||
|
||||
// get available connection scopes ------------------------------------
|
||||
$connectionScope = Model\BasicModel::getNew('ConnectionScopeModel');
|
||||
@@ -113,7 +114,7 @@ class Map extends Controller\AccessController {
|
||||
];
|
||||
$connectionScopeData[$rowData->name] = $data;
|
||||
}
|
||||
$initData['connectionScopes'] = $connectionScopeData;
|
||||
$return->connectionScopes = $connectionScopeData;
|
||||
|
||||
// get available character status -------------------------------------
|
||||
$characterStatus = Model\BasicModel::getNew('CharacterStatusModel');
|
||||
@@ -127,17 +128,33 @@ class Map extends Controller\AccessController {
|
||||
];
|
||||
$characterStatusData[$rowData->name] = $data;
|
||||
}
|
||||
$initData['characterStatus'] = $characterStatusData;
|
||||
$return->characterStatus = $characterStatusData;
|
||||
|
||||
// get max number of shared entities per map --------------------------
|
||||
$maxSharedCount = [
|
||||
'user' => $f3->get('PATHFINDER.MAX_SHARED_USER'),
|
||||
'character' => $f3->get('PATHFINDER.MAX_SHARED_CHARACTER'),
|
||||
'corporation' => $f3->get('PATHFINDER.MAX_SHARED_CORPORATION'),
|
||||
'alliance' => $f3->get('PATHFINDER.MAX_SHARED_ALLIANCE'),
|
||||
];
|
||||
$initData['maxSharedCount'] = $maxSharedCount;
|
||||
$return->maxSharedCount = $maxSharedCount;
|
||||
|
||||
echo json_encode($initData);
|
||||
// get program routes -------------------------------------------------
|
||||
$return->routes = [
|
||||
'ssoLogin' => $this->getF3()->alias( 'sso', ['action' => 'requestAuthorization'] )
|
||||
];
|
||||
|
||||
// get SSO error messages that should be shown immediately ------------
|
||||
// -> e.g. errors while character switch from previous HTTP requests
|
||||
if( $f3->exists(Controller\Ccp\Sso::SESSION_KEY_SSO_ERROR) ){
|
||||
$ssoError = (object) [];
|
||||
$ssoError->type = 'error';
|
||||
$ssoError->title = 'Login failed';
|
||||
$ssoError->message = $f3->get(Controller\Ccp\Sso::SESSION_KEY_SSO_ERROR);
|
||||
$return->error[] = $ssoError;
|
||||
$f3->clear(Controller\Ccp\Sso::SESSION_KEY_SSO_ERROR);
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +230,6 @@ class Map extends Controller\AccessController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach($mapData['data']['connections'] as $connectionData){
|
||||
// check if source and target IDs match with new system ID
|
||||
if(
|
||||
@@ -296,7 +312,6 @@ class Map extends Controller\AccessController {
|
||||
$activeCharacter = $this->getCharacter(0);
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
|
||||
/**
|
||||
* @var $map Model\MapModel
|
||||
@@ -306,7 +321,7 @@ class Map extends Controller\AccessController {
|
||||
|
||||
if(
|
||||
$map->dry() ||
|
||||
$map->hasAccess($user)
|
||||
$map->hasAccess($activeCharacter)
|
||||
){
|
||||
// new map
|
||||
$map->setData($formData);
|
||||
@@ -315,36 +330,36 @@ class Map extends Controller\AccessController {
|
||||
// save global map access. Depends on map "type"
|
||||
if($map->isPrivate()){
|
||||
|
||||
// share map between users -> set access
|
||||
if(isset($formData['mapUsers'])){
|
||||
// share map between characters -> set access
|
||||
if(isset($formData['mapCharacters'])){
|
||||
// avoid abuse -> respect share limits
|
||||
$accessUsers = array_slice( $formData['mapUsers'], 0, $f3->get('PATHFINDER.MAX_SHARED_USER') );
|
||||
$accessCharacters = array_slice( $formData['mapCharacters'], 0, $f3->get('PATHFINDER.MAX_SHARED_CHARACTER') );
|
||||
|
||||
// clear map access. In case something has removed from access list
|
||||
$map->clearAccess();
|
||||
|
||||
/**
|
||||
* @var $tempUser Model\UserModel
|
||||
* @var $tempCharacter Model\CharacterModel
|
||||
*/
|
||||
$tempUser = Model\BasicModel::getNew('UserModel');
|
||||
$tempCharacter = Model\BasicModel::getNew('CharacterModel');
|
||||
|
||||
foreach($accessUsers as $userId){
|
||||
$tempUser->getById( (int)$userId );
|
||||
foreach($accessCharacters as $characterId){
|
||||
$tempCharacter->getById( (int)$characterId );
|
||||
|
||||
if(
|
||||
!$tempUser->dry() &&
|
||||
$tempUser->shared == 1 // check if map shared is enabled
|
||||
!$tempCharacter->dry() &&
|
||||
$tempCharacter->shared == 1 // check if map shared is enabled
|
||||
){
|
||||
$map->setAccess($tempUser);
|
||||
$map->setAccess($tempCharacter);
|
||||
}
|
||||
|
||||
$tempUser->reset();
|
||||
$tempCharacter->reset();
|
||||
}
|
||||
}
|
||||
|
||||
// the current user itself should always have access
|
||||
// the current character itself should always have access
|
||||
// just in case he removed himself :)
|
||||
$map->setAccess($user);
|
||||
$map->setAccess($activeCharacter);
|
||||
}elseif($map->isCorporation()){
|
||||
$corporation = $activeCharacter->getCorporation();
|
||||
|
||||
@@ -459,7 +474,7 @@ class Map extends Controller\AccessController {
|
||||
*/
|
||||
$map = Model\BasicModel::getNew('MapModel');
|
||||
$map->getById($mapData['id']);
|
||||
$map->delete( $activeCharacter->getUser() );
|
||||
$map->delete( $activeCharacter );
|
||||
}
|
||||
|
||||
echo json_encode([]);
|
||||
@@ -480,15 +495,15 @@ class Map extends Controller\AccessController {
|
||||
|
||||
if($activeCharacter){
|
||||
|
||||
$cacheKey = 'user_map_data_' . $activeCharacter->id;
|
||||
$cacheKey = 'user_map_data_' . $activeCharacter->_id;
|
||||
|
||||
// if there is any system/connection change data submitted -> save new data
|
||||
if(
|
||||
!$f3->exists($cacheKey) ||
|
||||
!empty($mapData)
|
||||
!empty($mapData) ||
|
||||
!$f3->exists($cacheKey)
|
||||
){
|
||||
// get current map data ========================================================
|
||||
$maps = $activeCharacter->getUser()->getMaps();
|
||||
$maps = $activeCharacter->getMaps();
|
||||
|
||||
// loop all submitted map data that should be saved
|
||||
// -> currently there will only be ONE map data change submitted -> single loop
|
||||
@@ -583,7 +598,7 @@ class Map extends Controller\AccessController {
|
||||
|
||||
// cache time(s) per user should be equal or less than this function is called
|
||||
// prevent request flooding
|
||||
$responseTTL = $f3->get('PATHFINDER.TIMER.UPDATE_SERVER_MAP.DELAY') / 1000;
|
||||
$responseTTL = (int)$f3->get('PATHFINDER.TIMER.UPDATE_SERVER_MAP.DELAY') / 1000;
|
||||
|
||||
$f3->set($cacheKey, $return, $responseTTL);
|
||||
}else{
|
||||
@@ -631,17 +646,16 @@ class Map extends Controller\AccessController {
|
||||
public function updateUserData(\Base $f3){
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
$activeCharacter = $this->getCharacter();
|
||||
$activeCharacter = $this->getCharacter(0);
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
|
||||
if( !empty($f3->get('POST.mapIds')) ){
|
||||
$mapIds = (array)$f3->get('POST.mapIds');
|
||||
// check if data for specific system is requested
|
||||
$systemData = (array)$f3->get('POST.systemData');
|
||||
// update current location
|
||||
$activeCharacter->updateLog();
|
||||
$activeCharacter = $activeCharacter->updateLog();
|
||||
|
||||
// if data is requested extend the cache key in order to get new data
|
||||
$requestSystemData = (object) [];
|
||||
@@ -657,7 +671,7 @@ class Map extends Controller\AccessController {
|
||||
$cacheKey = 'user_data_' . $tempId . '_' . $requestSystemData->systemId;
|
||||
if( !$f3->exists($cacheKey) ){
|
||||
foreach($mapIds as $mapId){
|
||||
$map = $user->getMap($mapId);
|
||||
$map = $activeCharacter->getMap($mapId);
|
||||
|
||||
if( !is_null($map) ){
|
||||
$return->mapUserData[] = $map->getUserData();
|
||||
@@ -677,7 +691,7 @@ class Map extends Controller\AccessController {
|
||||
|
||||
// cache time (seconds) should be equal or less than request trigger time
|
||||
// prevent request flooding
|
||||
$responseTTL = $f3->get('PATHFINDER.TIMER.UPDATE_SERVER_USER_DATA.DELAY') / 1000;
|
||||
$responseTTL = (int)$f3->get('PATHFINDER.TIMER.UPDATE_SERVER_USER_DATA.DELAY') / 1000;
|
||||
|
||||
// cache response
|
||||
$f3->set($cacheKey, $return, $responseTTL);
|
||||
@@ -688,9 +702,10 @@ class Map extends Controller\AccessController {
|
||||
$return = $f3->get($cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
// get current user data -> this should not be cached because each user has different personal data
|
||||
// even if they have multiple characters using the same map!
|
||||
$return->userData = $user->getData();
|
||||
$return->userData = $activeCharacter->getUser()->getData();
|
||||
}else{
|
||||
// user logged off
|
||||
$return->error[] = $this->getLogoutError();
|
||||
|
||||
@@ -40,7 +40,7 @@ class Signature extends \Controller\AccessController{
|
||||
|
||||
if(!$system->dry()){
|
||||
// check access
|
||||
if( $system->hasAccess($activeCharacter->getUser()) ){
|
||||
if( $system->hasAccess($activeCharacter) ){
|
||||
$signatureData = $system->getSignaturesData();
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,6 @@ class Signature extends \Controller\AccessController{
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
|
||||
/**
|
||||
* @var Model\SystemModel $system
|
||||
@@ -95,9 +94,9 @@ class Signature extends \Controller\AccessController{
|
||||
$signature = null;
|
||||
if( isset($data['pk']) ){
|
||||
// try to get system by "primary key"
|
||||
$signature = $system->getSignatureById($user, (int)$data['pk']);
|
||||
$signature = $system->getSignatureById($activeCharacter, (int)$data['pk']);
|
||||
}elseif( isset($data['name']) ){
|
||||
$signature = $system->getSignatureByName($user, $data['name']);
|
||||
$signature = $system->getSignatureByName($activeCharacter, $data['name']);
|
||||
}
|
||||
|
||||
if( is_null($signature) ){
|
||||
@@ -186,7 +185,7 @@ class Signature extends \Controller\AccessController{
|
||||
$signature = Model\BasicModel::getNew('SystemSignatureModel');
|
||||
foreach($signatureIds as $signatureId){
|
||||
$signature->getById($signatureId);
|
||||
$signature->delete( $activeCharacter->getUser() );
|
||||
$signature->delete( $activeCharacter );
|
||||
$signature->reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,6 @@ class System extends \Controller\AccessController {
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
$systemData = (array)$postData['systemData'];
|
||||
$mapData = (array)$postData['mapData'];
|
||||
|
||||
@@ -205,7 +204,7 @@ class System extends \Controller\AccessController {
|
||||
$system = Model\BasicModel::getNew('SystemModel');
|
||||
$system->getById($systemData['id']);
|
||||
if( !$system->dry() ){
|
||||
if( $system->hasAccess($user) ){
|
||||
if( $system->hasAccess($activeCharacter) ){
|
||||
// system model found
|
||||
$systemModel = $system;
|
||||
}
|
||||
@@ -219,7 +218,7 @@ class System extends \Controller\AccessController {
|
||||
$map = Model\BasicModel::getNew('MapModel');
|
||||
$map->getById($mapData['id']);
|
||||
if( !$map->dry() ){
|
||||
if( $map->hasAccess($user) ){
|
||||
if( $map->hasAccess($activeCharacter) ){
|
||||
|
||||
$systemData['mapId'] = $map;
|
||||
|
||||
@@ -270,9 +269,9 @@ class System extends \Controller\AccessController {
|
||||
$systemLogModel = Model\BasicModel::getNew($ModelClass);
|
||||
|
||||
// 10min cache (could be up to 1h cache time)
|
||||
$systemLogModel->getByForeignKey('systemId', $systemId, array(), 60 * 10);
|
||||
$systemLogModel->getByForeignKey('systemId', $systemId, [], 60 * 10);
|
||||
|
||||
if(!$systemLogModel->dry()){
|
||||
if( !$systemLogModel->dry() ){
|
||||
$counter = 0;
|
||||
for( $i = $logEntryCount; $i >= 1; $i--){
|
||||
$column = 'value' . $i;
|
||||
@@ -340,17 +339,15 @@ class System extends \Controller\AccessController {
|
||||
*/
|
||||
public function delete(\Base $f3){
|
||||
$systemIds = $f3->get('POST.systemIds');
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
if($activeCharacter = $this->getCharacter()){
|
||||
/**
|
||||
* @var Model\SystemModel $system
|
||||
*/
|
||||
$system = Model\BasicModel::getNew('SystemModel');
|
||||
foreach((array)$systemIds as $systemId){
|
||||
$system->getById($systemId);
|
||||
$system->delete($user);
|
||||
$system->delete($activeCharacter);
|
||||
$system->reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ use DB;
|
||||
|
||||
class User extends Controller\Controller{
|
||||
|
||||
// captcha specific session keys
|
||||
const SESSION_CAPTCHA_ACCOUNT_UPDATE = 'SESSION.CAPTCHA.ACCOUNT.UPDATE';
|
||||
const SESSION_CAPTCHA_ACCOUNT_DELETE = 'SESSION.CAPTCHA.ACCOUNT.DELETE';
|
||||
|
||||
// user specific session keys
|
||||
const SESSION_KEY_USER = 'SESSION.USER';
|
||||
const SESSION_KEY_USER_ID = 'SESSION.USER.ID';
|
||||
@@ -36,7 +40,7 @@ class User extends Controller\Controller{
|
||||
* valid reasons for captcha images
|
||||
* @var string array
|
||||
*/
|
||||
private static $captchaReason = ['createAccount', 'deleteAccount'];
|
||||
private static $captchaReason = [self::SESSION_CAPTCHA_ACCOUNT_UPDATE, self::SESSION_CAPTCHA_ACCOUNT_DELETE];
|
||||
|
||||
/**
|
||||
* login a valid character
|
||||
@@ -106,7 +110,7 @@ class User extends Controller\Controller{
|
||||
'fonts/oxygen-bold-webfont.ttf',
|
||||
14,
|
||||
6,
|
||||
'SESSION.' . $reason,
|
||||
$reason,
|
||||
'',
|
||||
$colorText,
|
||||
$colorBG
|
||||
@@ -155,14 +159,12 @@ class User extends Controller\Controller{
|
||||
|
||||
$return = (object) [];
|
||||
|
||||
$privateSharing = 0;
|
||||
$corporationSharing = 0;
|
||||
$allianceSharing = 0;
|
||||
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
if($activeCharacter){
|
||||
$user = $activeCharacter->getUser();
|
||||
$privateSharing = 0;
|
||||
$corporationSharing = 0;
|
||||
$allianceSharing = 0;
|
||||
|
||||
// form values
|
||||
if(isset($data['formData'])){
|
||||
@@ -181,8 +183,8 @@ class User extends Controller\Controller{
|
||||
}
|
||||
}
|
||||
|
||||
$user->shared = $privateSharing;
|
||||
$user->save();
|
||||
$activeCharacter->shared = $privateSharing;
|
||||
$activeCharacter = $activeCharacter->save();
|
||||
|
||||
// update corp/ally ---------------------------------------------------------------
|
||||
$corporation = $activeCharacter->getCorporation();
|
||||
@@ -198,6 +200,7 @@ class User extends Controller\Controller{
|
||||
$alliance->save();
|
||||
}
|
||||
|
||||
$user = $activeCharacter->getUser();
|
||||
$return->userData = $user->getData();
|
||||
}
|
||||
|
||||
@@ -205,61 +208,9 @@ class User extends Controller\Controller{
|
||||
}
|
||||
|
||||
/**
|
||||
* search for a registration key model
|
||||
* e.g. for new user registration with "invite" feature enabled
|
||||
* @param $email
|
||||
* @param $registrationKey
|
||||
* @return bool|Model\RegistrationKeyModel
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getRegistrationKey($email, $registrationKey){
|
||||
$registrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
|
||||
$registrationKeyModel->load([
|
||||
'registrationKey = :registrationKey AND
|
||||
email = :email AND
|
||||
used = 0 AND
|
||||
active = 1',
|
||||
':registrationKey' => $registrationKey,
|
||||
':email' => $email
|
||||
]);
|
||||
|
||||
if( $registrationKeyModel->dry() ){
|
||||
return false;
|
||||
}else{
|
||||
return $registrationKeyModel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if there is already an active Key for a mail
|
||||
* @param $email
|
||||
* @param bool|false $used
|
||||
* @return bool|null
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function findRegistrationKey($email, $used = false){
|
||||
|
||||
$queryPart = 'email = :email AND active = 1';
|
||||
|
||||
if(is_int($used)){
|
||||
$queryPart .= ' AND used = ' . $used;
|
||||
}
|
||||
|
||||
$registrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
|
||||
$registrationKeyModels = $registrationKeyModel->find([
|
||||
$queryPart,
|
||||
':email' => $email
|
||||
]);
|
||||
|
||||
if( is_object($registrationKeyModels) ){
|
||||
return $registrationKeyModels;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* save/update user account data
|
||||
* update user account data
|
||||
* -> a fresh user automatically generated on first login with a new character
|
||||
* -> see CREST SSO login
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function saveAccount(\Base $f3){
|
||||
@@ -268,183 +219,100 @@ class User extends Controller\Controller{
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
|
||||
$captcha = $f3->get('SESSION.createAccount');
|
||||
$captcha = $f3->get(self::SESSION_CAPTCHA_ACCOUNT_UPDATE);
|
||||
|
||||
// reset captcha -> forces user to enter new one
|
||||
$f3->clear('SESSION.createAccount');
|
||||
$f3->clear(self::SESSION_CAPTCHA_ACCOUNT_UPDATE);
|
||||
|
||||
$newUserData = null;
|
||||
|
||||
// check for new user
|
||||
$loginAfterSave = false;
|
||||
|
||||
// valid registration key Model is required for new registration
|
||||
// if "invite" feature is enabled
|
||||
$registrationKeyModel = false;
|
||||
|
||||
if( isset($data['settingsData']) ){
|
||||
$settingsData = $data['settingsData'];
|
||||
if( isset($data['formData']) ){
|
||||
$formData = $data['formData'];
|
||||
|
||||
try{
|
||||
$activeCharacter = $this->getCharacter(0);
|
||||
$user = $activeCharacter->getUser();
|
||||
if($activeCharacter = $this->getCharacter(0)){
|
||||
$user = $activeCharacter->getUser();
|
||||
|
||||
// captcha is send -> check captcha
|
||||
if(
|
||||
isset($settingsData['captcha']) &&
|
||||
!empty($settingsData['captcha'])
|
||||
){
|
||||
|
||||
|
||||
if($settingsData['captcha'] === $captcha){
|
||||
// change/set sensitive user data requires captcha!
|
||||
|
||||
if(is_null($user)){
|
||||
|
||||
// check if registration key invite function is enabled
|
||||
if($f3->get('PATHFINDER.REGISTRATION.INVITE') === 1 ){
|
||||
$registrationKeyModel = $this->getRegistrationKey( $settingsData['email'], $settingsData['registrationKey'] );
|
||||
|
||||
if($registrationKeyModel === false){
|
||||
throw new Exception\RegistrationException('Registration key invalid', 'registrationKey');
|
||||
}
|
||||
}
|
||||
|
||||
// new user registration
|
||||
$user = Model\BasicModel::getNew('UserModel');
|
||||
$loginAfterSave = true;
|
||||
// captcha is send -> check captcha ---------------------------------
|
||||
if(
|
||||
isset($formData['captcha']) &&
|
||||
!empty($formData['captcha'])
|
||||
){
|
||||
if($formData['captcha'] === $captcha){
|
||||
// change/set sensitive user data requires captcha!
|
||||
|
||||
// set username
|
||||
if(
|
||||
isset($settingsData['name']) &&
|
||||
!empty($settingsData['name'])
|
||||
isset($formData['name']) &&
|
||||
!empty($formData['name'])
|
||||
){
|
||||
$user->name = $settingsData['name'];
|
||||
}
|
||||
}
|
||||
|
||||
// change/set email
|
||||
if(
|
||||
isset($settingsData['email']) &&
|
||||
isset($settingsData['email_confirm']) &&
|
||||
!empty($settingsData['email']) &&
|
||||
!empty($settingsData['email_confirm']) &&
|
||||
$settingsData['email'] == $settingsData['email_confirm']
|
||||
){
|
||||
$user->email = $settingsData['email'];
|
||||
}
|
||||
|
||||
// change/set password
|
||||
if(
|
||||
isset($settingsData['password']) &&
|
||||
isset($settingsData['password_confirm']) &&
|
||||
!empty($settingsData['password']) &&
|
||||
!empty($settingsData['password_confirm']) &&
|
||||
$settingsData['password'] == $settingsData['password_confirm']
|
||||
){
|
||||
$user->password = $settingsData['password'];
|
||||
}
|
||||
}else{
|
||||
// captcha was send but not valid -> return error
|
||||
$captchaError = (object) [];
|
||||
$captchaError->type = 'error';
|
||||
$captchaError->message = 'Captcha does not match';
|
||||
$return->error[] = $captchaError;
|
||||
}
|
||||
}
|
||||
|
||||
// saving additional user info requires valid user object (no captcha required)
|
||||
if($user){
|
||||
|
||||
// save API data
|
||||
if(
|
||||
isset($settingsData['keyId']) &&
|
||||
isset($settingsData['vCode']) &&
|
||||
is_array($settingsData['keyId']) &&
|
||||
is_array($settingsData['vCode'])
|
||||
){
|
||||
|
||||
// get all existing API models for this user
|
||||
$apiModels = $user->getAPIs();
|
||||
|
||||
foreach($settingsData['keyId'] as $i => $keyId){
|
||||
$api = null;
|
||||
|
||||
// search for existing API model
|
||||
foreach($apiModels as $key => $apiModel){
|
||||
if($apiModel->keyId == $keyId){
|
||||
$api = $apiModel;
|
||||
// make sure model is up2data -> cast()
|
||||
$api->cast();
|
||||
unset($apiModels[$key]);
|
||||
break;
|
||||
}
|
||||
$user->name = $formData['name'];
|
||||
}
|
||||
|
||||
if(is_null($api)){
|
||||
// new API Key
|
||||
$api = Model\BasicModel::getNew('UserApiModel');
|
||||
$api->userId = $user;
|
||||
// set email
|
||||
if(
|
||||
isset($formData['email']) &&
|
||||
isset($formData['email_confirm']) &&
|
||||
!empty($formData['email']) &&
|
||||
!empty($formData['email_confirm']) &&
|
||||
$formData['email'] == $formData['email_confirm']
|
||||
){
|
||||
$user->email = $formData['email'];
|
||||
}
|
||||
|
||||
$api->keyId = $keyId;
|
||||
$api->vCode = $settingsData['vCode'][$i];
|
||||
$api->save();
|
||||
// save/update user model
|
||||
// this will fail if model validation fails!
|
||||
$user->save();
|
||||
|
||||
$characterCount = $api->updateCharacters();
|
||||
}else{
|
||||
// captcha was send but not valid -> return error
|
||||
$captchaError = (object) [];
|
||||
$captchaError->type = 'error';
|
||||
$captchaError->message = 'Captcha does not match';
|
||||
$return->error[] = $captchaError;
|
||||
}
|
||||
}
|
||||
|
||||
if($characterCount == 0){
|
||||
// no characters found -> return warning
|
||||
$characterError = (object) [];
|
||||
$characterError->type = 'warning';
|
||||
$characterError->message = 'API verification failed. No Characters found for KeyId ' . $api->keyId;
|
||||
$return->error[] = $characterError;
|
||||
}
|
||||
// sharing config ---------------------------------------------------
|
||||
if(isset($formData['share'])){
|
||||
$privateSharing = 0;
|
||||
$corporationSharing = 0;
|
||||
$allianceSharing = 0;
|
||||
|
||||
if(isset($formData['privateSharing'])){
|
||||
$privateSharing = 1;
|
||||
}
|
||||
|
||||
// delete API models that no longer exists
|
||||
foreach($apiModels as $apiModel){
|
||||
$apiModel->delete();
|
||||
if(isset($formData['corporationSharing'])){
|
||||
$corporationSharing = 1;
|
||||
}
|
||||
|
||||
// get fresh updated user object (API info may have has changed)
|
||||
//$user = $this->_getUser(0);
|
||||
}
|
||||
if(isset($formData['allianceSharing'])){
|
||||
$allianceSharing = 1;
|
||||
}
|
||||
|
||||
// set main character
|
||||
if( isset($settingsData['mainCharacterId']) ){
|
||||
$user->setMainCharacterId((int)$settingsData['mainCharacterId']);
|
||||
}
|
||||
// update private/corp/ally
|
||||
$corporation = $activeCharacter->getCorporation();
|
||||
$alliance = $activeCharacter->getAlliance();
|
||||
|
||||
// check if the user already has a main character
|
||||
// if not -> save the next best character as main
|
||||
$mainUserCharacter = $user->getMainUserCharacter();
|
||||
if(is_object($corporation)){
|
||||
$corporation->shared = $corporationSharing;
|
||||
$corporation->save();
|
||||
}
|
||||
|
||||
// set main character if no main character exists
|
||||
if(is_null($mainUserCharacter)){
|
||||
$user->setMainCharacterId();
|
||||
}
|
||||
if(is_object($alliance)){
|
||||
$alliance->shared = $allianceSharing;
|
||||
$alliance->save();
|
||||
}
|
||||
|
||||
// save/update user model
|
||||
// this will fail if model validation fails!
|
||||
$user->save();
|
||||
|
||||
if(is_object($registrationKeyModel)){
|
||||
$registrationKeyModel->used = 1;
|
||||
$registrationKeyModel->save();
|
||||
}
|
||||
|
||||
// log user in (in case he is new
|
||||
if($loginAfterSave){
|
||||
$this->logInByData( $user->name, $settingsData['password'] );
|
||||
|
||||
// return reroute path
|
||||
$return->reroute = rtrim(self::getEnvironmentData('URL'), '/') . $this->f3->alias('map');
|
||||
$activeCharacter->shared = $privateSharing;
|
||||
$activeCharacter->save();
|
||||
}
|
||||
|
||||
// get fresh updated user object
|
||||
$newUserData = $user->getData();
|
||||
}
|
||||
|
||||
}catch(Exception\ValidationException $e){
|
||||
$validationError = (object) [];
|
||||
$validationError->type = 'error';
|
||||
@@ -461,109 +329,6 @@ class User extends Controller\Controller{
|
||||
|
||||
// return new/updated user data
|
||||
$return->userData = $newUserData;
|
||||
|
||||
}
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* send mail with registration key
|
||||
* -> check INVITE in pathfinder.ini
|
||||
* @param \Base $f3
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendInvite(\Base $f3){
|
||||
$data = $f3->get('POST.settingsData');
|
||||
$return = (object) [];
|
||||
|
||||
// check invite limit
|
||||
// get handed out key count
|
||||
$tempRegistrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
|
||||
$tempRegistrationKeyModels = $tempRegistrationKeyModel->find([ '
|
||||
email != "" AND
|
||||
active = 1'
|
||||
]);
|
||||
|
||||
$totalKeys = 0;
|
||||
if(is_object($tempRegistrationKeyModels)){
|
||||
$totalKeys = $tempRegistrationKeyModels->count();
|
||||
}
|
||||
|
||||
if(
|
||||
$f3->get('PATHFINDER.REGISTRATION.INVITE') == 1 &&
|
||||
$totalKeys < $f3->get('PATHFINDER.REGISTRATION.INVITE_LIMIT')
|
||||
){
|
||||
// key limit not reached
|
||||
|
||||
if(
|
||||
isset($data['email']) &&
|
||||
!empty($data['email'])
|
||||
){
|
||||
$email = trim($data['email']);
|
||||
|
||||
// check if mail is valid
|
||||
if( \Audit::instance()->email($email) ){
|
||||
|
||||
// new key for this mail is allowed
|
||||
$registrationKeyModel = $this->findRegistrationKey($email, 0);
|
||||
|
||||
if($registrationKeyModel === false){
|
||||
|
||||
// check for total number of invites (active and inactive) -> prevent spamming
|
||||
$allRegistrationKeysByMail = $this->findRegistrationKey($email);
|
||||
|
||||
if(
|
||||
$allRegistrationKeysByMail == false ||
|
||||
$allRegistrationKeysByMail->count() < 3
|
||||
){
|
||||
|
||||
// get a fresh key
|
||||
$registrationKeyModel = Model\BasicModel::getNew('RegistrationKeyModel');
|
||||
$registrationKeyModel->load(['
|
||||
used = 0 AND
|
||||
active = 1 AND
|
||||
email = "" ',
|
||||
':email' => $email
|
||||
], ['limit' => 1]);
|
||||
|
||||
}else{
|
||||
$validationError = (object) [];
|
||||
$validationError->type = 'warning';
|
||||
$validationError->message = 'The number of keys is limited by Email. You can not get more keys';
|
||||
$return->error[] = $validationError;
|
||||
}
|
||||
|
||||
}else{
|
||||
$registrationKeyModel = $registrationKeyModel[0];
|
||||
}
|
||||
|
||||
// send "old" key again or send a new key
|
||||
if( is_object($registrationKeyModel) ){
|
||||
$msg = 'Your personal Registration Key: ' . $registrationKeyModel->registrationKey;
|
||||
|
||||
$mailController = new MailController();
|
||||
$status = $mailController->sendInviteKey($email, $msg);
|
||||
|
||||
if( $status ){
|
||||
$registrationKeyModel->email = $email;
|
||||
$registrationKeyModel->ip = $this->f3->get('IP');
|
||||
$registrationKeyModel->save();
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
$validationError = (object) [];
|
||||
$validationError->type = 'error';
|
||||
$validationError->field = 'email';
|
||||
$validationError->message = 'Email is not valid';
|
||||
$return->error[] = $validationError;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$validationError = (object) [];
|
||||
$validationError->type = 'warning';
|
||||
$validationError->message = 'The pool of beta keys has been exhausted, please try again in a few days/weeks';
|
||||
$return->error[] = $validationError;
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
@@ -577,10 +342,10 @@ class User extends Controller\Controller{
|
||||
$data = $f3->get('POST.formData');
|
||||
$return = (object) [];
|
||||
|
||||
$captcha = $f3->get('SESSION.deleteAccount');
|
||||
$captcha = $f3->get(self::SESSION_CAPTCHA_ACCOUNT_DELETE);
|
||||
|
||||
// reset captcha -> forces user to enter new one
|
||||
$f3->clear('SESSION.deleteAccount');
|
||||
$f3->clear(self::SESSION_CAPTCHA_ACCOUNT_DELETE);
|
||||
|
||||
if(
|
||||
isset($data['captcha']) &&
|
||||
@@ -589,13 +354,8 @@ class User extends Controller\Controller{
|
||||
){
|
||||
$activeCharacter = $this->getCharacter(0);
|
||||
$user = $activeCharacter->getUser();
|
||||
$validUser = $this->_verifyUser( $user->name, $data['password']);
|
||||
|
||||
if(
|
||||
is_object($validUser) &&
|
||||
is_object($user) &&
|
||||
$user->id === $validUser->id
|
||||
){
|
||||
if($user){
|
||||
// send delete account mail
|
||||
$msg = 'Hello ' . $user->name . ',<br><br>';
|
||||
$msg .= 'your account data has been successfully deleted.';
|
||||
@@ -616,12 +376,6 @@ class User extends Controller\Controller{
|
||||
$this->logOut($f3);
|
||||
die();
|
||||
}
|
||||
}else{
|
||||
// password does not match current user pw
|
||||
$passwordError = (object) [];
|
||||
$passwordError->type = 'error';
|
||||
$passwordError->message = 'Invalid password';
|
||||
$return->error[] = $passwordError;
|
||||
}
|
||||
}else{
|
||||
// captcha not valid -> return error
|
||||
|
||||
@@ -19,7 +19,9 @@ class AppController extends Controller {
|
||||
parent::afterroute($f3);
|
||||
|
||||
// clear all SSO related temp data
|
||||
$f3->clear(Ccp\Sso::SESSION_KEY_SSO);
|
||||
if( $f3->exists(Ccp\Sso::SESSION_KEY_SSO) ){
|
||||
$f3->clear(Ccp\Sso::SESSION_KEY_SSO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,10 @@ class Sso extends Api\User{
|
||||
const SESSION_KEY_SSO = 'SESSION.SSO';
|
||||
const SESSION_KEY_SSO_ERROR = 'SESSION.SSO.ERROR';
|
||||
const SESSION_KEY_SSO_STATE = 'SESSION.SSO.STATE';
|
||||
const SESSION_KEY_SSO_CHARACTER_ID = 'SESSION.SSO.CHARACTER.ID';
|
||||
|
||||
// cache keys
|
||||
const CACHE_KEY_LOCATION_DATA = 'CACHED.LOCATION.%s';
|
||||
|
||||
// error messages
|
||||
const ERROR_CCP_SSO_URL = 'Invalid "ENVIRONMENT.[ENVIRONMENT].SSO_CCP_URL" url. %s';
|
||||
@@ -44,6 +48,9 @@ class Sso extends Api\User{
|
||||
const ERROR_GET_ENDPOINT = 'Unable to get endpoint data. $s';
|
||||
const ERROR_FIND_ENDPOINT = 'Unable to find endpoint: %s';
|
||||
const ERROR_LOGIN_FAILED = 'Failed authentication due to technical problems: %s';
|
||||
const ERROR_CHARACTER_FORBIDDEN = 'Character "%s" is not authorized to log in';
|
||||
const ERROR_CHARACTER_MISMATCH = 'The character "%s" you tried to log in, does not match';
|
||||
const ERROR_SERVICE_TIMEOUT = 'CCP SSO service timeout (%ss). Try again later';
|
||||
|
||||
/**
|
||||
* CREST "Scopes" are used by pathfinder
|
||||
@@ -62,6 +69,12 @@ class Sso extends Api\User{
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function requestAuthorization($f3){
|
||||
$params = $f3->get('GET');
|
||||
|
||||
if(isset($params['characterId'])){
|
||||
// restrict login to this characterId e.g. for character switch
|
||||
$f3->set(self::SESSION_KEY_SSO_CHARACTER_ID, (int)trim($params['characterId']) );
|
||||
}
|
||||
|
||||
// used for "state" check between request and callback
|
||||
$state = bin2hex(mcrypt_create_iv(12, MCRYPT_DEV_URANDOM));
|
||||
@@ -89,6 +102,10 @@ class Sso extends Api\User{
|
||||
public function callbackAuthorization($f3){
|
||||
$getParams = (array)$f3->get('GET');
|
||||
|
||||
// users can log in either from @login (new user) or @map (existing user) root alias
|
||||
// -> in case login fails, users should be redirected differently
|
||||
$authFromMapAlias = false;
|
||||
|
||||
if($f3->exists(self::SESSION_KEY_SSO_STATE)){
|
||||
// check response and validate 'state'
|
||||
if(
|
||||
@@ -98,8 +115,15 @@ class Sso extends Api\User{
|
||||
!empty($getParams['state']) &&
|
||||
$f3->get(self::SESSION_KEY_SSO_STATE) === $getParams['state']
|
||||
){
|
||||
// clear 'state' for new next request
|
||||
// $requestedCharacterId can be [-1 => add char, 0 => new user, >0 => specific user]
|
||||
$requiredCharacterId = (int)$f3->get(self::SESSION_KEY_SSO_CHARACTER_ID);
|
||||
if($requiredCharacterId !== 0){
|
||||
$authFromMapAlias = true;
|
||||
}
|
||||
|
||||
// clear 'state' for new next login request
|
||||
$f3->clear(self::SESSION_KEY_SSO_STATE);
|
||||
$f3->clear(self::SESSION_KEY_SSO_CHARACTER_ID);
|
||||
|
||||
$accessData = $this->getCrestAccessData($getParams['code']);
|
||||
|
||||
@@ -111,74 +135,91 @@ class Sso extends Api\User{
|
||||
$verificationCharacterData = $this->verifyCharacterData($accessData->accessToken);
|
||||
|
||||
if( !is_null($verificationCharacterData)){
|
||||
// verification data available. Data is needed for "ownerHash" check
|
||||
|
||||
// get character data from CREST
|
||||
$characterData = $this->getCharacterData($accessData->accessToken);
|
||||
// check if login is restricted to a characterID
|
||||
if(
|
||||
$requiredCharacterId <= 0 ||
|
||||
$verificationCharacterData->CharacterID === $requiredCharacterId
|
||||
){
|
||||
// verification available data. Data is needed for "ownerHash" check
|
||||
|
||||
if(isset($characterData->character)){
|
||||
// add "ownerHash" and CREST tokens
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
$characterData->character['crestAccessToken'] = $accessData->accessToken;
|
||||
$characterData->character['crestRefreshToken'] = $accessData->refreshToken;
|
||||
// get character data from CREST
|
||||
$characterData = $this->getCharacterData($accessData->accessToken);
|
||||
|
||||
// add/update static character data
|
||||
$characterModel = $this->updateCharacter($characterData);
|
||||
if(isset($characterData->character)){
|
||||
// add "ownerHash" and CREST tokens
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
$characterData->character['crestAccessToken'] = $accessData->accessToken;
|
||||
$characterData->character['crestRefreshToken'] = $accessData->refreshToken;
|
||||
|
||||
if( !is_null($characterModel) ){
|
||||
// check if character is authorized to log in
|
||||
if($characterModel->isAuthorized()){
|
||||
// add/update static character data
|
||||
$characterModel = $this->updateCharacter($characterData);
|
||||
|
||||
// character is authorized to log in
|
||||
// -> update character log (current location,...)
|
||||
$characterModel = $characterModel->updateLog();
|
||||
if( !is_null($characterModel) ){
|
||||
// check if character is authorized to log in
|
||||
if($characterModel->isAuthorized()){
|
||||
|
||||
// check if there is already a user created who owns this char
|
||||
$user = $characterModel->getUser();
|
||||
// character is authorized to log in
|
||||
// -> update character log (current location,...)
|
||||
$characterModel = $characterModel->updateLog();
|
||||
|
||||
if(is_null($user)){
|
||||
// no user found -> create one and connect to character
|
||||
/**
|
||||
* @var Model\UserModel $user
|
||||
*/
|
||||
$user = Model\BasicModel::getNew('UserModel');
|
||||
$user->name = $characterModel->name;
|
||||
$user->save();
|
||||
// check if there is already an active user logged in
|
||||
if($activeCharacter = $this->getCharacter()){
|
||||
// connect character with current user
|
||||
$user = $activeCharacter->getUser();
|
||||
}elseif( is_null( $user = $characterModel->getUser()) ){
|
||||
// no user found (new character) -> create new user and connect to character
|
||||
$user = Model\BasicModel::getNew('UserModel');
|
||||
$user->name = $characterModel->name;
|
||||
$user->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Model\UserCharacterModel $userCharactersModel
|
||||
*/
|
||||
$userCharactersModel = Model\BasicModel::getNew('UserCharacterModel');
|
||||
if( is_null($userCharactersModel = $characterModel->userCharacter) ){
|
||||
$userCharactersModel = Model\BasicModel::getNew('UserCharacterModel');
|
||||
$userCharactersModel->characterId = $characterModel;
|
||||
}
|
||||
|
||||
// user might have changed
|
||||
$userCharactersModel->userId = $user;
|
||||
$userCharactersModel->characterId = $characterModel;
|
||||
$userCharactersModel->save();
|
||||
|
||||
// get updated character model
|
||||
$characterModel = $userCharactersModel->getCharacter();
|
||||
}
|
||||
|
||||
// login by character
|
||||
$loginCheck = $this->loginByCharacter($characterModel);
|
||||
// login by character
|
||||
$loginCheck = $this->loginByCharacter($characterModel);
|
||||
|
||||
if($loginCheck){
|
||||
// route to "map"
|
||||
$f3->reroute('@map');
|
||||
if($loginCheck){
|
||||
// route to "map"
|
||||
$f3->reroute('@map');
|
||||
}else{
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_LOGIN_FAILED, $characterModel->name));
|
||||
}
|
||||
}else{
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_LOGIN_FAILED, $characterModel->name));
|
||||
// character is not authorized to log in
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_CHARACTER_FORBIDDEN, $characterModel->name));
|
||||
}
|
||||
}else{
|
||||
// character is not authorized to log in
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, 'Character "' . $characterModel->name . '" is not authorized to log in.');
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// characterID is not allowed to login
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_CHARACTER_MISMATCH, $verificationCharacterData->CharacterName));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// CREST "accessData" missing (e.g. timeout)
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_SERVICE_TIMEOUT, self::CREST_TIMEOUT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// on error -> route back to login form
|
||||
$f3->reroute('@login');
|
||||
if($authFromMapAlias){
|
||||
// on error -> route back to map
|
||||
$f3->reroute('@map');
|
||||
}else{
|
||||
// on error -> route back to login form
|
||||
$f3->reroute('@login');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,16 +307,18 @@ class Sso extends Api\User{
|
||||
$apiResponse = Lib\Web::instance()->request($verifyAuthCodeUrl, $requestOptions);
|
||||
|
||||
if($apiResponse['body']){
|
||||
$authCodeRequestData = json_decode($apiResponse['body']);
|
||||
$authCodeRequestData = json_decode($apiResponse['body'], true);
|
||||
|
||||
if(isset($authCodeRequestData->access_token)){
|
||||
// this token is required for endpoints that require Auth
|
||||
$accessData->accessToken = $authCodeRequestData->access_token;
|
||||
}
|
||||
if( !empty($authCodeRequestData) ){
|
||||
if( isset($authCodeRequestData['access_token']) ){
|
||||
// this token is required for endpoints that require Auth
|
||||
$accessData->accessToken = $authCodeRequestData['access_token'];
|
||||
}
|
||||
|
||||
if(isset($authCodeRequestData->refresh_token)){
|
||||
// this token is used to refresh/get a new access_token when expires
|
||||
$accessData->refreshToken = $authCodeRequestData->refresh_token;
|
||||
if(isset($authCodeRequestData['refresh_token'])){
|
||||
// this token is used to refresh/get a new access_token when expires
|
||||
$accessData->refreshToken = $authCodeRequestData['refresh_token'];
|
||||
}
|
||||
}
|
||||
}else{
|
||||
self::getCrestLogger()->write(
|
||||
@@ -450,25 +493,37 @@ class Sso extends Api\User{
|
||||
}
|
||||
|
||||
/**
|
||||
* get current character location data
|
||||
* get current character location data (result is cached!)
|
||||
* -> solarSystem data where character is currently active
|
||||
* @param $accessToken
|
||||
* @return object
|
||||
* @param int $ttl
|
||||
* @return array
|
||||
*/
|
||||
public function getCharacterLocationData($accessToken){
|
||||
$endpoints = $this->getEndpoints($accessToken);
|
||||
$locationData = (object) [];
|
||||
public function getCharacterLocationData($accessToken, $ttl = 10){
|
||||
$locationData = [];
|
||||
|
||||
$endpoint = $this->walkEndpoint($accessToken, $endpoints, [
|
||||
'decode',
|
||||
'character',
|
||||
'location'
|
||||
]);
|
||||
// in addition to the cURL caching (based on cache-control headers,
|
||||
// the final location data is cached additionally -> speed up
|
||||
$cacheKey = sprintf(self::CACHE_KEY_LOCATION_DATA, 'TOKEN_' . hash('md5', $accessToken));
|
||||
|
||||
if( !empty($endpoint) ){
|
||||
if(isset($endpoint['solarSystem'])){
|
||||
$locationData->system = (new Mapper\CrestSystem($endpoint['solarSystem']))->getData();
|
||||
if( !$this->getF3()->exists($cacheKey) ){
|
||||
$endpoints = $this->getEndpoints($accessToken);
|
||||
|
||||
$endpoint = $this->walkEndpoint($accessToken, $endpoints, [
|
||||
'decode',
|
||||
'character',
|
||||
'location'
|
||||
]);
|
||||
|
||||
if( !empty($endpoint) ){
|
||||
if(isset($endpoint['solarSystem'])){
|
||||
$locationData['system'] = (new Mapper\CrestSystem($endpoint['solarSystem']))->getData();
|
||||
}
|
||||
}
|
||||
|
||||
$this->getF3()->set($cacheKey, $locationData, $ttl);
|
||||
}else{
|
||||
$locationData = $this->getF3()->get($cacheKey);
|
||||
}
|
||||
|
||||
return $locationData;
|
||||
|
||||
@@ -120,7 +120,7 @@ class Controller {
|
||||
* @return Model\CharacterModel|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getCharacter($ttl = 5){
|
||||
public function getCharacter($ttl = 0){
|
||||
$character = null;
|
||||
|
||||
if( $this->getF3()->exists(Api\User::SESSION_KEY_CHARACTER_ID) ){
|
||||
@@ -170,33 +170,6 @@ class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* verifies weather a given username and password is valid
|
||||
* @param string $userName
|
||||
* @param string $password
|
||||
* @return Model\UserModel|null
|
||||
*/
|
||||
protected function _verifyUser($userName, $password) {
|
||||
$validUser = null;
|
||||
|
||||
/**
|
||||
* @var $user \Model\UserModel
|
||||
*/
|
||||
$user = Model\BasicModel::getNew('UserModel', 0);
|
||||
$user->getByName($userName);
|
||||
|
||||
// check userName is valid
|
||||
if( !$user->dry() ){
|
||||
// check if password is valid
|
||||
$isValid = $user->verify($password);
|
||||
if($isValid === true){
|
||||
$validUser = $user;
|
||||
}
|
||||
}
|
||||
|
||||
return $validUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* check weather the page is IGB trusted or not
|
||||
* @return boolean
|
||||
|
||||
@@ -30,17 +30,14 @@ class Setup extends Controller {
|
||||
'Model\SystemStatusModel',
|
||||
'Model\SystemNeighbourModel',
|
||||
'Model\WormholeModel',
|
||||
'Model\RegistrationKeyModel',
|
||||
|
||||
'Model\CharacterStatusModel',
|
||||
'Model\ConnectionScopeModel',
|
||||
|
||||
'Model\UserMapModel',
|
||||
'Model\CharacterMapModel',
|
||||
'Model\AllianceMapModel',
|
||||
'Model\CorporationMapModel',
|
||||
|
||||
'Model\UserApiModel',
|
||||
'Model\UserCharacterModel',
|
||||
'Model\CharacterModel',
|
||||
'Model\CharacterLogModel',
|
||||
|
||||
@@ -47,43 +47,48 @@ class AbstractIterator extends \RecursiveArrayIterator {
|
||||
*/
|
||||
static function recursiveIterator($iterator){
|
||||
|
||||
$keyWhitelist = array_keys(static::$map);
|
||||
|
||||
while($iterator->valid()){
|
||||
|
||||
if(array_key_exists($iterator->key(), static::$map)){
|
||||
if( isset(static::$map[$iterator->key()]) ){
|
||||
$mapValue = static::$map[$iterator->key()];
|
||||
|
||||
// check for mapping key
|
||||
if($iterator->hasChildren()){
|
||||
|
||||
// recursive call for child elements
|
||||
$iterator->offsetSet($iterator->key(), forward_static_call(array('self', __METHOD__), $iterator->getChildren())->getArrayCopy());
|
||||
$iterator->next();
|
||||
}elseif(is_array(static::$map[$iterator->key()])){
|
||||
}elseif(is_array($mapValue)){
|
||||
// a -> array mapping
|
||||
$parentKey = array_keys(static::$map[$iterator->key()])[0];
|
||||
$entryKey = array_values(static::$map[$iterator->key()])[0];
|
||||
$parentKey = array_keys($mapValue)[0];
|
||||
$entryKey = array_values($mapValue)[0];
|
||||
|
||||
// check if key already exists
|
||||
if($iterator->offsetExists($parentKey)){
|
||||
$currentValue = $iterator->offsetGet($parentKey);
|
||||
// add new array entry
|
||||
$currentValue[$entryKey] = $iterator->current();
|
||||
|
||||
$iterator->offsetSet($parentKey, $currentValue);
|
||||
}else{
|
||||
$iterator->offsetSet($parentKey, [$entryKey => $iterator->current()]);
|
||||
$keyWhitelist[] = $parentKey;
|
||||
}
|
||||
|
||||
|
||||
}elseif(is_object(static::$map[$iterator->key()])){
|
||||
$iterator->offsetUnset($iterator->key());
|
||||
}elseif(is_object($mapValue)){
|
||||
// a -> a (format by function)
|
||||
$formatFunction = static::$map[$iterator->key()];
|
||||
$formatFunction = $mapValue;
|
||||
$iterator->offsetSet($iterator->key(), call_user_func($formatFunction, $iterator));
|
||||
|
||||
// just value change no key change
|
||||
$iterator->next();
|
||||
}elseif(static::$map[$iterator->key()] !== $iterator->key()){
|
||||
}elseif($mapValue !== $iterator->key()){
|
||||
// a -> b mapping (key changed)
|
||||
$iterator->offsetSet(static::$map[$iterator->key()], $iterator->current());
|
||||
$iterator->offsetSet($mapValue, $iterator->current());
|
||||
$iterator->offsetUnset($iterator->key());
|
||||
$keyWhitelist[] = $mapValue;
|
||||
}else{
|
||||
// a -> a (no changes)
|
||||
$iterator->next();
|
||||
@@ -91,13 +96,13 @@ class AbstractIterator extends \RecursiveArrayIterator {
|
||||
|
||||
}elseif(
|
||||
static::$removeUnmapped &&
|
||||
!in_array($iterator->key(), static::$map)
|
||||
|
||||
!in_array($iterator->key(), $keyWhitelist)
|
||||
){
|
||||
$iterator->offsetUnset($iterator->key());
|
||||
}else{
|
||||
$iterator->next();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $iterator;
|
||||
|
||||
@@ -166,7 +166,7 @@ class CcpSystemsMapper extends AbstractIterator {
|
||||
|
||||
// just value change no key change
|
||||
$removeOldEntry = false;
|
||||
$iterator -> next();
|
||||
$iterator->next();
|
||||
}else{
|
||||
// a -> b mapping
|
||||
$iterator->offsetSet( self::$map[$iterator->key()], $iterator->current() );
|
||||
|
||||
47
app/main/data/mapper/igbheader.php
Normal file
47
app/main/data/mapper/igbheader.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 01.04.2016
|
||||
* Time: 19:48
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class IgbHeader extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'charid' => ['character' => 'id'],
|
||||
'charname' => ['character' => 'name'],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
'solarsystemid' => ['system' => 'id'],
|
||||
'solarsystemname' => ['system' => 'name'],
|
||||
|
||||
'constellationid' => ['constellation' => 'id'],
|
||||
'constellationname' => ['constellation' => 'name'],
|
||||
|
||||
'regionid' => ['region' => 'id'],
|
||||
'regionname' => ['region' => 'name'],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
'shiptypeid' => ['ship' => 'typeId'],
|
||||
'shiptypename' => ['ship' => 'typeName'],
|
||||
'shipid' => ['ship' => 'id'],
|
||||
'shipname' => ['ship' => 'name'],
|
||||
|
||||
'stationid' => ['station' => 'id'],
|
||||
'stationname' => ['station' => 'name'],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
'corpid' => ['corporation' => 'id'],
|
||||
'corpname' => ['corporation' => 'name'],
|
||||
|
||||
'allianceid' => ['alliance' => 'id'],
|
||||
'alliancename' => ['alliance' => 'name']
|
||||
];
|
||||
}
|
||||
@@ -8,8 +8,15 @@
|
||||
|
||||
namespace Lib;
|
||||
|
||||
use controller\LogController;
|
||||
|
||||
class Web extends \Web {
|
||||
|
||||
const ERROR_DEFAULT_MSG = 'method: \'%s\', url: \'%s\'';
|
||||
const ERROR_STATUS_UNKNOWN = 'HTTP response - unknown HTTP status: \'%s\'. url: \'%s\'';
|
||||
const ERROR_TIMEOUT = 'Request timeout \'%ss\'. url: \'%s\'';
|
||||
|
||||
|
||||
/**
|
||||
* end of line
|
||||
* @var string
|
||||
@@ -79,7 +86,7 @@ class Web extends \Web {
|
||||
$options['method'] . ' '
|
||||
. $url . ' '
|
||||
. $headers
|
||||
).'.url';
|
||||
) . 'url';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,11 +103,42 @@ class Web extends \Web {
|
||||
$result = parent::request($url, $options);
|
||||
$statusCode = $this->getStatuscodeFromHeaders( $result['headers'] );
|
||||
|
||||
if($statusCode == 200){
|
||||
// request succeeded -> check if response should be cached
|
||||
if( $ttl = $this->getCacheTimeFromHeaders( $result['headers'] ) ){
|
||||
$f3->set($hash, $result, $ttl);
|
||||
}
|
||||
switch($statusCode){
|
||||
case 200:
|
||||
// request succeeded -> check if response should be cached
|
||||
$ttl = $this->getCacheTimeFromHeaders( $result['headers'] );
|
||||
|
||||
if(
|
||||
$ttl > 0 &&
|
||||
!empty( json_decode( $result['body'], true ) )
|
||||
){
|
||||
$f3->set($hash, $result, $ttl);
|
||||
}
|
||||
break;
|
||||
case 500:
|
||||
case 501:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
case 505:
|
||||
$f3->error($statusCode, $this->getErrorMessageFromJsonResponse(
|
||||
$options['method'],
|
||||
$url,
|
||||
json_decode($result['body'])
|
||||
));
|
||||
break;
|
||||
case 0:
|
||||
// timeout
|
||||
LogController::getLogger('error')->write(
|
||||
sprintf(self::ERROR_TIMEOUT, $options['timeout'], $url)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
// unknown status
|
||||
LogController::getLogger('error')->write(
|
||||
sprintf(self::ERROR_STATUS_UNKNOWN, $statusCode, $url)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
$result = $f3->get($hash);
|
||||
@@ -109,4 +147,21 @@ class Web extends \Web {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get error message from response object
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param \stdClass $responseBody
|
||||
* @return string
|
||||
*/
|
||||
protected function getErrorMessageFromJsonResponse($method, $url, $responseBody){
|
||||
if( empty($responseBody->message) ){
|
||||
$message = sprintf(self::ERROR_DEFAULT_MSG, $method, $url);
|
||||
}else{
|
||||
$message = $responseBody->message . ', url: \'' . $url . '\'';
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -108,18 +108,27 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return;
|
||||
}
|
||||
|
||||
if($key != 'updated'){
|
||||
if(
|
||||
!$this->dry() &&
|
||||
$key != 'updated'
|
||||
){
|
||||
if( $this->exists($key) ){
|
||||
$currentVal = $this->get($key);
|
||||
|
||||
// if current value is not a relational object
|
||||
// and value has changed -> update table col
|
||||
if(
|
||||
!is_object($currentVal) &&
|
||||
$currentVal != $val
|
||||
){
|
||||
if(is_object($currentVal)){
|
||||
if(
|
||||
is_numeric($val) &&
|
||||
is_subclass_of($currentVal, 'Model\BasicModel') &&
|
||||
$currentVal->_id !== (int)$val
|
||||
){
|
||||
$this->touch('updated');
|
||||
}
|
||||
}elseif($currentVal != $val){
|
||||
$this->touch('updated');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +256,67 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return $cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* get cached data from this model
|
||||
* @param string $dataCacheKeyPrefix - optional key prefix
|
||||
* @return \stdClass|null
|
||||
*/
|
||||
protected function getCacheData($dataCacheKeyPrefix = ''){
|
||||
|
||||
$cacheKey = $this->getCacheKey($dataCacheKeyPrefix);
|
||||
$cacheData = null;
|
||||
|
||||
if( !is_null($cacheKey) ){
|
||||
$f3 = self::getF3();
|
||||
|
||||
if( $f3->exists($cacheKey) ){
|
||||
$cacheData = $f3->get( $cacheKey );
|
||||
}
|
||||
}
|
||||
|
||||
return $cacheData;
|
||||
}
|
||||
|
||||
/**
|
||||
* update/set the getData() cache for this object
|
||||
* @param $cacheData
|
||||
* @param string $dataCacheKeyPrefix
|
||||
* @param int $data_ttl
|
||||
*/
|
||||
public function updateCacheData($cacheData, $dataCacheKeyPrefix = '', $data_ttl = 300){
|
||||
|
||||
$cacheDataTmp = (array)$cacheData;
|
||||
|
||||
// check if data should be cached
|
||||
// and cacheData is not empty
|
||||
if(
|
||||
$data_ttl > 0 &&
|
||||
!empty( $cacheDataTmp )
|
||||
){
|
||||
$cacheKey = $this->getCacheKey($dataCacheKeyPrefix);
|
||||
|
||||
if( !is_null($cacheKey) ){
|
||||
self::getF3()->set($cacheKey, $cacheData, $data_ttl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unset the getData() cache for this object
|
||||
*/
|
||||
public function clearCacheData(){
|
||||
$cacheKey = $this->getCacheKey();
|
||||
|
||||
if( !is_null($cacheKey) ){
|
||||
$f3 = self::getF3();
|
||||
|
||||
if( $f3->exists($cacheKey) ){
|
||||
$f3->clear($cacheKey);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a validation error for a giben column
|
||||
* @param $col
|
||||
@@ -350,10 +420,10 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
|
||||
/**
|
||||
* function should be overwritten in child classes with access restriction
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAccess(UserModel $user){
|
||||
public function hasAccess(CharacterModel $characterModel){
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -365,113 +435,6 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get cached data from this model
|
||||
* @param string $dataCacheKeyPrefix - optional key prefix
|
||||
* @return \stdClass|null
|
||||
*/
|
||||
protected function getCacheData($dataCacheKeyPrefix = ''){
|
||||
|
||||
$cacheKey = $this->getCacheKey($dataCacheKeyPrefix);
|
||||
$cacheData = null;
|
||||
|
||||
if( !is_null($cacheKey) ){
|
||||
$f3 = self::getF3();
|
||||
|
||||
if( $f3->exists($cacheKey) ){
|
||||
$cacheData = $f3->get( $cacheKey );
|
||||
}
|
||||
}
|
||||
|
||||
return $cacheData;
|
||||
}
|
||||
|
||||
/**
|
||||
* update/set the getData() cache for this object
|
||||
* @param $cacheData
|
||||
* @param string $dataCacheKeyPrefix
|
||||
* @param int $data_ttl
|
||||
*/
|
||||
public function updateCacheData($cacheData, $dataCacheKeyPrefix = '', $data_ttl = 300){
|
||||
|
||||
$cacheDataTmp = (array)$cacheData;
|
||||
|
||||
// check if data should be cached
|
||||
// and cacheData is not empty
|
||||
if(
|
||||
$data_ttl > 0 &&
|
||||
!empty( $cacheDataTmp )
|
||||
){
|
||||
$cacheKey = $this->getCacheKey($dataCacheKeyPrefix);
|
||||
|
||||
if( !is_null($cacheKey) ){
|
||||
self::getF3()->set($cacheKey, $cacheData, $data_ttl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unset the getData() cache for this object
|
||||
*/
|
||||
public function clearCacheData(){
|
||||
$cacheKey = $this->getCacheKey();
|
||||
|
||||
if( !is_null($cacheKey) ){
|
||||
$f3 = self::getF3();
|
||||
|
||||
if( $f3->exists($cacheKey) ){
|
||||
$f3->clear($cacheKey);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current class name
|
||||
* -> namespace not included
|
||||
* @return string
|
||||
*/
|
||||
public static function getClassName(){
|
||||
$parts = explode('\\', static::class);
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* factory for all Models
|
||||
* @param string $model
|
||||
* @param int $ttl
|
||||
* @return BasicModel
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getNew($model, $ttl = 86400){
|
||||
$class = null;
|
||||
|
||||
$model = '\\' . __NAMESPACE__ . '\\' . $model;
|
||||
if(class_exists($model)){
|
||||
$class = new $model( null, null, null, $ttl );
|
||||
}else{
|
||||
throw new \Exception('No model class found');
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the framework instance (singleton)
|
||||
* @return \Base
|
||||
*/
|
||||
public static function getF3(){
|
||||
return \Base::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* debug log function
|
||||
* @param string $text
|
||||
*/
|
||||
public static function log($text){
|
||||
Controller\LogController::getLogger('debug')->write($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* export and download table data as *.csv
|
||||
* this is primarily used for static tables
|
||||
@@ -584,6 +547,52 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return ['added' => $addedCount, 'updated' => $updatedCount, 'deleted' => $deletedCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current class name
|
||||
* -> namespace not included
|
||||
* @return string
|
||||
*/
|
||||
public static function getClassName(){
|
||||
$parts = explode('\\', static::class);
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* factory for all Models
|
||||
* @param string $model
|
||||
* @param int $ttl
|
||||
* @return BasicModel
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getNew($model, $ttl = 86400){
|
||||
$class = null;
|
||||
|
||||
$model = '\\' . __NAMESPACE__ . '\\' . $model;
|
||||
if(class_exists($model)){
|
||||
$class = new $model( null, null, null, $ttl );
|
||||
}else{
|
||||
throw new \Exception('No model class found');
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the framework instance (singleton)
|
||||
* @return \Base
|
||||
*/
|
||||
public static function getF3(){
|
||||
return \Base::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* debug log function
|
||||
* @param string $text
|
||||
*/
|
||||
public static function log($text){
|
||||
Controller\LogController::getLogger('debug')->write($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* get tableModifier class for this table
|
||||
* @return bool|DB\SQL\TableModifier
|
||||
|
||||
@@ -41,6 +41,9 @@ class CharacterLogModel extends BasicModel {
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
@@ -50,6 +53,35 @@ class CharacterLogModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'constellationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'constellationName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'regionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'regionName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
'shipTypeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'shipTypeName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'shipId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
@@ -59,32 +91,69 @@ class CharacterLogModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'shipTypeName' => [
|
||||
'stationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'stationName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
]
|
||||
];
|
||||
|
||||
public function __construct($db = NULL, $table = NULL, $fluid = NULL, $ttl = 0){
|
||||
|
||||
parent::__construct($db, $table, $fluid, $ttl);
|
||||
|
||||
// events -----------------------------------------
|
||||
$this->beforeerase(function($self){
|
||||
$self->clearCacheData();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* set log data from object
|
||||
* @param object $logData
|
||||
* set log data from array
|
||||
* @param array $logData
|
||||
*/
|
||||
public function setData($logData){
|
||||
if( !empty($logData->system) ){
|
||||
$this->systemId = $logData->system['id'];
|
||||
$this->systemName = $logData->system['name'];
|
||||
|
||||
if( isset($logData['system']) ){
|
||||
$this->systemId = (int)$logData['system']['id'];
|
||||
$this->systemName = $logData['system']['name'];
|
||||
}else{
|
||||
$this->systemId = null;
|
||||
$this->systemName = '';
|
||||
}
|
||||
|
||||
if( isset($logData['constellation']) ){
|
||||
$this->constellationId = (int)$logData['constellation']['id'];
|
||||
$this->constellationName = $logData['constellation']['name'];
|
||||
}else{
|
||||
$this->constellationId = null;
|
||||
$this->constellationName = '';
|
||||
}
|
||||
|
||||
if( isset($logData['region']) ){
|
||||
$this->regionId = (int)$logData['region']['id'];
|
||||
$this->regionName = $logData['region']['name'];
|
||||
}else{
|
||||
$this->regionId = null;
|
||||
$this->regionName = '';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
if( isset($logData['ship']) ){
|
||||
$this->shipTypeId = (int)$logData['ship']['typeId'];
|
||||
$this->shipTypeName = $logData['ship']['typeName'];
|
||||
$this->shipId = (int)$logData['ship']['id'];
|
||||
$this->shipName = $logData['ship']['name'];
|
||||
}else{
|
||||
$this->shipTypeId = null;
|
||||
$this->shipTypeName = '';
|
||||
$this->shipId = null;
|
||||
$this->shipName = '';
|
||||
}
|
||||
|
||||
if( isset($logData['station']) ){
|
||||
$this->stationId = (int)$logData['station']['id'];
|
||||
$this->stationName = $logData['station']['name'];
|
||||
}else{
|
||||
$this->stationId = null;
|
||||
$this->stationName = '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,30 +164,30 @@ class CharacterLogModel extends BasicModel {
|
||||
|
||||
$logData = (object) [];
|
||||
$logData->system = (object) [];
|
||||
$logData->system->id = $this->systemId;
|
||||
$logData->system->id = (int)$this->systemId;
|
||||
$logData->system->name = $this->systemName;
|
||||
|
||||
$logData->constellation = (object) [];
|
||||
$logData->constellation->id = (int)$this->constellationId;
|
||||
$logData->constellation->name = $this->constellationName;
|
||||
|
||||
$logData->region = (object) [];
|
||||
$logData->region->id = (int)$this->regionId;
|
||||
$logData->region->name = $this->regionName;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
$logData->ship = (object) [];
|
||||
$logData->ship->typeId = (int)$this->shipTypeId;
|
||||
$logData->ship->typeName = $this->shipTypeName;
|
||||
$logData->ship->id = $this->shipId;
|
||||
$logData->ship->name = $this->shipName;
|
||||
$logData->ship->typeName = $this->shipTypeName;
|
||||
|
||||
$logData->station = (object) [];
|
||||
$logData->station->id = (int)$this->stationId;
|
||||
$logData->station->name = $this->stationName;
|
||||
|
||||
return $logData;
|
||||
}
|
||||
|
||||
/**
|
||||
* see parent
|
||||
*/
|
||||
public function clearCacheData(){
|
||||
parent::clearCacheData();
|
||||
|
||||
// delete log cache key as well
|
||||
$f3 = self::getF3();
|
||||
$character = $this->characterId;
|
||||
|
||||
$character->clearCacheData();
|
||||
$f3->clear('LOGGED.user.character.id_' . $character->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
|
||||
namespace Model;
|
||||
|
||||
use Controller;
|
||||
use Controller\Ccp;
|
||||
use DB\SQL\Schema;
|
||||
use Data\Mapper as Mapper;
|
||||
|
||||
class CharacterModel extends BasicModel {
|
||||
|
||||
@@ -78,11 +80,19 @@ class CharacterModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'shared' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'userCharacter' => [
|
||||
'has-one' => ['Model\UserCharacterModel', 'characterId']
|
||||
],
|
||||
'characterLog' => [
|
||||
'has-one' => ['Model\CharacterLogModel', 'characterId']
|
||||
],
|
||||
'characterMaps' => [
|
||||
'has-many' => ['Model\CharacterMapModel', 'characterId']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -92,16 +102,24 @@ class CharacterModel extends BasicModel {
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData($addCharacterLogData = false){
|
||||
$characterData = null;
|
||||
|
||||
$cacheKeyModifier = '';
|
||||
|
||||
// check if there is cached data
|
||||
// temporary disabled (performance test)
|
||||
$characterData = $this->getCacheData();
|
||||
if($addCharacterLogData){
|
||||
$cacheKeyModifier = strtoupper($this->table) . '_LOG';
|
||||
}
|
||||
|
||||
$characterData = $this->getCacheData($cacheKeyModifier);
|
||||
|
||||
if(is_null($characterData)){
|
||||
|
||||
// no cached character data found
|
||||
$characterData = (object) [];
|
||||
$characterData->id = $this->id;
|
||||
$characterData->name = $this->name;
|
||||
$characterData->shared = $this->shared;
|
||||
|
||||
if($addCharacterLogData){
|
||||
if($logModel = $this->getLog()){
|
||||
@@ -122,7 +140,7 @@ class CharacterModel extends BasicModel {
|
||||
// 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($characterData, '', 300);
|
||||
$this->updateCacheData($characterData, $cacheKeyModifier, 10);
|
||||
}
|
||||
|
||||
return $characterData;
|
||||
@@ -314,37 +332,58 @@ class CharacterModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* update character log (active system, ...)
|
||||
* -> CREST API request for character log data
|
||||
* -> HTTP Header Data (if IGB)
|
||||
* -> CREST API request for character log data (if not IGB)
|
||||
* @return CharacterModel
|
||||
*/
|
||||
public function updateLog(){
|
||||
|
||||
$characterModel = $this;
|
||||
$ssoController = new Ccp\Sso();
|
||||
$logData = [];
|
||||
$headerData = Controller\Controller::getIGBHeaderData();
|
||||
|
||||
$locationData = $ssoController->getCharacterLocationData($this->getAccessToken());
|
||||
// check if IGB Data is available
|
||||
if(
|
||||
$headerData->trusted === true &&
|
||||
!empty($headerData->values)
|
||||
){
|
||||
// format header data
|
||||
$formattedHeaderData = (new Mapper\IgbHeader($headerData->values))->getData();
|
||||
|
||||
if( empty((array)$locationData) ){
|
||||
// just for security -> check if Header Data matches THIS character
|
||||
if(
|
||||
isset($formattedHeaderData['character']) &&
|
||||
$formattedHeaderData['character']['id'] == $this->_id
|
||||
){
|
||||
$logData = $formattedHeaderData;
|
||||
}
|
||||
}else{
|
||||
// get Location Data from CREST endpoint
|
||||
// user is NOT with IGB online OR has not jet set "trusted" page
|
||||
$ssoController = new Ccp\Sso();
|
||||
$logData = $ssoController->getCharacterLocationData($this->getAccessToken());
|
||||
}
|
||||
|
||||
if( empty($logData) ){
|
||||
// character is not in-game
|
||||
if(is_object($this->characterLog)){
|
||||
// delete existing log
|
||||
$this->characterLog->erase();
|
||||
$characterModel = $this->save();
|
||||
$this->save();
|
||||
}
|
||||
}else{
|
||||
// character is currently in-game
|
||||
if( !$characterLog = $this->getLog() ){
|
||||
// create new log
|
||||
$characterLog = $this->rel('characterLog');
|
||||
$characterLog->characterId = $this;
|
||||
$characterLog->characterId = $this->_id;
|
||||
}
|
||||
$characterLog->setData($locationData);
|
||||
$characterLog->setData($logData);
|
||||
$characterLog->save();
|
||||
|
||||
$this->characterLog = $characterLog;
|
||||
$characterModel = $this->save();
|
||||
}
|
||||
|
||||
return $characterModel;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,10 +397,65 @@ class CharacterModel extends BasicModel {
|
||||
is_object($this->characterLog) &&
|
||||
!$this->characterLog->dry()
|
||||
){
|
||||
$characterLog = $this->characterLog;
|
||||
$characterLog = &$this->characterLog;
|
||||
}
|
||||
|
||||
return $characterLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* get mapModel by id and check if user has access
|
||||
* @param int $mapId
|
||||
* @return MapModel|null
|
||||
*/
|
||||
public function getMap(int $mapId){
|
||||
/**
|
||||
* @var $map MapModel
|
||||
*/
|
||||
$map = self::getNew('MapModel');
|
||||
$map->getById( $mapId );
|
||||
|
||||
$returnMap = null;
|
||||
if($map->hasAccess($this)){
|
||||
$returnMap = $map;
|
||||
}
|
||||
|
||||
return $returnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all accessible map models for this character
|
||||
* @return MapModel[]
|
||||
*/
|
||||
public function getMaps(){
|
||||
|
||||
$this->filter(
|
||||
'characterMaps',
|
||||
['active = ?', 1],
|
||||
['order' => 'created']
|
||||
);
|
||||
|
||||
$maps = [];
|
||||
if($this->characterMaps){
|
||||
$mapCountPrivate = 0;
|
||||
foreach($this->characterMaps as &$characterMap){
|
||||
if($mapCountPrivate < self::getF3()->get('PATHFINDER.MAX_MAPS_PRIVATE')){
|
||||
$maps[] = &$characterMap->mapId;
|
||||
$mapCountPrivate++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get
|
||||
if($alliance = $this->getAlliance()){
|
||||
$maps = array_merge($maps, $alliance->getMaps());
|
||||
}
|
||||
|
||||
if($corporation = $this->getCorporation()){
|
||||
$maps = array_merge($maps, $corporation->getMaps());
|
||||
}
|
||||
|
||||
return $maps;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -103,11 +103,11 @@ class ConnectionModel extends BasicModel{
|
||||
|
||||
/**
|
||||
* check object for model access
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
* @return mixed
|
||||
*/
|
||||
public function hasAccess(UserModel $user){
|
||||
return $this->mapId->hasAccess($user);
|
||||
public function hasAccess(CharacterModel $characterModel){
|
||||
return $this->mapId->hasAccess($characterModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,13 +127,12 @@ class ConnectionModel extends BasicModel{
|
||||
|
||||
/**
|
||||
* delete a connection
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
*/
|
||||
public function delete(UserModel $user){
|
||||
|
||||
if(!$this->dry()){
|
||||
// check if editor has access
|
||||
if($this->hasAccess($user)){
|
||||
public function delete(CharacterModel $characterModel){
|
||||
if( !$this->dry() ){
|
||||
// check if character has access
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->erase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ class MapModel extends BasicModel {
|
||||
'connections' => [
|
||||
'has-many' => ['Model\ConnectionModel', 'mapId']
|
||||
],
|
||||
'mapUsers' => [
|
||||
'has-many' => ['Model\UserMapModel', 'mapId']
|
||||
'mapCharacters' => [
|
||||
'has-many' => ['Model\CharacterMapModel', 'mapId']
|
||||
],
|
||||
'mapCorporations' => [
|
||||
'has-many' => ['Model\CorporationMapModel', 'mapId']
|
||||
@@ -157,17 +157,23 @@ class MapModel extends BasicModel {
|
||||
|
||||
// get access object data -------------------------------------
|
||||
if($this->isPrivate()){
|
||||
$users = $this->getUsers();
|
||||
$userData = [];
|
||||
foreach($users as $user){
|
||||
$userData[] = $user->getSimpleData();
|
||||
$characters = $this->getCharacters();
|
||||
$characterData = [];
|
||||
foreach($characters as $character){
|
||||
/**
|
||||
* @var $character CharacterModel
|
||||
*/
|
||||
$characterData[] = $character->getData();
|
||||
}
|
||||
$mapData->access->user = $userData;
|
||||
$mapData->access->character = $characterData;
|
||||
} elseif($this->isCorporation()){
|
||||
$corporations = $this->getCorporations();
|
||||
$corporationData = [];
|
||||
|
||||
foreach($corporations as $corporation){
|
||||
/**
|
||||
* @var $corporation CorporationModel
|
||||
*/
|
||||
$corporationData[] = $corporation->getData();
|
||||
}
|
||||
$mapData->access->corporation = $corporationData;
|
||||
@@ -176,6 +182,9 @@ class MapModel extends BasicModel {
|
||||
$allianceData = [];
|
||||
|
||||
foreach($alliances as $alliance){
|
||||
/**
|
||||
* @var $alliance AllianceModel
|
||||
*/
|
||||
$allianceData[] = $alliance->getData();
|
||||
}
|
||||
$mapData->access->alliance = $allianceData;
|
||||
@@ -230,8 +239,9 @@ class MapModel extends BasicModel {
|
||||
$this->filter('systems',
|
||||
['active = :active AND id > 0',
|
||||
':active' => 1
|
||||
],
|
||||
['order' => 'posX']);
|
||||
],
|
||||
['order' => 'posX']
|
||||
);
|
||||
|
||||
$systems = [];
|
||||
if($this->systems){
|
||||
@@ -251,6 +261,9 @@ class MapModel extends BasicModel {
|
||||
|
||||
$systemData = [];
|
||||
foreach($systems as $system){
|
||||
/**
|
||||
* @var $system SystemModel
|
||||
*/
|
||||
$systemData[] = $system->getData();
|
||||
}
|
||||
|
||||
@@ -284,6 +297,9 @@ class MapModel extends BasicModel {
|
||||
|
||||
$connectionData = [];
|
||||
foreach($connections as $connection){
|
||||
/**
|
||||
* @var $connection ConnectionModel
|
||||
*/
|
||||
$connectionData[] = $connection->getData();
|
||||
}
|
||||
|
||||
@@ -291,26 +307,26 @@ class MapModel extends BasicModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* set map access for an object (user, corporation or alliance)
|
||||
* set map access for an object (character, corporation or alliance)
|
||||
* @param $obj
|
||||
*/
|
||||
public function setAccess($obj){
|
||||
|
||||
$newAccessGranted = false;
|
||||
|
||||
if($obj instanceof UserModel){
|
||||
if($obj instanceof CharacterModel){
|
||||
// private map
|
||||
|
||||
// check whether the user has already map access
|
||||
$this->has('mapUsers', ['active = 1 AND userId = :userId', ':userId' => $obj->id]);
|
||||
$this->has('mapCharacters', ['active = 1 AND characterId = :characterId', ':characterId' => $obj->id]);
|
||||
$result = $this->findone(['id = :id', ':id' => $this->id]);
|
||||
|
||||
if($result === false){
|
||||
// grant access for the user
|
||||
$userMap = self::getNew('UserMapModel');
|
||||
$userMap->userId = $obj;
|
||||
$userMap->mapId = $this;
|
||||
$userMap->save();
|
||||
// grant access for the character
|
||||
$characterMap = self::getNew('CharacterMapModel');
|
||||
$characterMap-> characterId = $obj;
|
||||
$characterMap->mapId = $this;
|
||||
$characterMap->save();
|
||||
|
||||
$newAccessGranted = true;
|
||||
}
|
||||
@@ -356,16 +372,16 @@ class MapModel extends BasicModel {
|
||||
* clear access for a given type of objects
|
||||
* @param array $clearKeys
|
||||
*/
|
||||
public function clearAccess($clearKeys = ['user', 'corporation', 'alliance']){
|
||||
public function clearAccess($clearKeys = ['character', 'corporation', 'alliance']){
|
||||
|
||||
foreach($clearKeys as $key){
|
||||
switch($key){
|
||||
case 'user':
|
||||
foreach((array)$this->mapUsers as $userMapModel){
|
||||
case 'character':
|
||||
foreach((array)$this->mapCharacters as $characterMapModel){
|
||||
/**
|
||||
* @var UserMapModel $userMapModel
|
||||
* @var CharacterMapModel $characterMapModel
|
||||
*/
|
||||
$userMapModel->erase();
|
||||
$characterMapModel->erase();
|
||||
};
|
||||
break;
|
||||
case 'corporation':
|
||||
@@ -389,17 +405,17 @@ class MapModel extends BasicModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* checks weather a user has access to this map or not
|
||||
* @param UserModel $user
|
||||
* checks weather a character has access to this map or not
|
||||
* @param CharacterModel $characterModel
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAccess(UserModel $user){
|
||||
public function hasAccess(CharacterModel $characterModel){
|
||||
$hasAccess = false;
|
||||
|
||||
if( !$this->dry() ){
|
||||
// get all maps the user has access to
|
||||
// this includes corporation and alliance maps
|
||||
$maps = $user->getMaps();
|
||||
$maps = $characterModel->getMaps();
|
||||
foreach($maps as $map){
|
||||
if($map->id === $this->id){
|
||||
$hasAccess = true;
|
||||
@@ -412,42 +428,39 @@ class MapModel extends BasicModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* get all user models that have access to this map
|
||||
* note: This function is just for "private" maps
|
||||
* @return UserModel[]
|
||||
* get all (private) characters for this map
|
||||
* @return CharacterModel array
|
||||
*/
|
||||
public function getUsers(){
|
||||
$users = [];
|
||||
private function getCharacters(){
|
||||
$characters = [];
|
||||
|
||||
if($this->isPrivate()){
|
||||
$this->filter('mapUsers', ['active = ?', 1]);
|
||||
$this->filter('mapCharacters', ['active = ?', 1]);
|
||||
|
||||
if($this->mapUsers){
|
||||
foreach($this->mapUsers as $mapUser){
|
||||
$users[] = $mapUser->userId;
|
||||
}
|
||||
if($this->mapCharacters){
|
||||
foreach($this->mapCharacters as $characterMapModel){
|
||||
$characters[] = $characterMapModel->characterId;
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
return $characters;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all character models that are currently online "viewing" this map
|
||||
* @return CharacterModel[]
|
||||
*/
|
||||
private function getCharacters(){
|
||||
private function getActiveCharacters(){
|
||||
$characters = [];
|
||||
|
||||
if($this->isPrivate()){
|
||||
$users = $this->getUsers();
|
||||
$activeCharacters = $this->getCharacters();
|
||||
|
||||
// add active character for each user
|
||||
foreach($users as $user){
|
||||
foreach($activeCharacters as $activeCharacter){
|
||||
/**
|
||||
* @var UserModel $user
|
||||
*/
|
||||
$characters = array_merge($characters, $user->getActiveCharacters());
|
||||
$characters[] = $activeCharacter;
|
||||
}
|
||||
}elseif($this->isCorporation()){
|
||||
$corporations = $this->getCorporations();
|
||||
@@ -484,7 +497,7 @@ class MapModel extends BasicModel {
|
||||
|
||||
if(is_null($charactersData)){
|
||||
$charactersData = [];
|
||||
$characters = $this->getCharacters();
|
||||
$characters = $this->getActiveCharacters();
|
||||
|
||||
foreach($characters as $character){
|
||||
$charactersData[] = $character->getData(true);
|
||||
@@ -492,7 +505,7 @@ class MapModel extends BasicModel {
|
||||
|
||||
// cache active characters (if found)
|
||||
if(!empty($charactersData)){
|
||||
$this->updateCacheData($charactersData, 'CHARACTERS', 10);
|
||||
$this->updateCacheData($charactersData, 'CHARACTERS', 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,16 +554,13 @@ class MapModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* delete this map and all dependencies
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
*/
|
||||
public function delete(UserModel $user){
|
||||
|
||||
if(!$this->dry()){
|
||||
// check if user has access
|
||||
if($this->hasAccess($user)){
|
||||
public function delete(CharacterModel $characterModel){
|
||||
if( !$this->dry() ){
|
||||
// check if character has access
|
||||
if($this->hasAccess($characterModel)){
|
||||
// all map related tables will be deleted on cascade
|
||||
|
||||
// delete map
|
||||
$this->erase();
|
||||
}
|
||||
}
|
||||
@@ -663,9 +673,9 @@ class MapModel extends BasicModel {
|
||||
if( $mapModel->isPrivate() ){
|
||||
$mapModel->clearAccess(['corporation', 'alliance']);
|
||||
}elseif( $mapModel->isCorporation() ){
|
||||
$mapModel->clearAccess(['user', 'alliance']);
|
||||
$mapModel->clearAccess(['character', 'alliance']);
|
||||
}elseif( $mapModel->isAlliance() ){
|
||||
$mapModel->clearAccess(['user', 'corporation']);
|
||||
$mapModel->clearAccess(['character', 'corporation']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodus4d
|
||||
* Date: 29.08.15
|
||||
* Time: 11:57
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class RegistrationKeyModel extends BasicModel {
|
||||
|
||||
protected $table = 'registration_key';
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'ip' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'used' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'email' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => '',
|
||||
'index' => true
|
||||
],
|
||||
'registrationKey' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => '',
|
||||
'index' => true,
|
||||
'unique' => true
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
@@ -177,18 +177,18 @@ class SystemModel extends BasicModel {
|
||||
}else{
|
||||
// special array data
|
||||
if($key == 'constellation'){
|
||||
$this->constellationId = $value['id'];
|
||||
$this->constellationId = (int)$value['id'];
|
||||
$this->constellation = $value['name'];
|
||||
}elseif($key == 'region'){
|
||||
$this->regionId = $value['id'];
|
||||
$this->regionId = (int)$value['id'];
|
||||
$this->region = $value['name'];
|
||||
}elseif($key == 'type'){
|
||||
$this->typeId = $value['id'];
|
||||
$this->typeId = (int)$value['id'];
|
||||
}elseif($key == 'status'){
|
||||
$this->statusId = $value['id'];
|
||||
$this->statusId = (int)$value['id'];
|
||||
}elseif($key == 'position'){
|
||||
$this->posX = $value['x'];
|
||||
$this->posY = $value['y'];
|
||||
$this->posX = (int)$value['x'];
|
||||
$this->posY = (int)$value['y'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,23 +313,22 @@ class SystemModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* check object for model access
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
* @return mixed
|
||||
*/
|
||||
public function hasAccess(UserModel $user){
|
||||
return $this->mapId->hasAccess($user);
|
||||
public function hasAccess(CharacterModel $characterModel){
|
||||
return $this->mapId->hasAccess($characterModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a system from a map
|
||||
* hint: signatures and connections will be deleted on cascade
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
*/
|
||||
public function delete(UserModel $user){
|
||||
|
||||
if(! $this->dry()){
|
||||
// check if user has access
|
||||
if($this->hasAccess($user)){
|
||||
public function delete(CharacterModel $characterModel){
|
||||
if( !$this->dry() ){
|
||||
// check if character has access
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->erase();
|
||||
}
|
||||
}
|
||||
@@ -367,14 +366,14 @@ class SystemModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* get Signature by id and check for access
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
* @param $id
|
||||
* @return bool|null
|
||||
*/
|
||||
public function getSignatureById(UserModel $user, $id){
|
||||
public function getSignatureById(CharacterModel $characterModel, $id){
|
||||
$signature = null;
|
||||
|
||||
if($this->hasAccess($user)){
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->filter('signatures', ['active = ? AND id = ?', 1, $id]);
|
||||
if($this->signatures){
|
||||
$signature = reset( $this->signatures );
|
||||
@@ -386,14 +385,14 @@ class SystemModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* get a signature by its "unique" 3-digit name
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getSignatureByName(UserModel $user, $name){
|
||||
public function getSignatureByName(CharacterModel $characterModel, $name){
|
||||
$signature = null;
|
||||
|
||||
if($this->hasAccess($user)){
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->filter('signatures', ['active = ? AND name = ?', 1, $name]);
|
||||
if($this->signatures){
|
||||
$signature = reset( $this->signatures );
|
||||
|
||||
@@ -151,21 +151,21 @@ class SystemSignatureModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* check object for model access
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAccess(UserModel $user){
|
||||
return $this->systemId->hasAccess($user);
|
||||
public function hasAccess(CharacterModel $characterModel){
|
||||
return $this->systemId->hasAccess($characterModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete signature
|
||||
* @param UserModel $user
|
||||
* @param CharacterModel $characterModel
|
||||
*/
|
||||
public function delete(UserModel $user){
|
||||
if(!$this->dry()){
|
||||
// check if editor has access
|
||||
if($this->hasAccess($user)){
|
||||
public function delete(CharacterModel $characterModel){
|
||||
if( !$this->dry() ){
|
||||
// check if character has access
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->erase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodus4d
|
||||
* Date: 28.03.15
|
||||
* Time: 16:41
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
use Controller;
|
||||
|
||||
class UserApiModel extends BasicModel {
|
||||
|
||||
protected $table = 'user_api';
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'userId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\UserModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'user',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'keyId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'unique' => true
|
||||
],
|
||||
'vCode' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => '',
|
||||
],
|
||||
'userCharacters' => [
|
||||
'has-many' => ['Model\UserCharacterModel', 'apiId']
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* get all data for this api
|
||||
* @return object
|
||||
*/
|
||||
public function getData(){
|
||||
$apiData = (object) [];
|
||||
$apiData->keyId = $this->keyId;
|
||||
$apiData->vCode = $this->vCode;
|
||||
|
||||
return $apiData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all characters for this API
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getUserCharacters(){
|
||||
$this->filter('userCharacters', ['active = ?', 1]);
|
||||
|
||||
$userCharacters = [];
|
||||
if($this->userCharacters){
|
||||
$userCharacters = $this->userCharacters;
|
||||
}
|
||||
|
||||
return $userCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for a user character model by a characterId
|
||||
* @param $characterId
|
||||
* @return null
|
||||
*/
|
||||
public function getUserCharacterById($characterId){
|
||||
$userCharacters = $this->getUserCharacters();
|
||||
$returnUserCharacter = null;
|
||||
|
||||
foreach($userCharacters as $userCharacter){
|
||||
if($userCharacter->characterId->id == $characterId){
|
||||
$returnUserCharacter = $userCharacter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $returnUserCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if this api model has a main character
|
||||
* @return bool
|
||||
*/
|
||||
public function hasMainCharacter(){
|
||||
$hasMain = false;
|
||||
|
||||
$characters = $this->getUserCharacters();
|
||||
foreach($characters as $character){
|
||||
if($character->isMain()){
|
||||
$hasMain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $hasMain;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the user object for this model
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUser(){
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete this api model
|
||||
*/
|
||||
public function delete(){
|
||||
|
||||
// check if this api model had a main character
|
||||
$user = $this->userId;
|
||||
$setNewMain = false;
|
||||
|
||||
if($this->hasMainCharacter()){
|
||||
$setNewMain = true;
|
||||
}
|
||||
$this->erase();
|
||||
|
||||
if($setNewMain){
|
||||
$user->setMainCharacterId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,17 +32,6 @@ class UserCharacterModel extends BasicModel {
|
||||
]
|
||||
]
|
||||
],
|
||||
'apiId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\UserApiModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'user_api',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'characterId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
@@ -54,12 +43,6 @@ class UserCharacterModel extends BasicModel {
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'isMain' => [
|
||||
'type' => Schema::DT_BOOLEAN,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
'index' => true
|
||||
]
|
||||
];
|
||||
|
||||
@@ -68,9 +51,7 @@ class UserCharacterModel extends BasicModel {
|
||||
* @param $characterData
|
||||
*/
|
||||
public function setData($characterData){
|
||||
|
||||
foreach((array)$characterData as $key => $value){
|
||||
|
||||
if(!is_array($value)){
|
||||
if($this->exists($key)){
|
||||
$this->$key = $value;
|
||||
@@ -95,27 +76,6 @@ class UserCharacterModel extends BasicModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check if this character is Main character or not
|
||||
* @return bool
|
||||
*/
|
||||
public function isMain(){
|
||||
$isMain = false;
|
||||
if($this->isMain == 1){
|
||||
$isMain = true;
|
||||
}
|
||||
|
||||
return $isMain;
|
||||
}
|
||||
|
||||
/**
|
||||
* set this character as main character
|
||||
*/
|
||||
public function setMain($value = 0){
|
||||
$this->isMain = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the character model of this character
|
||||
* @return mixed
|
||||
@@ -135,10 +95,7 @@ class UserCharacterModel extends BasicModel {
|
||||
$status = parent::setup($db,$table,$fields);
|
||||
|
||||
if($status === true){
|
||||
$status = parent::setMultiColumnIndex(['userId', 'apiId', 'characterId'], true);
|
||||
if($status === true){
|
||||
$status = parent::setMultiColumnIndex(['userId', 'apiId']);
|
||||
}
|
||||
$status = parent::setMultiColumnIndex(['userId', 'characterId'], true);
|
||||
}
|
||||
|
||||
return $status;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodus4d
|
||||
* Date: 28.02.15
|
||||
* Time: 11:57
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class UserMapModel extends BasicModel {
|
||||
|
||||
protected $table = 'user_map';
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'userId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\UserModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'user',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'mapId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\MapModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'map',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* see parent
|
||||
*/
|
||||
public function clearCacheData(){
|
||||
parent::clearCacheData();
|
||||
|
||||
// clear map cache as well
|
||||
$this->mapId->clearCacheData();
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrites parent
|
||||
* @param null $db
|
||||
* @param null $table
|
||||
* @param null $fields
|
||||
* @return bool
|
||||
*/
|
||||
public static function setup($db=null, $table=null, $fields=null){
|
||||
$status = parent::setup($db,$table,$fields);
|
||||
|
||||
if($status === true){
|
||||
$status = parent::setMultiColumnIndex(['userId', 'mapId'], true);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,24 +35,8 @@ class UserModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'password' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'shared' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'apis' => [
|
||||
'has-many' => ['Model\UserApiModel', 'userId']
|
||||
],
|
||||
'userCharacters' => [
|
||||
'has-many' => ['Model\UserCharacterModel', 'userId']
|
||||
],
|
||||
'userMaps' => [
|
||||
'has-many' => ['Model\UserMapModel', 'userId']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -62,11 +46,6 @@ class UserModel extends BasicModel {
|
||||
'min' => 5,
|
||||
'max' => 25
|
||||
]
|
||||
],
|
||||
'password' => [
|
||||
'length' => [
|
||||
'min' => 6
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
@@ -84,9 +63,6 @@ class UserModel extends BasicModel {
|
||||
// add sensitive user data
|
||||
$userData->email = $this->email;
|
||||
|
||||
// user shared info
|
||||
$userData->shared = $this->shared;
|
||||
|
||||
// all chars
|
||||
$userData->characters = [];
|
||||
$characters = $this->getCharacters();
|
||||
@@ -97,7 +73,7 @@ class UserModel extends BasicModel {
|
||||
$userData->characters[] = $character->getData();
|
||||
}
|
||||
|
||||
// set active character with log data
|
||||
// get active character with log data
|
||||
$activeCharacter = $this->getActiveCharacter();
|
||||
$userData->character = $activeCharacter->getData(true);
|
||||
|
||||
@@ -134,20 +110,6 @@ class UserModel extends BasicModel {
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* set a password hash for this user
|
||||
* @param string $password
|
||||
* @return string
|
||||
*/
|
||||
public function set_password($password){
|
||||
if(strlen($password) < 6){
|
||||
$this->throwValidationError('password');
|
||||
}
|
||||
|
||||
$salt = uniqid('', true);
|
||||
return \Bcrypt::instance()->hash($password, $salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if new user registration is allowed
|
||||
* @return bool
|
||||
@@ -179,133 +141,6 @@ class UserModel extends BasicModel {
|
||||
return $this->getByForeignKey('name', $name, [], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* verify a user by his password
|
||||
* @param $password
|
||||
* @return bool
|
||||
*/
|
||||
public function verify($password){
|
||||
$valid = false;
|
||||
|
||||
if(! $this->dry()){
|
||||
$valid = (bool) \Bcrypt::instance()->verify($password, $this->password);
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all accessible map models for this user
|
||||
* @return MapModel[]
|
||||
*/
|
||||
public function getMaps(){
|
||||
|
||||
$this->filter(
|
||||
'userMaps',
|
||||
['active = ?', 1],
|
||||
['order' => 'created']
|
||||
);
|
||||
|
||||
$maps = [];
|
||||
if($this->userMaps){
|
||||
$mapCountPrivate = 0;
|
||||
foreach($this->userMaps as &$userMap){
|
||||
if(
|
||||
$userMap->mapId->isActive() &&
|
||||
$mapCountPrivate < self::getF3()->get('PATHFINDER.MAX_MAPS_PRIVATE')
|
||||
){
|
||||
$maps[] = &$userMap->mapId;
|
||||
$mapCountPrivate++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get current active character
|
||||
$controller = new Controller\Controller();
|
||||
$activeCharacter = $controller->getCharacter();
|
||||
$corporation = $activeCharacter->getCorporation();
|
||||
$alliance = $activeCharacter->getAlliance();
|
||||
|
||||
if($alliance){
|
||||
$maps = array_merge($maps, $alliance->getMaps());
|
||||
}
|
||||
|
||||
if($corporation){
|
||||
$maps = array_merge($maps, $corporation->getMaps());
|
||||
}
|
||||
|
||||
return $maps;
|
||||
}
|
||||
|
||||
/**
|
||||
* get mapModel by id and check if user has access
|
||||
* @param int $mapId
|
||||
* @return MapModel|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getMap(int $mapId){
|
||||
/**
|
||||
* @var $map MapModel
|
||||
*/
|
||||
$map = self::getNew('MapModel');
|
||||
$map->getById( $mapId );
|
||||
|
||||
$returnMap = null;
|
||||
if($map->hasAccess($this)){
|
||||
$returnMap = $map;
|
||||
}
|
||||
|
||||
return $returnMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get all API models for this user
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function getAPIs(){
|
||||
$this->filter('apis', ['active = ?', 1]);
|
||||
|
||||
$apis = [];
|
||||
if($this->apis){
|
||||
$apis = $this->apis;
|
||||
}
|
||||
|
||||
return $apis;
|
||||
}
|
||||
|
||||
/**
|
||||
* set main character ID for this user.
|
||||
* If id does not match with his API chars -> select "random" main character
|
||||
* @param int $characterId
|
||||
*/
|
||||
public function setMainCharacterId($characterId = 0){
|
||||
|
||||
if(is_int($characterId)){
|
||||
$userCharacters = $this->getUserCharacters();
|
||||
|
||||
if(count($userCharacters) > 0){
|
||||
$mainSet = false;
|
||||
foreach($userCharacters as $userCharacter){
|
||||
if($characterId == $userCharacter->getCharacter()->id){
|
||||
$mainSet = true;
|
||||
$userCharacter->setMain(1);
|
||||
}else{
|
||||
$userCharacter->setMain(0);
|
||||
}
|
||||
$userCharacter->save();
|
||||
}
|
||||
|
||||
// set first character as "main"
|
||||
if( !$mainSet ){
|
||||
$userCharacter = reset($userCharacters);
|
||||
$userCharacter->setMain(1);
|
||||
$userCharacter->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get all userCharacters models for a user
|
||||
* characters will be checked/updated on login by CCP API call
|
||||
@@ -322,24 +157,6 @@ class UserModel extends BasicModel {
|
||||
return $userCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the main user character for this user
|
||||
* @return null
|
||||
*/
|
||||
public function getMainUserCharacter(){
|
||||
$mainUserCharacter = null;
|
||||
$userCharacters = $this->getUserCharacters();
|
||||
|
||||
foreach($userCharacters as $userCharacter){
|
||||
if($userCharacter->isMain()){
|
||||
$mainUserCharacter = $userCharacter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $mainUserCharacter;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current active character for this user
|
||||
* -> EITHER - the current active one for the current user
|
||||
@@ -359,7 +176,7 @@ class UserModel extends BasicModel {
|
||||
}else{
|
||||
// set "first" found as active for this user
|
||||
if($activeCharacters = $this->getActiveCharacters()){
|
||||
$activeCharacter = &$activeCharacters[0];
|
||||
$activeCharacter = $activeCharacters[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,105 +226,4 @@ class UserModel extends BasicModel {
|
||||
return $activeCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* updated the character log entry for a user character by IGB Header data
|
||||
* @param int $ttl cache time in seconds
|
||||
* @throws \Exception
|
||||
*/
|
||||
/*
|
||||
public function updateCharacterLog($ttl = 0){
|
||||
|
||||
$headerData = Controller\Controller::getIGBHeaderData();
|
||||
|
||||
// check if IGB Data is available
|
||||
if( !empty($headerData->values) ){
|
||||
$f3 = self::getF3();
|
||||
|
||||
// check if system has changed since the last call
|
||||
// current location is stored (global) to avoid unnecessary DB calls
|
||||
$sessionCharacterKey = 'LOGGED.user.character.id_' . $headerData->values['charid'];
|
||||
|
||||
if($f3->exists($sessionCharacterKey)){
|
||||
// cache data exists
|
||||
$cacheData = $f3->get($sessionCharacterKey);
|
||||
}else{
|
||||
// new cache data
|
||||
$cacheData = [
|
||||
'systemId' => 0,
|
||||
'shipId' => 0
|
||||
];
|
||||
}
|
||||
|
||||
if(
|
||||
$cacheData['systemId'] != $headerData->values['solarsystemid'] ||
|
||||
$cacheData['shipId'] != $headerData->values['shiptypeid']
|
||||
){
|
||||
$cacheData['systemId'] = (int)$headerData->values['solarsystemid'];
|
||||
$cacheData['shipId'] = (int)$headerData->values['shiptypeid'];
|
||||
|
||||
// character has changed system, or character just logged on
|
||||
$character = self::getNew('CharacterModel');
|
||||
$character->getById( (int)$headerData->values['charid'] );
|
||||
|
||||
if( $character->dry() ){
|
||||
// this can happen if a valid user plays the game with a not registered character
|
||||
// whose API is not registered -> save new character or update character data
|
||||
$corporationId = array_key_exists('corpid', $headerData->values) ? $headerData->values['corpid'] : null;
|
||||
$allianceId = array_key_exists('allianceid', $headerData->values) ? $headerData->values['allianceid'] : null;
|
||||
|
||||
// check if corp exists
|
||||
if( !is_null($corporationId) ){
|
||||
$corporation = self::getNew('CorporationModel');
|
||||
$corporation->getById( (int)$corporationId );
|
||||
if( $corporation->dry() ){
|
||||
$corporation->id = $corporationId;
|
||||
$corporation->name = $headerData->values['corpname'];
|
||||
$corporation->save();
|
||||
}
|
||||
}
|
||||
|
||||
// check if ally exists
|
||||
if( !is_null($allianceId) ){
|
||||
$alliance = self::getNew('AllianceModel');
|
||||
$alliance->getById( (int)$allianceId );
|
||||
if( $alliance->dry() ){
|
||||
$alliance->id = $allianceId;
|
||||
$alliance->name = $headerData->values['alliancename'];
|
||||
$alliance->save();
|
||||
}
|
||||
}
|
||||
|
||||
$character->id = (int) $headerData->values['charid'];
|
||||
$character->name = $headerData->values['charname'];
|
||||
$character->corporationId = $corporationId;
|
||||
$character->allianceId = $allianceId;
|
||||
$character->save();
|
||||
}
|
||||
|
||||
// check if this character has an active log
|
||||
if( !$characterLog = $character->getLog() ){
|
||||
$characterLog = self::getNew('CharacterLogModel');
|
||||
}
|
||||
|
||||
// set character log values
|
||||
$characterLog->characterId = $character;
|
||||
$characterLog->systemId = (int)$headerData->values['solarsystemid'];
|
||||
$characterLog->systemName = $headerData->values['solarsystemname'];
|
||||
$characterLog->shipId = (int)$headerData->values['shiptypeid'];
|
||||
$characterLog->shipName = $headerData->values['shipname'];
|
||||
$characterLog->shipTypeName = $headerData->values['shiptypename'];
|
||||
|
||||
$characterLog->save();
|
||||
|
||||
// clear cache for the characterModel as well
|
||||
$character->clearCacheData();
|
||||
|
||||
// cache character log information
|
||||
$f3->set($sessionCharacterKey, $cacheData, $ttl);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@ MAX_MAPS_CORPORATION = 3
|
||||
MAX_MAPS_ALLIANCE = 3
|
||||
|
||||
; Max number of shared entities per map
|
||||
MAX_SHARED_USER = 10
|
||||
MAX_SHARED_CHARACTER = 10
|
||||
MAX_SHARED_CORPORATION = 3
|
||||
MAX_SHARED_ALLIANCE = 2
|
||||
|
||||
@@ -35,8 +35,8 @@ INVITE = 0
|
||||
INVITE_LIMIT = 50
|
||||
|
||||
[PATHFINDER.LOGIN]
|
||||
|
||||
CORPORATION = 1000166
|
||||
; restrict login to specific corporations/alliances by id (e.g. 1000166,1000080)
|
||||
CORPORATION =
|
||||
ALLIANCE =
|
||||
|
||||
; View ============================================================================================
|
||||
@@ -83,7 +83,7 @@ EXECUTION_LIMIT = 50
|
||||
; map user update ping (ajax) (ms)
|
||||
[PATHFINDER.TIMER.UPDATE_SERVER_USER_DATA]
|
||||
DELAY = 5000
|
||||
EXECUTION_LIMIT = 200
|
||||
EXECUTION_LIMIT = 300
|
||||
|
||||
; update client user data (ms)
|
||||
[PATHFINDER.TIMER.UPDATE_CLIENT_USER_DATA]
|
||||
|
||||
@@ -3,16 +3,15 @@
|
||||
[routes]
|
||||
; DB setup setup
|
||||
; IMPORTANT: remove/comment this line after setup/update is finished!
|
||||
GET @setup: /setup = Controller\Setup->init, 0
|
||||
GET @setup: /setup [sync] = Controller\Setup->init, 0
|
||||
; login (index) page
|
||||
GET @login: / = Controller\AppController->init, 0
|
||||
GET @login: / [sync] = Controller\AppController->init, 0
|
||||
; CCP SSO redirect
|
||||
GET @sso: /sso/@action = Controller\Ccp\Sso->@action, 0
|
||||
|
||||
GET @sso: /sso/@action [sync] = Controller\Ccp\Sso->@action, 0
|
||||
; map page
|
||||
GET @map: /map = Controller\MapController->init, 0
|
||||
GET @map: /map [sync] = Controller\MapController->init, 0
|
||||
|
||||
; ajax wildcard APIs (throttled)
|
||||
GET|POST /api/@controller/@action [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
GET|POST /api/@controller/@action/@arg1 [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
GET|POST /api/@controller/@action/@arg1/@arg2 [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
GET|POST /api/@controller/@action [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
GET|POST /api/@controller/@action/@arg1 [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
GET|POST /api/@controller/@action/@arg1/@arg2 [ajax] = Controller\Api\@controller->@action, 0, 512
|
||||
|
||||
28
gulpfile.js
28
gulpfile.js
@@ -6,7 +6,6 @@ var plumber = require('gulp-plumber');
|
||||
var gzip = require('gulp-gzip');
|
||||
var gulpif = require('gulp-if');
|
||||
var clean = require('gulp-clean');
|
||||
var critical = require('critical');
|
||||
|
||||
var runSequence = require('run-sequence');
|
||||
var exec = require('child_process').exec;
|
||||
@@ -91,13 +90,7 @@ gulp.task('jshint', function(){
|
||||
errorHandler: onError
|
||||
}))
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter(stylish))
|
||||
.pipe(notify({
|
||||
icon: path.resolve(__dirname, _src.ICON),
|
||||
title: 'JSHint',
|
||||
message: 'Task complete',
|
||||
onLast: true
|
||||
}));
|
||||
.pipe(jshint.reporter(stylish));
|
||||
// .pipe(jshint.reporter('fail')); // uncomment this line to stop build on error
|
||||
});
|
||||
|
||||
@@ -247,25 +240,6 @@ gulp.task('default', function(tag) {
|
||||
);
|
||||
});
|
||||
|
||||
/*
|
||||
// This removes all CSS styles "above the fold" from *.css and inlines them
|
||||
// -> to improve pagespeed. The remaining (main) css file will be lazy loaded afterwards...
|
||||
// https://github.com/addyosmani/critical
|
||||
gulp.task('critical', function (cb) {
|
||||
critical.generate({
|
||||
inline: true,
|
||||
base: './',
|
||||
src: './public/templates/view/index.html',
|
||||
dest: './public/templates/view/index-critical.html',
|
||||
extract: true,
|
||||
minify: true,
|
||||
width: 2560,
|
||||
height: 1440
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* clear all backend (fat free framework) cache files
|
||||
*/
|
||||
|
||||
@@ -45,7 +45,7 @@ requirejs.config({
|
||||
hoverIntent: 'lib/jquery.hoverIntent.minified', // v1.8.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
|
||||
fullScreen: 'lib/jquery.fullscreen.min', // v0.5.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
|
||||
select2: 'lib/select2.min', // v4.0.0 Drop Down customization - https://select2.github.io/
|
||||
validator: 'lib/validator.min', // v0.7.2 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
|
||||
validator: 'lib/validator.min', // v0.10.1 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
|
||||
lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info/
|
||||
blueImpGallery: 'lib/blueimp-gallery', // v2.15.2 Image Gallery - https://github.com/blueimp/Gallery/
|
||||
blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery
|
||||
|
||||
@@ -16,6 +16,7 @@ define(['jquery'], function($) {
|
||||
logOut: 'api/user/logOut', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
getUserData: 'api/user/getData', // ajax URL - get user data
|
||||
saveSharingConfig: 'api/user/saveSharingConfig', // ajax URL - save "sharing settings" dialog
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
// access API
|
||||
|
||||
@@ -83,6 +83,7 @@ define([
|
||||
autoWidth: false,
|
||||
hover: false,
|
||||
pageLength: 15,
|
||||
lengthMenu: [[10, 15, 25, 50, 50], [10, 15, 25, 50, 50]],
|
||||
data: logData, // load cached logs (if available)
|
||||
language: {
|
||||
emptyTable: 'No entries',
|
||||
|
||||
@@ -84,54 +84,6 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
// login buttons ------------------------------------------------
|
||||
var loginForm = $('#' + config.loginFormId);
|
||||
|
||||
loginForm.on('submit', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var loginFormMessageContainer = $('#' + config.loginMessageContainerId);
|
||||
|
||||
// validate form
|
||||
loginForm.validator('validate');
|
||||
|
||||
// check weather the form is valid
|
||||
var formValid = loginForm.isValidForm();
|
||||
|
||||
if(formValid === true){
|
||||
|
||||
// show splash overlay
|
||||
$('.' + config.splashOverlayClass).showSplashOverlay(function(){
|
||||
|
||||
var loginData = {loginData: loginForm.getFormValues()};
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.logIn,
|
||||
data: loginData,
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
// login error
|
||||
if(data.error !== undefined){
|
||||
$('.' + config.splashOverlayClass).hideSplashOverlay();
|
||||
loginFormMessageContainer.showMessage({title: 'Login failed', text: ' Invalid username or password', type: 'error'});
|
||||
|
||||
}else if(data.reroute !== undefined){
|
||||
window.location = data.reroute;
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
$('.' + config.splashOverlayClass).hideSplashOverlay();
|
||||
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': login', text: reason, type: 'error'});
|
||||
|
||||
// show Form message
|
||||
loginFormMessageContainer.showMessage({title: 'Login failed', text: ' internal server error', type: 'error'});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// releases -----------------------------------------------------
|
||||
$('.' + config.navigationVersionLinkClass).on('click', function(e){
|
||||
$.fn.releasesDialog();
|
||||
|
||||
@@ -602,12 +602,12 @@ define([
|
||||
system.attr('data-mapid', parseInt(mapContainer.data('id')));
|
||||
|
||||
// locked system
|
||||
if( Boolean( system.data( 'locked') ) !== Boolean( parseInt( data.locked ) )){
|
||||
if( Boolean( system.data( 'locked') ) !== data.locked ){
|
||||
system.toggleLockSystem(false, {hideNotification: true, hideCounter: true, map: map});
|
||||
}
|
||||
|
||||
// rally system
|
||||
if( Boolean( system.data( 'rally') ) !== Boolean( parseInt( data.rally ) )){
|
||||
if( Boolean( system.data( 'rally') ) !== data.rally ){
|
||||
system.toggleRallyPoint(false, {hideNotification: true, hideCounter: true});
|
||||
}
|
||||
|
||||
@@ -3099,12 +3099,10 @@ define([
|
||||
// this is restricted to IGB-usage! CharacterLog data is always set through the IGB
|
||||
// ->this prevent adding the same system multiple times, if a user is online with IGB AND OOG
|
||||
if(
|
||||
CCP.isInGameBrowser() === true &&
|
||||
currentUserOnMap === false &&
|
||||
currentCharacterLog &&
|
||||
mapTracking
|
||||
){
|
||||
|
||||
// add new system to the map
|
||||
var requestData = {
|
||||
systemData: {
|
||||
@@ -3344,6 +3342,15 @@ define([
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* removes a map instance from local cache
|
||||
* @param mapId
|
||||
*/
|
||||
var clearMapInstance = function(mapId){
|
||||
if(typeof activeInstances[mapId] === 'object'){
|
||||
delete activeInstances[mapId];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* get a new jsPlumb map instance or or get a cached one for update
|
||||
@@ -3583,4 +3590,8 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
clearMapInstance: clearMapInstance
|
||||
};
|
||||
|
||||
});
|
||||
@@ -39,14 +39,26 @@ define([
|
||||
// map init load static data =======================================================
|
||||
$.getJSON( Init.path.initMap, function( initData ) {
|
||||
|
||||
Init.timer = initData.timer;
|
||||
Init.mapTypes = initData.mapTypes;
|
||||
Init.mapScopes = initData.mapScopes;
|
||||
Init.connectionScopes = initData.connectionScopes;
|
||||
Init.systemStatus = initData.systemStatus;
|
||||
Init.systemType = initData.systemType;
|
||||
Init.characterStatus = initData.characterStatus;
|
||||
Init.maxSharedCount = initData.maxSharedCount;
|
||||
|
||||
if( initData.error.length > 0 ){
|
||||
for(var i = 0; i < initData.error.length; i++){
|
||||
Util.showNotify({
|
||||
title: initData.error[i].title,
|
||||
text: initData.error[i].message,
|
||||
type: initData.error[i].type
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Init.timer = initData.timer;
|
||||
Init.mapTypes = initData.mapTypes;
|
||||
Init.mapScopes = initData.mapScopes;
|
||||
Init.connectionScopes = initData.connectionScopes;
|
||||
Init.systemStatus = initData.systemStatus;
|
||||
Init.systemType = initData.systemType;
|
||||
Init.characterStatus = initData.characterStatus;
|
||||
Init.maxSharedCount = initData.maxSharedCount;
|
||||
Init.routes = initData.routes;
|
||||
|
||||
// init tab change observer, Once the timers are available
|
||||
Page.initTabChangeObserver();
|
||||
@@ -168,14 +180,7 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
|
||||
// clear both main update request trigger timer
|
||||
clearUpdateTimeouts();
|
||||
|
||||
var reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
$(document).trigger('pf:shutdown', {reason: reason});
|
||||
});
|
||||
}).fail(handleAjaxErrorResponse);
|
||||
};
|
||||
|
||||
// ping for user data update =======================================================
|
||||
@@ -258,14 +263,35 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
}).fail(handleAjaxErrorResponse);
|
||||
|
||||
// clear both main update request trigger timer
|
||||
clearUpdateTimeouts();
|
||||
};
|
||||
|
||||
var reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
$(document).trigger('pf:shutdown', {reason: reason});
|
||||
});
|
||||
/**
|
||||
* Ajax error response handler function for main-ping functions
|
||||
* @param jqXHR
|
||||
* @param status
|
||||
* @param error
|
||||
*/
|
||||
var handleAjaxErrorResponse = function(jqXHR, status, error){
|
||||
// clear both main update request trigger timer
|
||||
clearUpdateTimeouts();
|
||||
|
||||
var reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
var errorData = [];
|
||||
|
||||
if(jqXHR.responseText){
|
||||
var errorObj = $.parseJSON(jqXHR.responseText);
|
||||
|
||||
if(
|
||||
errorObj.error &&
|
||||
errorObj.error.length > 0
|
||||
){
|
||||
errorData = errorObj.error;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).trigger('pf:shutdown', {reason: reason, error: errorData});
|
||||
|
||||
};
|
||||
|
||||
@@ -287,7 +313,6 @@ define([
|
||||
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -2,6 +2,7 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/map',
|
||||
'app/counter',
|
||||
'app/ui/system_info',
|
||||
'app/ui/system_graph',
|
||||
@@ -9,9 +10,8 @@ define([
|
||||
'app/ui/system_route',
|
||||
'app/ui/system_killboard',
|
||||
'datatablesTableTools',
|
||||
'datatablesResponsive',
|
||||
'app/map/map'
|
||||
], function($, Init, Util) {
|
||||
'datatablesResponsive'
|
||||
], function($, Init, Util, Map) {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -259,6 +259,11 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get a fresh tab element
|
||||
* @param options
|
||||
* @returns {*|jQuery|HTMLElement}
|
||||
*/
|
||||
var getTabElement = function(options){
|
||||
|
||||
var tabElement = $('<div>', {
|
||||
@@ -395,7 +400,7 @@ define([
|
||||
// update Tab element -> set data
|
||||
linkElement.updateTabData(options);
|
||||
|
||||
// tabs content ====================================
|
||||
// tabs content =======================================================
|
||||
var contentElement = $('<div>', {
|
||||
id: config.mapTabIdPrefix + parseInt( options.id ),
|
||||
class: [config.mapTabContentClass].join(' ')
|
||||
@@ -405,8 +410,7 @@ define([
|
||||
|
||||
tabContent.append(contentElement);
|
||||
|
||||
|
||||
// init tab =========================================================
|
||||
// init tab ===========================================================
|
||||
linkElement.on('click', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
@@ -482,8 +486,11 @@ define([
|
||||
liElement.remove();
|
||||
contentElement.remove();
|
||||
|
||||
// remove map instance from local cache
|
||||
Map.clearMapInstance(mapId);
|
||||
|
||||
if(findNewActiveTab === true){
|
||||
tabElement.find('a:first').tab('show');
|
||||
tabElement.find('.' + config.mapTabClass + ':not(.pull-right):first a').tab('show');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,6 +547,9 @@ define([
|
||||
// tab element already exists
|
||||
var tabElements = mapModuleElement.getMapTabElements();
|
||||
|
||||
// map ID that is currently active
|
||||
var activeMapId = 0;
|
||||
|
||||
// mapIds that are currently active
|
||||
var activeMapIds = [];
|
||||
|
||||
@@ -582,6 +592,15 @@ define([
|
||||
|
||||
var newTabElements = tabMapElement.addTab(data.config);
|
||||
|
||||
// check if there is any active map yet (this is not the case
|
||||
// when ALL maps are removed AND new maps are added in one call
|
||||
// e.g. character switch)
|
||||
if(tabMapElement.find('.' + config.mapTabClass + '.active:not(.pull-right)').length === 0){
|
||||
tabMapElement.find('.' + config.mapTabClass + ':not(.pull-right):first a').tab('show');
|
||||
|
||||
activeMapId = data.config.id;
|
||||
}
|
||||
|
||||
// set observer for manually triggered map events
|
||||
newTabElements.contentElement.setTabContentObserver();
|
||||
|
||||
@@ -596,7 +615,9 @@ define([
|
||||
});
|
||||
|
||||
// get current active map
|
||||
var activeMapId = Util.getMapModule().getActiveMap().data('id');
|
||||
if(activeMapId === 0){
|
||||
activeMapId = Util.getMapModule().getActiveMap().data('id');
|
||||
}
|
||||
var activeMapData = Util.getCurrentMapData(activeMapId);
|
||||
|
||||
if(activeMapData !== false){
|
||||
|
||||
@@ -14,7 +14,6 @@ define([
|
||||
'text!templates/modules/footer.html',
|
||||
'dialog/notification',
|
||||
'dialog/trust',
|
||||
'dialog/sharing_settings',
|
||||
'dialog/map_info',
|
||||
'dialog/account_settings',
|
||||
'dialog/manual',
|
||||
@@ -143,13 +142,13 @@ define([
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Sharing settings').prepend(
|
||||
}).html(' Settings').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-share-alt fa-fw'
|
||||
class: 'fa fa-gears fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSharingSettings');
|
||||
})
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
@@ -400,11 +399,6 @@ define([
|
||||
slideMenu.slidebars.toggle('right');
|
||||
});
|
||||
|
||||
// settings
|
||||
$('.' + config.headUserCharacterClass).find('a').on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
});
|
||||
|
||||
// active pilots
|
||||
$('.' + config.headActiveUserClass).find('a').on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
@@ -439,11 +433,8 @@ define([
|
||||
});
|
||||
|
||||
// set default values for map tracking checkbox
|
||||
if(CCP.isInGameBrowser() === false){
|
||||
mapTrackingCheckbox.bootstrapToggle('disable');
|
||||
}else{
|
||||
mapTrackingCheckbox.bootstrapToggle('on');
|
||||
}
|
||||
// -> always "enable"
|
||||
mapTrackingCheckbox.bootstrapToggle('on');
|
||||
|
||||
mapTrackingCheckbox.on('change', function(e) {
|
||||
var value = $(this).is(':checked');
|
||||
@@ -502,13 +493,6 @@ define([
|
||||
*/
|
||||
var setDocumentObserver = function(){
|
||||
|
||||
// tab close/reload detected
|
||||
window.addEventListener('beforeunload', function (e) {
|
||||
|
||||
// logout
|
||||
deleteLog();
|
||||
});
|
||||
|
||||
// on "full-screen" change event
|
||||
$(document).on('fscreenchange', function(e, state, elem){
|
||||
|
||||
@@ -526,12 +510,6 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowSharingSettings', function(e){
|
||||
// show sharing settings dialog
|
||||
$.fn.showSharingSettingsDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowSystemEffectInfo', function(e){
|
||||
// show system effects info box
|
||||
$.fn.showSystemEffectInfoDialog();
|
||||
@@ -670,12 +648,22 @@ define([
|
||||
title: 'Shutdown',
|
||||
headline: 'Emergency shutdown',
|
||||
text: [
|
||||
'Sorry! Under normal circumstances that should not happen',
|
||||
data.reason
|
||||
]
|
||||
],
|
||||
textSmaller: []
|
||||
}
|
||||
};
|
||||
|
||||
// add error information (if available)
|
||||
if(
|
||||
data.error &&
|
||||
data.error.length
|
||||
){
|
||||
for(var i = 0; i < data.error.length; i++){
|
||||
options.content.textSmaller.push(data.error[i].message);
|
||||
}
|
||||
}
|
||||
|
||||
$.fn.showNotificationDialog(options);
|
||||
|
||||
$(document).setProgramStatus('offline');
|
||||
@@ -752,7 +740,7 @@ define([
|
||||
newCharacterName = userData.character.name;
|
||||
|
||||
if(userData.character.log){
|
||||
newShipId = userData.character.log.ship.id;
|
||||
newShipId = userData.character.log.ship.typeId;
|
||||
newShipName = userData.character.log.ship.typeName;
|
||||
}
|
||||
}
|
||||
@@ -769,6 +757,9 @@ define([
|
||||
animateHeaderElement(userInfoElement, function(){
|
||||
userInfoElement.find('span').text( newCharacterName );
|
||||
userInfoElement.find('img').attr('src', Init.url.ccpImageServer + 'Character/' + newCharacterId + '_32.jpg' );
|
||||
|
||||
// init "character switch" popover
|
||||
userInfoElement.initCharacterSwitchPopover(userData);
|
||||
}, showCharacterElement);
|
||||
|
||||
// set new id for next check
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* user register/settings dialog
|
||||
* user settings/share dialog
|
||||
*/
|
||||
|
||||
define([
|
||||
@@ -12,22 +12,13 @@ define([
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
dialogWizardNavigationClass: 'pf-wizard-navigation', // class for wizard navigation bar
|
||||
|
||||
// select character dialog
|
||||
settingsDialogId: 'pf-settings-dialog', // id for "settings" dialog
|
||||
settingsImageWrapperClass: 'pf-dialog-image-wrapper', // class for image wrapper (animated)
|
||||
settingsImageInfoClass: 'pf-dialog-character-info', // class for character info layer (visible on hover)
|
||||
settingsMainClass: 'pf-dialog-character-main', // class for main character highlighting
|
||||
settingsNavigationButtonClass: 'pf-dialog-navigation-button', // class for all navigation buttons
|
||||
settingsFinishButtonClass: 'pf-dialog-finish-button', // class for "finish" button
|
||||
settingsPrevButtonClass: 'pf-dialog-prev-button', // class for "prev" button
|
||||
settingsNextButtonClass: 'pf-dialog-next-button', // class for "next" button
|
||||
settingsCloneApiRowClass: 'pf-dialog-api-row', // class for form row with API data (will be cloned)
|
||||
settingsCloneRowButtonClass: 'pf-dialog-clone-button', // class for clone button (api row)
|
||||
settingsDeleteRowButtonClass: 'pf-dialog-delete-button', // class for delete button (api row)
|
||||
settingsAccountContainerId: 'pf-settings-dialog-account', // id for the "account" container
|
||||
settingsShareContainerId: 'pf-settings-dialog-share', // id for the "share" container
|
||||
|
||||
// captcha
|
||||
captchaKeyUpdateAccount: 'SESSION.CAPTCHA.ACCOUNT.UPDATE', // key for captcha reason
|
||||
captchaImageWrapperId: 'pf-dialog-captcha-wrapper', // id for "captcha image" wrapper
|
||||
captchaImageId: 'pf-dialog-captcha-image', // id for "captcha image"
|
||||
|
||||
@@ -35,80 +26,9 @@ define([
|
||||
icon: {
|
||||
size: 'fa-2x'
|
||||
}
|
||||
},
|
||||
|
||||
// character status
|
||||
settingsCharacterStatusOwn : { // "own" -> my characters
|
||||
name: 'own',
|
||||
class: 'pf-user-status-own'
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* get active Tab link element for a dialog
|
||||
* @param dialog
|
||||
* @returns {JQuery|*}
|
||||
*/
|
||||
var getActiveTabElement = function(dialog){
|
||||
var navigationBarElement = $(dialog).find('.' + config.dialogWizardNavigationClass);
|
||||
var currentActiveTab = navigationBarElement.find('li.active');
|
||||
|
||||
return currentActiveTab;
|
||||
};
|
||||
|
||||
/**
|
||||
* init popovers in dialog
|
||||
* @param dialogElement
|
||||
*/
|
||||
var initPopover = function(dialogElement){
|
||||
|
||||
var apiCloneButtons = dialogElement.find('.' + config.settingsCloneRowButtonClass);
|
||||
var apiDeleteButtons = dialogElement.find('.' + config.settingsDeleteRowButtonClass);
|
||||
|
||||
var confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'left',
|
||||
btnCancelClass: 'btn btn-sm btn-default',
|
||||
btnCancelLabel: 'cancel',
|
||||
btnCancelIcon: 'fa fa-fw fa-ban'
|
||||
};
|
||||
|
||||
// add API key row
|
||||
var cloneConfirmationSettings = $.extend({
|
||||
title: 'Add additional key',
|
||||
btnOkClass: 'btn btn-sm btn-success',
|
||||
btnOkLabel: 'confirm',
|
||||
btnOkIcon: 'fa fa-fw fa-check',
|
||||
onConfirm: function(e) {
|
||||
var cloneRow = dialogElement.find('.' + config.settingsCloneApiRowClass).last();
|
||||
var newApiRow = cloneRow.clone();
|
||||
|
||||
newApiRow.find('.form-group').removeClass('has-success has-error');
|
||||
newApiRow.find('input').val('');
|
||||
cloneRow.after(newApiRow);
|
||||
|
||||
// init new row with popups
|
||||
initPopover(dialogElement);
|
||||
}
|
||||
}, confirmationSettings);
|
||||
|
||||
// delete API key row
|
||||
var deleteConfirmationSettings = $.extend({
|
||||
title: 'Delete key',
|
||||
btnOkClass: 'btn btn-sm btn-danger',
|
||||
btnOkLabel: 'delete',
|
||||
btnOkIcon: 'fa fa-fw fa-close',
|
||||
onConfirm: function(e, target) {
|
||||
$(target).parents('.row').remove();
|
||||
}
|
||||
}, confirmationSettings);
|
||||
|
||||
$(apiCloneButtons).confirmation(cloneConfirmationSettings);
|
||||
$(apiDeleteButtons).confirmation(deleteConfirmationSettings);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* show "register/settings" dialog
|
||||
* @param options
|
||||
@@ -122,213 +42,124 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
var reroutePath = '';
|
||||
|
||||
// check navigation buttons and show/hide them
|
||||
var checkNavigationButton = function(dialog){
|
||||
var navigationBarElement = $(dialog).find('.' + config.dialogWizardNavigationClass);
|
||||
var currentActiveTab = navigationBarElement.find('li.active');
|
||||
|
||||
var hidePrevButton = currentActiveTab.prevAll().length > 0 ? false : true;
|
||||
var hideNextButton = currentActiveTab.nextAll().length > 0 ? false : true;
|
||||
|
||||
if(hidePrevButton){
|
||||
$('.' + config.settingsPrevButtonClass).hide();
|
||||
}else{
|
||||
$('.' + config.settingsPrevButtonClass).show();
|
||||
}
|
||||
|
||||
if(hideNextButton){
|
||||
$('.' + config.settingsNextButtonClass).hide();
|
||||
}else{
|
||||
$('.' + config.settingsNextButtonClass).show();
|
||||
}
|
||||
};
|
||||
|
||||
requirejs(['text!templates/dialog/settings.html', 'mustache'], function(template, Mustache) {
|
||||
|
||||
// if this is a new registration there is no API key -> fake an empty API to make fields visible
|
||||
if(options.register === 1){
|
||||
Init.currentUserData = {};
|
||||
Init.currentUserData.api = [{
|
||||
keyId: '',
|
||||
vCode: ''
|
||||
}];
|
||||
}else if(Init.currentUserData.api === undefined){
|
||||
Init.currentUserData.api = [{
|
||||
keyId: '',
|
||||
vCode: ''
|
||||
}];
|
||||
}
|
||||
|
||||
var data = {
|
||||
id: config.settingsDialogId,
|
||||
register: options.register === 1 ? 1 : 0,
|
||||
invite : options.invite === 1 ? 1 : 0,
|
||||
navigationClass: config.dialogWizardNavigationClass,
|
||||
settingsAccountContainerId: config.settingsAccountContainerId,
|
||||
settingsShareContainerId: config.settingsShareContainerId,
|
||||
userData: Init.currentUserData,
|
||||
cloneApiRowClass: config.settingsCloneApiRowClass,
|
||||
cloneRowButtonClass: config.settingsCloneRowButtonClass,
|
||||
deleteRowButtonClass: config.settingsDeleteRowButtonClass,
|
||||
captchaImageWrapperId: config.captchaImageWrapperId,
|
||||
captchaImageId: config.captchaImageId,
|
||||
formErrorContainerClass: Util.config.formErrorContainerClass,
|
||||
formWarningContainerClass: Util.config.formWarningContainerClass
|
||||
ccpImageServer: Init.url.ccpImageServer
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, data);
|
||||
|
||||
var selectCharacterDialog = bootbox.dialog({
|
||||
title: options.register === 1 ? 'Registration' : 'Account settings',
|
||||
var accountSettingsDialog = bootbox.dialog({
|
||||
title: 'Account settings',
|
||||
message: content,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'finish',
|
||||
className: ['btn-success', 'pull-right', config.settingsFinishButtonClass].join(' '),
|
||||
callback: function(e){
|
||||
|
||||
if(options.register === 1){
|
||||
if(reroutePath !== undefined){
|
||||
// root user to main app
|
||||
window.location = reroutePath;
|
||||
}
|
||||
}else{
|
||||
// close dialog
|
||||
return true;
|
||||
}
|
||||
}
|
||||
label: 'cancel',
|
||||
className: 'btn-default'
|
||||
},
|
||||
prev: {
|
||||
label: '<i class="fa fa-fw fa-angle-left"></i>back',
|
||||
className: ['btn-default', 'pull-left', config.settingsNavigationButtonClass, config.settingsPrevButtonClass].join(' '),
|
||||
callback: function (e) {
|
||||
var currentActiveTab = getActiveTabElement(this);
|
||||
currentActiveTab.removeClass('finished');
|
||||
currentActiveTab.prev('li').find('a').tab('show');
|
||||
success: {
|
||||
label: '<i class="fa fa-check fa-fw"></i> save',
|
||||
className: 'btn-success',
|
||||
callback: function() {
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
next: {
|
||||
label: 'next<i class="fa fa-fw fa-angle-right"></i>',
|
||||
className: ['btn-primary', 'pull-right', config.settingsNavigationButtonClass, config.settingsNextButtonClass].join(' '),
|
||||
callback: function (e) {
|
||||
var dialogElement = $(this);
|
||||
var currentActiveTab = getActiveTabElement(dialogElement);
|
||||
var currentActiveLink = currentActiveTab.find('a');
|
||||
var tabContentElement = $(currentActiveLink.attr('href'));
|
||||
var form = tabContentElement.find('form');
|
||||
|
||||
var changeTab = function(){
|
||||
currentActiveTab.addClass('finished');
|
||||
currentActiveLink.removeClass('btn-danger btn-default');
|
||||
currentActiveLink.addClass('btn-primary');
|
||||
|
||||
currentActiveTab.next('li').find('a').tab('show');
|
||||
};
|
||||
// get the current active form
|
||||
var form = $('#' + config.settingsDialogId).find('form').filter(':visible');
|
||||
|
||||
// validate form
|
||||
form.validator('validate');
|
||||
|
||||
// check weather the form is valid
|
||||
var formValid = form.isValidForm();
|
||||
|
||||
if(!formValid){
|
||||
currentActiveTab.removeClass('disabled');
|
||||
currentActiveLink.removeClass('btn-default btn-primary');
|
||||
currentActiveLink.addClass('btn-danger');
|
||||
}else{
|
||||
if(formValid === true){
|
||||
var tabFormValues = form.getFormValues();
|
||||
|
||||
if(! $.isEmptyObject(tabFormValues) ){
|
||||
// send Tab data and store values
|
||||
var requestData = {
|
||||
formData: tabFormValues
|
||||
};
|
||||
|
||||
// send Tab data and store values
|
||||
var requestData = {
|
||||
settingsData: tabFormValues
|
||||
};
|
||||
accountSettingsDialog.find('.modal-content').showLoadingAnimation();
|
||||
|
||||
selectCharacterDialog.find('.modal-content').showLoadingAnimation();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.saveUserConfig,
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData){
|
||||
accountSettingsDialog.find('.modal-content').hideLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.saveUserConfig,
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData){
|
||||
selectCharacterDialog.find('.modal-content').hideLoadingAnimation();
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all data)
|
||||
if(
|
||||
responseData.error &&
|
||||
responseData.error.length > 0
|
||||
){
|
||||
form.showFormMessage(responseData.error);
|
||||
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all data)
|
||||
if(
|
||||
responseData.error &&
|
||||
responseData.error.length > 0
|
||||
){
|
||||
form.showFormMessage(responseData.error);
|
||||
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount', function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}else{
|
||||
// store new/updated user data -> update head
|
||||
if(responseData.userData){
|
||||
Util.setCurrentUserData(responseData.userData);
|
||||
}
|
||||
|
||||
// store reroute path after registration finished
|
||||
if(responseData.reroute){
|
||||
reroutePath = responseData.reroute;
|
||||
}
|
||||
|
||||
dialogElement.find('.alert').velocity('transition.slideDownOut',{
|
||||
duration: 500,
|
||||
complete: function(){
|
||||
// switch tab
|
||||
changeTab();
|
||||
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount', function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Util.showNotify({title: 'Account saved', type: 'success'});
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
selectCharacterDialog.find('.modal-content').hideLoadingAnimation();
|
||||
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': saveAccount', text: reason, type: 'error'});
|
||||
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all)
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount', function(){
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyUpdateAccount, function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}else{
|
||||
// store new/updated user data -> update head
|
||||
if(responseData.userData){
|
||||
Util.setCurrentUserData(responseData.userData);
|
||||
}
|
||||
|
||||
// check for DB errors
|
||||
if(jqXHR.status === 500){
|
||||
|
||||
if(jqXHR.responseText){
|
||||
var errorObj = $.parseJSON(jqXHR.responseText);
|
||||
|
||||
if(
|
||||
errorObj.error &&
|
||||
errorObj.error.length > 0
|
||||
){
|
||||
form.showFormMessage(errorObj.error);
|
||||
}
|
||||
form.find('.alert').velocity('transition.slideDownOut',{
|
||||
duration: 500,
|
||||
complete: function(){
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyUpdateAccount, function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if( options.register !== 1 ){
|
||||
$(document).setProgramStatus('problem');
|
||||
}
|
||||
Util.showNotify({title: 'Account saved', type: 'success'});
|
||||
|
||||
// close dialog/menu
|
||||
$(document).trigger('pf:closeMenu', [{}]);
|
||||
accountSettingsDialog.modal('hide');
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
accountSettingsDialog.find('.modal-content').hideLoadingAnimation();
|
||||
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': saveAccountSettings', text: reason, type: 'error'});
|
||||
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all)
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyUpdateAccount, function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
|
||||
}else{
|
||||
// no request required -> change tab
|
||||
changeTab();
|
||||
}
|
||||
// check for DB errors
|
||||
if(jqXHR.status === 500){
|
||||
|
||||
if(jqXHR.responseText){
|
||||
var errorObj = $.parseJSON(jqXHR.responseText);
|
||||
|
||||
if(
|
||||
errorObj.error &&
|
||||
errorObj.error.length > 0
|
||||
){
|
||||
form.showFormMessage(errorObj.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).setProgramStatus('problem');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -338,163 +169,42 @@ define([
|
||||
});
|
||||
|
||||
// after modal is shown =======================================================================
|
||||
selectCharacterDialog.on('shown.bs.modal', function(e) {
|
||||
accountSettingsDialog.on('shown.bs.modal', function(e) {
|
||||
|
||||
var dialogElement = $(this);
|
||||
var tabLinkElements = dialogElement.find('a[data-toggle="tab"]');
|
||||
var form = dialogElement.find('form');
|
||||
|
||||
// request captcha image and show
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount');
|
||||
var captchaImageWrapperContainer = $('#' + config.captchaImageWrapperId);
|
||||
captchaImageWrapperContainer.showCaptchaImage(config.captchaKeyUpdateAccount);
|
||||
|
||||
// init captcha refresh button
|
||||
captchaImageWrapperContainer.find('i').on('click', function(){
|
||||
captchaImageWrapperContainer.showCaptchaImage(config.captchaKeyUpdateAccount);
|
||||
});
|
||||
|
||||
|
||||
// init dialog tooltips
|
||||
dialogElement.initTooltips();
|
||||
|
||||
// init popups
|
||||
initPopover( dialogElement );
|
||||
|
||||
// init form validation
|
||||
form.initFormValidation();
|
||||
});
|
||||
|
||||
// on Tab switch ======================================================================
|
||||
tabLinkElements.on('shown.bs.tab', function (e) {
|
||||
|
||||
// check navigation buttons (hide/show)
|
||||
checkNavigationButton(dialogElement);
|
||||
|
||||
$(e.target).removeClass('disabled');
|
||||
|
||||
// hide finish button
|
||||
dialogElement.find('.' + config.settingsFinishButtonClass).hide();
|
||||
|
||||
|
||||
if($(e.target).text() < $(e.relatedTarget).text()){
|
||||
var currentActiveTab = getActiveTabElement(dialogElement);
|
||||
var nextTabElements = currentActiveTab.nextAll();
|
||||
|
||||
// disable all next tabs
|
||||
currentActiveTab.removeClass('finished');
|
||||
nextTabElements.removeClass('finished');
|
||||
nextTabElements.find('a').removeClass('btn-primary btn-danger').addClass('btn-default disabled');
|
||||
}
|
||||
|
||||
if($(e.target).text() === '3'){
|
||||
|
||||
// load character tab -----------------------------------------------
|
||||
|
||||
requirejs(['text!templates/form/character_panel.html', 'mustache'], function(template, Mustache) {
|
||||
|
||||
// all characters for the current user
|
||||
var characters = Init.currentUserData.characters;
|
||||
// calculate grid class
|
||||
var characterCount = characters.length;
|
||||
var gridClass = ((12 / characterCount) < 4)? 4 : 12 / characterCount ;
|
||||
|
||||
// add character status information for each character
|
||||
var statusInfo = {};
|
||||
statusInfo.class = config.settingsCharacterStatusOwn.class;
|
||||
statusInfo.label = config.settingsCharacterStatusOwn.name;
|
||||
|
||||
var mainCharacter = 0;
|
||||
for(var i = 0; i < characters.length; i++){
|
||||
characters[i].status = statusInfo;
|
||||
|
||||
if(characters[i].isMain === 1){
|
||||
mainCharacter = characters[i].id;
|
||||
}else if(mainCharacter === 0){
|
||||
// mark at least one character as "main" if no main char was found
|
||||
// e.g. first account setup
|
||||
mainCharacter = characters[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
var characterTemplateData = {
|
||||
imageWrapperClass: config.settingsImageWrapperClass,
|
||||
imageInfoClass: config.settingsImageInfoClass,
|
||||
imageWrapperMainClass: config.settingsMainClass,
|
||||
charactersData: characters,
|
||||
gridClass: 'col-sm-' + gridClass,
|
||||
mainCharacter: mainCharacter
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, characterTemplateData);
|
||||
|
||||
var characterForm = dialogElement.find('#pf-dialog-settings-character form');
|
||||
|
||||
// add form HTML
|
||||
characterForm.html(content);
|
||||
|
||||
var imageWrapperElements = dialogElement.find('.' + config.settingsImageWrapperClass);
|
||||
|
||||
// special effects :)
|
||||
imageWrapperElements.velocity('stop').delay(100).velocity('transition.flipBounceXIn', {
|
||||
display: 'inline-block',
|
||||
stagger: 60,
|
||||
drag: true,
|
||||
duration: 400,
|
||||
complete: function(){
|
||||
// init new character tooltips
|
||||
dialogElement.initTooltips();
|
||||
}
|
||||
});
|
||||
|
||||
// Hover effect for character info layer
|
||||
imageWrapperElements.hoverIntent(function(e){
|
||||
var characterInfoElement = $(this).find('.' + config.settingsImageInfoClass);
|
||||
|
||||
characterInfoElement.velocity('finish').velocity({
|
||||
width: ['100%', [ 400, 15 ] ]
|
||||
},{
|
||||
easing: 'easeInSine'
|
||||
});
|
||||
}, function(e){
|
||||
var characterInfoElement = $(this).find('.' + config.settingsImageInfoClass);
|
||||
|
||||
characterInfoElement.velocity('finish').velocity({
|
||||
width: 0
|
||||
},{
|
||||
duration: 150,
|
||||
easing: 'easeInOutSine'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// click event on character image
|
||||
imageWrapperElements.on('click', function(e){
|
||||
var wrapperElement = $(this);
|
||||
var characterId = wrapperElement.data('id');
|
||||
|
||||
// update layout if character is selected
|
||||
if(characterId > 0){
|
||||
// update hidden field with new mainCharacterId
|
||||
dialogElement.find('input[name="mainCharacterId"]').val(characterId);
|
||||
|
||||
imageWrapperElements.removeClass( config.settingsMainClass );
|
||||
wrapperElement.addClass( config.settingsMainClass );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}else if($(e.target).text() === '4'){
|
||||
// show finish button
|
||||
dialogElement.find('.' + config.settingsFinishButtonClass).show();
|
||||
|
||||
// show success message
|
||||
dialogElement.find('h1').velocity('stop').delay(200).velocity('transition.flipBounceXIn', {
|
||||
duration: 500
|
||||
}).delay(100).velocity('callout.pulse');
|
||||
}
|
||||
// events for tab change
|
||||
accountSettingsDialog.find('.navbar a').on('shown.bs.tab', function(e){
|
||||
|
||||
// init "toggle" switches on current active tab
|
||||
accountSettingsDialog.find( $(this).attr('href') ).find('input[type="checkbox"]').bootstrapToggle({
|
||||
on: '<i class="fa fa-fw fa-check"></i> Enable',
|
||||
off: 'Disable <i class="fa fa-fw fa-ban"></i>',
|
||||
onstyle: 'success',
|
||||
offstyle: 'warning',
|
||||
width: 90,
|
||||
height: 30
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
@@ -15,6 +15,7 @@ define([
|
||||
deleteAccountId: 'pf-dialog-delete-account', // dialog id
|
||||
|
||||
// captcha
|
||||
captchaKeyDeleteAccount: 'SESSION.CAPTCHA.ACCOUNT.DELETE', // key for captcha reason
|
||||
captchaImageWrapperId: 'pf-dialog-captcha-wrapper' // id for "captcha image" wrapper
|
||||
};
|
||||
|
||||
@@ -82,8 +83,8 @@ define([
|
||||
){
|
||||
form.showFormMessage(responseData.error);
|
||||
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('deleteAccount', function(){
|
||||
form.find('[name="captcha"], [name="password"]').resetFormFields();
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyDeleteAccount, function(){
|
||||
form.find('[name="captcha"]').resetFormFields();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ define([
|
||||
// after modal is shown =======================================================================
|
||||
deleteAccountDialog.on('shown.bs.modal', function(e) {
|
||||
// request captcha image and show
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('deleteAccount');
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyDeleteAccount);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -642,7 +642,6 @@ define([
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(usersData);
|
||||
|
||||
var userDataTable = userTable.dataTable( {
|
||||
pageLength: 20,
|
||||
@@ -670,7 +669,7 @@ console.log(usersData);
|
||||
data: 'log.ship',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
return '<img src="' + Init.url.ccpImageServer + 'Render/' + data.id + '_32.png" />';
|
||||
return '<img src="' + Init.url.ccpImageServer + 'Render/' + data.typeId + '_32.png" />';
|
||||
}
|
||||
}
|
||||
},{
|
||||
@@ -736,6 +735,16 @@ console.log(usersData);
|
||||
}
|
||||
},{
|
||||
targets: 7,
|
||||
title: 'station',
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
data: 'log.station',
|
||||
render: {
|
||||
_: 'name',
|
||||
sort: 'name'
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -754,7 +763,7 @@ console.log(usersData);
|
||||
});
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
targets: 9,
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
|
||||
@@ -20,7 +20,7 @@ define([
|
||||
dialogMapSettingsContainerId: 'pf-map-dialog-settings', // id for the "settings" container
|
||||
dialogMapDownloadContainerId: 'pf-map-dialog-download', // id for the "download" container
|
||||
|
||||
userSelectId: 'pf-map-dialog-user-select', // id for "user" select
|
||||
characterSelectId: 'pf-map-dialog-character-select', // id for "character" select
|
||||
corporationSelectId: 'pf-map-dialog-corporation-select', // id for "corporation" select
|
||||
allianceSelectId: 'pf-map-dialog-alliance-select', // id for "alliance" select
|
||||
|
||||
@@ -100,7 +100,7 @@ define([
|
||||
contentEditMap = $(contentEditMap);
|
||||
|
||||
// current map access info
|
||||
var accessUser = [];
|
||||
var accessCharacter = [];
|
||||
var accessCorporation = [];
|
||||
var accessAlliance = [];
|
||||
|
||||
@@ -112,7 +112,7 @@ define([
|
||||
contentEditMap.find('select[name="scopeId"]').val( mapData.config.scope.id );
|
||||
contentEditMap.find('select[name="typeId"]').val( mapData.config.type.id );
|
||||
|
||||
accessUser = mapData.config.access.user;
|
||||
accessCharacter = mapData.config.access.character;
|
||||
accessCorporation = mapData.config.access.corporation;
|
||||
accessAlliance = mapData.config.access.alliance;
|
||||
}
|
||||
@@ -145,17 +145,17 @@ define([
|
||||
hideDownloadTab: hideDownloadTab,
|
||||
|
||||
// settings tab --------------
|
||||
userSelectId: config.userSelectId,
|
||||
characterSelectId: config.characterSelectId,
|
||||
corporationSelectId: config.corporationSelectId,
|
||||
allianceSelectId: config.allianceSelectId,
|
||||
|
||||
// map access objects --------
|
||||
accessUser: accessUser,
|
||||
accessCharacter: accessCharacter,
|
||||
accessCorporation: accessCorporation,
|
||||
accessAlliance: accessAlliance,
|
||||
|
||||
// access limitations --------
|
||||
maxUser: Init.maxSharedCount.user,
|
||||
maxCharacter: Init.maxSharedCount.character,
|
||||
maxCorporation: Init.maxSharedCount.corporation,
|
||||
maxAlliance: Init.maxSharedCount.alliance,
|
||||
|
||||
@@ -287,7 +287,7 @@ define([
|
||||
// events for tab change
|
||||
mapInfoDialog.find('.navbar a').on('shown.bs.tab', function(e){
|
||||
|
||||
var selectElementUser = mapInfoDialog.find('#' + config.userSelectId);
|
||||
var selectElementCharacter = mapInfoDialog.find('#' + config.characterSelectId);
|
||||
var selectElementCorporation = mapInfoDialog.find('#' + config.corporationSelectId);
|
||||
var selectElementAlliance = mapInfoDialog.find('#' + config.allianceSelectId);
|
||||
|
||||
@@ -295,8 +295,8 @@ define([
|
||||
// "settings" tab
|
||||
initSettingsSelectFields(mapInfoDialog);
|
||||
}else{
|
||||
if( $(selectElementUser).data('select2') !== undefined ){
|
||||
$(selectElementUser).select2('destroy');
|
||||
if( $(selectElementCharacter).data('select2') !== undefined ){
|
||||
$(selectElementCharacter).select2('destroy');
|
||||
}
|
||||
|
||||
if( $(selectElementCorporation).data('select2') !== undefined ){
|
||||
@@ -550,14 +550,14 @@ define([
|
||||
*/
|
||||
var initSettingsSelectFields = function(mapInfoDialog){
|
||||
|
||||
var selectElementUser = mapInfoDialog.find('#' + config.userSelectId);
|
||||
var selectElementCharacter = mapInfoDialog.find('#' + config.characterSelectId);
|
||||
var selectElementCorporation = mapInfoDialog.find('#' + config.corporationSelectId);
|
||||
var selectElementAlliance = mapInfoDialog.find('#' + config.allianceSelectId);
|
||||
|
||||
// init corporation select live search
|
||||
selectElementUser.initAccessSelect({
|
||||
type: 'user',
|
||||
maxSelectionLength: Init.maxSharedCount.user
|
||||
// init character select live search
|
||||
selectElementCharacter.initAccessSelect({
|
||||
type: 'character',
|
||||
maxSelectionLength: Init.maxSharedCount.character
|
||||
});
|
||||
|
||||
// init corporation select live search
|
||||
@@ -575,7 +575,7 @@ define([
|
||||
|
||||
/**
|
||||
* shows the delete map Dialog
|
||||
* @param mapElement
|
||||
* @param mapData
|
||||
*/
|
||||
$.fn.showDeleteMapDialog = function(mapData){
|
||||
|
||||
|
||||
@@ -47,8 +47,6 @@ define([
|
||||
releasesDialog.find('ul.timeline').append(content);
|
||||
}
|
||||
|
||||
// console.log()
|
||||
|
||||
$('.timeline > li').velocity('transition.expandIn', {
|
||||
stagger: 300,
|
||||
duration: 240,
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* sharing settings dialog
|
||||
*/
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox'
|
||||
], function($, Init, Util, Render, bootbox) {
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
// select character dialog
|
||||
sharingDialogId: 'pf-sharing-dialog', // id for "sharing settings" dialog
|
||||
};
|
||||
|
||||
$.fn.showSharingSettingsDialog = function(){
|
||||
|
||||
var sharingDialogElement = $('#' + config.sharingDialogId);
|
||||
if(!sharingDialogElement.is(':visible')){
|
||||
|
||||
var userData = Util.getCurrentUserData();
|
||||
|
||||
if(userData){
|
||||
|
||||
requirejs([
|
||||
'text!templates/dialog/sharing_settings.html',
|
||||
'mustache'
|
||||
], function(templatSharingDialog, Mustache) {
|
||||
|
||||
var data = {
|
||||
id: config.sharingDialogId,
|
||||
ccpImageServer: Init.url.ccpImageServer,
|
||||
userData: userData
|
||||
};
|
||||
|
||||
// render "new map" tab content -------------------------------------------
|
||||
var contentSharingDialog = Mustache.render(templatSharingDialog, data);
|
||||
|
||||
var sharingSettingsDialog = bootbox.dialog({
|
||||
title: 'Sharing settings',
|
||||
message: $(contentSharingDialog),
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'cancel',
|
||||
className: 'btn-default'
|
||||
},
|
||||
success: {
|
||||
label: '<i class="fa fa-check fa-fw"></i> save',
|
||||
className: 'btn-success',
|
||||
callback: function() {
|
||||
|
||||
var form = $('#' + config.sharingDialogId).find('form');
|
||||
|
||||
var sharingSettingsData = {formData: form.getFormValues()};
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.saveSharingConfig,
|
||||
data: sharingSettingsData,
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
|
||||
if(data.userData !== undefined){
|
||||
// store current user data global (cache)
|
||||
Util.setCurrentUserData(data.userData);
|
||||
|
||||
$(document).trigger('pf:closeMenu', [{}]);
|
||||
$(sharingSettingsDialog).modal('hide');
|
||||
|
||||
// success
|
||||
Util.showNotify({title: 'Sharing settings saved', type: 'success'});
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': shareSettings', text: reason, type: 'warning'});
|
||||
$(document).setProgramStatus('problem');
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// after modal is shown ---------------------------------------------------
|
||||
sharingSettingsDialog.on('shown.bs.modal', function(e) {
|
||||
|
||||
$(this).find('input[type="checkbox"]').bootstrapToggle({
|
||||
on: '<i class="fa fa-fw fa-check"></i> Enable',
|
||||
off: 'Disable <i class="fa fa-fw fa-ban"></i>',
|
||||
onstyle: 'success',
|
||||
offstyle: 'warning',
|
||||
width: 90,
|
||||
height: 30
|
||||
});
|
||||
});
|
||||
});
|
||||
}else{
|
||||
Util.showNotify({title: 'No userData found', type: 'warning'});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -131,7 +131,7 @@ define([
|
||||
|
||||
/**
|
||||
* init a select element as an ajax based "select2" object for Access resources
|
||||
* user (private map), corporation (corp map), alliance (ally map)
|
||||
* character (private map), corporation (corp map), alliance (ally map)
|
||||
* @param options
|
||||
*/
|
||||
$.fn.initAccessSelect = function(options){
|
||||
@@ -162,8 +162,9 @@ define([
|
||||
var previewContent = '';
|
||||
|
||||
switch(options.type){
|
||||
case 'user':
|
||||
previewContent = '<i class="fa fa-lg fa-user"></i>';
|
||||
case 'character':
|
||||
imagePath = Init.url.ccpImageServer + 'Character/' + data.id + '_32.jpg';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
case 'corporation':
|
||||
imagePath = Init.url.ccpImageServer + 'Corporation/' + data.id + '_32.png';
|
||||
|
||||
@@ -150,57 +150,58 @@ define([
|
||||
dataType: 'json'
|
||||
}).done(function(systemGraphsData){
|
||||
|
||||
// create new (hidden) module container
|
||||
var moduleElement = $('<div>', {
|
||||
class: [config.moduleClass, config.systemGraphModuleClass].join(' '),
|
||||
css: {opacity: 0}
|
||||
});
|
||||
|
||||
// insert at the correct position
|
||||
if($(parentElement).children().length === 1){
|
||||
$(parentElement).append(moduleElement);
|
||||
}else{
|
||||
$(parentElement).find('>:first-child').after(moduleElement);
|
||||
}
|
||||
|
||||
// row element
|
||||
var rowElement = $('<div>', {
|
||||
class: 'row'
|
||||
});
|
||||
moduleElement.append(rowElement);
|
||||
|
||||
$.each(systemGraphsData, function(systemId, graphsData){
|
||||
$.each(graphsData, function(graphKey, graphData){
|
||||
|
||||
var colElement = $('<div>', {
|
||||
class: ['col-xs-12', 'col-sm-6', 'col-md-4'].join(' ')
|
||||
});
|
||||
|
||||
var headlineElement = $('<h5>').text( getInfoForGraph(graphKey, 'headline') );
|
||||
|
||||
colElement.append(headlineElement);
|
||||
|
||||
var graphElement = $('<div>', {
|
||||
class: config.systemGraphClass
|
||||
});
|
||||
|
||||
colElement.append(graphElement);
|
||||
|
||||
rowElement.append(colElement);
|
||||
initGraph(graphElement, graphKey, graphData, eventLine);
|
||||
if(systemGraphsData.length > 0){
|
||||
// create new (hidden) module container
|
||||
var moduleElement = $('<div>', {
|
||||
class: [config.moduleClass, config.systemGraphModuleClass].join(' '),
|
||||
css: {opacity: 0}
|
||||
});
|
||||
});
|
||||
|
||||
moduleElement.append($('<div>', {
|
||||
css: {'clear': 'both'}
|
||||
}));
|
||||
// insert at the correct position
|
||||
if($(parentElement).children().length === 1){
|
||||
$(parentElement).append(moduleElement);
|
||||
}else{
|
||||
$(parentElement).find('>:first-child').after(moduleElement);
|
||||
}
|
||||
|
||||
// show module
|
||||
moduleElement.velocity('transition.slideDownIn', {
|
||||
duration: Init.animationSpeed.mapModule,
|
||||
delay: Init.animationSpeed.mapModule
|
||||
});
|
||||
// row element
|
||||
var rowElement = $('<div>', {
|
||||
class: 'row'
|
||||
});
|
||||
moduleElement.append(rowElement);
|
||||
|
||||
$.each(systemGraphsData, function(systemId, graphsData){
|
||||
$.each(graphsData, function(graphKey, graphData){
|
||||
|
||||
var colElement = $('<div>', {
|
||||
class: ['col-xs-12', 'col-sm-6', 'col-md-4'].join(' ')
|
||||
});
|
||||
|
||||
var headlineElement = $('<h5>').text( getInfoForGraph(graphKey, 'headline') );
|
||||
|
||||
colElement.append(headlineElement);
|
||||
|
||||
var graphElement = $('<div>', {
|
||||
class: config.systemGraphClass
|
||||
});
|
||||
|
||||
colElement.append(graphElement);
|
||||
|
||||
rowElement.append(colElement);
|
||||
initGraph(graphElement, graphKey, graphData, eventLine);
|
||||
});
|
||||
});
|
||||
|
||||
moduleElement.append($('<div>', {
|
||||
css: {'clear': 'both'}
|
||||
}));
|
||||
|
||||
// show module
|
||||
moduleElement.velocity('transition.slideDownIn', {
|
||||
duration: Init.animationSpeed.mapModule,
|
||||
delay: Init.animationSpeed.mapModule
|
||||
});
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': System graph data', text: reason, type: 'warning'});
|
||||
|
||||
@@ -333,34 +333,34 @@ define([
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
dataType: 'jsonp'
|
||||
}).done(function(kbData){
|
||||
dataType: 'json'
|
||||
}).done(function(kbData) {
|
||||
|
||||
// the API wont return more than 200KMs ! - remember last bar block with complete KM information
|
||||
var lastCompleteDiffHourData = 0;
|
||||
|
||||
|
||||
// loop kills and count kills by hour
|
||||
for(var i = 0; i < kbData.length; i++){
|
||||
for (var i = 0; i < kbData.length; i++) {
|
||||
var killmailData = kbData[i];
|
||||
|
||||
var killDate = getDateObjectByTimeString(killmailData.killTime);
|
||||
|
||||
// get time diff
|
||||
var timeDiffMin = Math.round( ( serverDate - killDate ) / 1000 / 60 );
|
||||
var timeDiffHour = Math.round( timeDiffMin / 60 );
|
||||
var timeDiffMin = Math.round(( serverDate - killDate ) / 1000 / 60);
|
||||
var timeDiffHour = Math.round(timeDiffMin / 60);
|
||||
|
||||
// update chart data
|
||||
if(chartData[timeDiffHour]){
|
||||
if (chartData[timeDiffHour]) {
|
||||
chartData[timeDiffHour].kills++;
|
||||
|
||||
// add kill mail data
|
||||
if(chartData[timeDiffHour].killmails === undefined){
|
||||
if (chartData[timeDiffHour].killmails === undefined) {
|
||||
chartData[timeDiffHour].killmails = [];
|
||||
}
|
||||
chartData[timeDiffHour].killmails.push(killmailData);
|
||||
|
||||
if(timeDiffHour > lastCompleteDiffHourData){
|
||||
if (timeDiffHour > lastCompleteDiffHourData) {
|
||||
lastCompleteDiffHourData = timeDiffHour;
|
||||
}
|
||||
}
|
||||
@@ -368,7 +368,7 @@ define([
|
||||
}
|
||||
|
||||
// remove empty chart Data
|
||||
if(kbData.length >= maxKillmailCount){
|
||||
if (kbData.length >= maxKillmailCount) {
|
||||
chartData = chartData.splice(0, lastCompleteDiffHourData + 1);
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ define([
|
||||
cache.systemKillsGraphData[cacheKey].count = kbData.length;
|
||||
|
||||
// draw table
|
||||
drawGraph( cache.systemKillsGraphData[cacheKey] );
|
||||
drawGraph(cache.systemKillsGraphData[cacheKey]);
|
||||
|
||||
// show killmail information
|
||||
showKillmails(moduleElement, cache.systemKillsGraphData[cacheKey]);
|
||||
|
||||
@@ -1634,6 +1634,10 @@ define([
|
||||
// submit all fields within a table row
|
||||
var formFields = rowElement.find('.editable');
|
||||
|
||||
// the "toggle" makes sure to take care about open editable fields (e.g. description)
|
||||
// otherwise, changes would not be submitted in this field (not necessary)
|
||||
formFields.editable('toggle');
|
||||
|
||||
// submit all xEditable fields
|
||||
formFields.editable('submit', {
|
||||
url: Init.path.saveSignatureData,
|
||||
|
||||
@@ -317,15 +317,17 @@ define([
|
||||
|
||||
/**
|
||||
* init form elements for validation (bootstrap3 validation)
|
||||
* @returns {any|JQuery|*}
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.initFormValidation = function(){
|
||||
$.fn.initFormValidation = function(options){
|
||||
options = (typeof options === 'undefined')? {} : options;
|
||||
|
||||
return this.each(function(){
|
||||
var form = $(this);
|
||||
|
||||
// init form validation
|
||||
form.validator();
|
||||
form.validator(options);
|
||||
|
||||
// validation event listener
|
||||
form.on('valid.bs.validator', function(validatorObj){
|
||||
@@ -342,7 +344,6 @@ define([
|
||||
inputGroup.removeClass('has-success').addClass('has-error');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -545,6 +546,84 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* add character switch popover
|
||||
* @param userData
|
||||
*/
|
||||
$.fn.initCharacterSwitchPopover = function(userData){
|
||||
var elements = $(this);
|
||||
var eventNamespace = 'hideCharacterPopup';
|
||||
|
||||
requirejs(['text!templates/tooltip/character_switch.html', 'mustache'], function (template, Mustache) {
|
||||
|
||||
var data = {
|
||||
routes: Init.routes,
|
||||
userData: userData,
|
||||
otherCharacters: $.grep( userData.characters, function( character ) {
|
||||
// exclude current active character
|
||||
return character.id !== userData.character.id;
|
||||
})
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, data);
|
||||
|
||||
return elements.each(function() {
|
||||
var element = $(this);
|
||||
|
||||
// destroy "popover" and remove "click" event for animation
|
||||
element.popover('destroy').off();
|
||||
|
||||
// init popover and add specific class to it (for styling)
|
||||
element.popover({
|
||||
html: true,
|
||||
title: 'select character',
|
||||
trigger: 'click',
|
||||
placement: 'bottom',
|
||||
content: content,
|
||||
animation: false
|
||||
}).data('bs.popover').tip().addClass('pf-character-info-popover');
|
||||
|
||||
element.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var easeEffect = $(this).attr('data-easein');
|
||||
var popover = $(this).data('bs.popover').tip();
|
||||
var velocityOptions = {
|
||||
duration: CCP.isInGameBrowser() ? 0 : Init.animationSpeed.dialogEvents
|
||||
};
|
||||
|
||||
switch(easeEffect){
|
||||
case 'shake':
|
||||
case 'pulse':
|
||||
case 'tada':
|
||||
case 'flash':
|
||||
case 'bounce':
|
||||
case 'swing':
|
||||
popover.velocity('callout.' + easeEffect, velocityOptions);
|
||||
break;
|
||||
default:
|
||||
popover.velocity('transition.' + easeEffect, velocityOptions);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// hide popup on clicking "somewhere" outside
|
||||
$('body').off('click.' + eventNamespace).on('click.' + eventNamespace, function (e) {
|
||||
|
||||
//the 'is' for buttons that trigger popups
|
||||
//the 'has' for icons within a button that triggers a popup
|
||||
if (
|
||||
!$(element).is(e.target) &&
|
||||
$(element).has(e.target).length === 0 &&
|
||||
$('.popover').has(e.target).length === 0
|
||||
){
|
||||
$(element).popover('hide');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* add a wormhole tooltip with wh specific data to elements
|
||||
* @param tooltipData
|
||||
@@ -575,7 +654,6 @@ define([
|
||||
var popover = element.data('bs.popover');
|
||||
popover.options.content = content;
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1129,7 +1207,6 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
var getSystemEffectTable = function(data){
|
||||
|
||||
var table = '';
|
||||
|
||||
if(data.length > 0){
|
||||
|
||||
128
js/lib/validator.min.js
vendored
128
js/lib/validator.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -45,7 +45,7 @@ requirejs.config({
|
||||
hoverIntent: 'lib/jquery.hoverIntent.minified', // v1.8.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
|
||||
fullScreen: 'lib/jquery.fullscreen.min', // v0.5.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
|
||||
select2: 'lib/select2.min', // v4.0.0 Drop Down customization - https://select2.github.io/
|
||||
validator: 'lib/validator.min', // v0.7.2 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
|
||||
validator: 'lib/validator.min', // v0.10.1 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
|
||||
lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', // v1.5.1 SVG line animation plugin - http://lazylinepainter.info/
|
||||
blueImpGallery: 'lib/blueimp-gallery', // v2.15.2 Image Gallery - https://github.com/blueimp/Gallery/
|
||||
blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery
|
||||
|
||||
@@ -16,6 +16,7 @@ define(['jquery'], function($) {
|
||||
logOut: 'api/user/logOut', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
getUserData: 'api/user/getData', // ajax URL - get user data
|
||||
saveSharingConfig: 'api/user/saveSharingConfig', // ajax URL - save "sharing settings" dialog
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
// access API
|
||||
|
||||
@@ -83,6 +83,7 @@ define([
|
||||
autoWidth: false,
|
||||
hover: false,
|
||||
pageLength: 15,
|
||||
lengthMenu: [[10, 15, 25, 50, 50], [10, 15, 25, 50, 50]],
|
||||
data: logData, // load cached logs (if available)
|
||||
language: {
|
||||
emptyTable: 'No entries',
|
||||
|
||||
@@ -84,54 +84,6 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
// login buttons ------------------------------------------------
|
||||
var loginForm = $('#' + config.loginFormId);
|
||||
|
||||
loginForm.on('submit', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var loginFormMessageContainer = $('#' + config.loginMessageContainerId);
|
||||
|
||||
// validate form
|
||||
loginForm.validator('validate');
|
||||
|
||||
// check weather the form is valid
|
||||
var formValid = loginForm.isValidForm();
|
||||
|
||||
if(formValid === true){
|
||||
|
||||
// show splash overlay
|
||||
$('.' + config.splashOverlayClass).showSplashOverlay(function(){
|
||||
|
||||
var loginData = {loginData: loginForm.getFormValues()};
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.logIn,
|
||||
data: loginData,
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
// login error
|
||||
if(data.error !== undefined){
|
||||
$('.' + config.splashOverlayClass).hideSplashOverlay();
|
||||
loginFormMessageContainer.showMessage({title: 'Login failed', text: ' Invalid username or password', type: 'error'});
|
||||
|
||||
}else if(data.reroute !== undefined){
|
||||
window.location = data.reroute;
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
$('.' + config.splashOverlayClass).hideSplashOverlay();
|
||||
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': login', text: reason, type: 'error'});
|
||||
|
||||
// show Form message
|
||||
loginFormMessageContainer.showMessage({title: 'Login failed', text: ' internal server error', type: 'error'});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// releases -----------------------------------------------------
|
||||
$('.' + config.navigationVersionLinkClass).on('click', function(e){
|
||||
$.fn.releasesDialog();
|
||||
|
||||
@@ -602,12 +602,12 @@ define([
|
||||
system.attr('data-mapid', parseInt(mapContainer.data('id')));
|
||||
|
||||
// locked system
|
||||
if( Boolean( system.data( 'locked') ) !== Boolean( parseInt( data.locked ) )){
|
||||
if( Boolean( system.data( 'locked') ) !== data.locked ){
|
||||
system.toggleLockSystem(false, {hideNotification: true, hideCounter: true, map: map});
|
||||
}
|
||||
|
||||
// rally system
|
||||
if( Boolean( system.data( 'rally') ) !== Boolean( parseInt( data.rally ) )){
|
||||
if( Boolean( system.data( 'rally') ) !== data.rally ){
|
||||
system.toggleRallyPoint(false, {hideNotification: true, hideCounter: true});
|
||||
}
|
||||
|
||||
@@ -3099,12 +3099,10 @@ define([
|
||||
// this is restricted to IGB-usage! CharacterLog data is always set through the IGB
|
||||
// ->this prevent adding the same system multiple times, if a user is online with IGB AND OOG
|
||||
if(
|
||||
CCP.isInGameBrowser() === true &&
|
||||
currentUserOnMap === false &&
|
||||
currentCharacterLog &&
|
||||
mapTracking
|
||||
){
|
||||
|
||||
// add new system to the map
|
||||
var requestData = {
|
||||
systemData: {
|
||||
@@ -3344,6 +3342,15 @@ define([
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* removes a map instance from local cache
|
||||
* @param mapId
|
||||
*/
|
||||
var clearMapInstance = function(mapId){
|
||||
if(typeof activeInstances[mapId] === 'object'){
|
||||
delete activeInstances[mapId];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* get a new jsPlumb map instance or or get a cached one for update
|
||||
@@ -3583,4 +3590,8 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
clearMapInstance: clearMapInstance
|
||||
};
|
||||
|
||||
});
|
||||
@@ -39,14 +39,26 @@ define([
|
||||
// map init load static data =======================================================
|
||||
$.getJSON( Init.path.initMap, function( initData ) {
|
||||
|
||||
Init.timer = initData.timer;
|
||||
Init.mapTypes = initData.mapTypes;
|
||||
Init.mapScopes = initData.mapScopes;
|
||||
Init.connectionScopes = initData.connectionScopes;
|
||||
Init.systemStatus = initData.systemStatus;
|
||||
Init.systemType = initData.systemType;
|
||||
Init.characterStatus = initData.characterStatus;
|
||||
Init.maxSharedCount = initData.maxSharedCount;
|
||||
|
||||
if( initData.error.length > 0 ){
|
||||
for(var i = 0; i < initData.error.length; i++){
|
||||
Util.showNotify({
|
||||
title: initData.error[i].title,
|
||||
text: initData.error[i].message,
|
||||
type: initData.error[i].type
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Init.timer = initData.timer;
|
||||
Init.mapTypes = initData.mapTypes;
|
||||
Init.mapScopes = initData.mapScopes;
|
||||
Init.connectionScopes = initData.connectionScopes;
|
||||
Init.systemStatus = initData.systemStatus;
|
||||
Init.systemType = initData.systemType;
|
||||
Init.characterStatus = initData.characterStatus;
|
||||
Init.maxSharedCount = initData.maxSharedCount;
|
||||
Init.routes = initData.routes;
|
||||
|
||||
// init tab change observer, Once the timers are available
|
||||
Page.initTabChangeObserver();
|
||||
@@ -168,14 +180,7 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
|
||||
// clear both main update request trigger timer
|
||||
clearUpdateTimeouts();
|
||||
|
||||
var reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
$(document).trigger('pf:shutdown', {reason: reason});
|
||||
});
|
||||
}).fail(handleAjaxErrorResponse);
|
||||
};
|
||||
|
||||
// ping for user data update =======================================================
|
||||
@@ -258,14 +263,35 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
}).fail(handleAjaxErrorResponse);
|
||||
|
||||
// clear both main update request trigger timer
|
||||
clearUpdateTimeouts();
|
||||
};
|
||||
|
||||
var reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
$(document).trigger('pf:shutdown', {reason: reason});
|
||||
});
|
||||
/**
|
||||
* Ajax error response handler function for main-ping functions
|
||||
* @param jqXHR
|
||||
* @param status
|
||||
* @param error
|
||||
*/
|
||||
var handleAjaxErrorResponse = function(jqXHR, status, error){
|
||||
// clear both main update request trigger timer
|
||||
clearUpdateTimeouts();
|
||||
|
||||
var reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
var errorData = [];
|
||||
|
||||
if(jqXHR.responseText){
|
||||
var errorObj = $.parseJSON(jqXHR.responseText);
|
||||
|
||||
if(
|
||||
errorObj.error &&
|
||||
errorObj.error.length > 0
|
||||
){
|
||||
errorData = errorObj.error;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).trigger('pf:shutdown', {reason: reason, error: errorData});
|
||||
|
||||
};
|
||||
|
||||
@@ -287,7 +313,6 @@ define([
|
||||
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -2,6 +2,7 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/map',
|
||||
'app/counter',
|
||||
'app/ui/system_info',
|
||||
'app/ui/system_graph',
|
||||
@@ -9,9 +10,8 @@ define([
|
||||
'app/ui/system_route',
|
||||
'app/ui/system_killboard',
|
||||
'datatablesTableTools',
|
||||
'datatablesResponsive',
|
||||
'app/map/map'
|
||||
], function($, Init, Util) {
|
||||
'datatablesResponsive'
|
||||
], function($, Init, Util, Map) {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -259,6 +259,11 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get a fresh tab element
|
||||
* @param options
|
||||
* @returns {*|jQuery|HTMLElement}
|
||||
*/
|
||||
var getTabElement = function(options){
|
||||
|
||||
var tabElement = $('<div>', {
|
||||
@@ -395,7 +400,7 @@ define([
|
||||
// update Tab element -> set data
|
||||
linkElement.updateTabData(options);
|
||||
|
||||
// tabs content ====================================
|
||||
// tabs content =======================================================
|
||||
var contentElement = $('<div>', {
|
||||
id: config.mapTabIdPrefix + parseInt( options.id ),
|
||||
class: [config.mapTabContentClass].join(' ')
|
||||
@@ -405,8 +410,7 @@ define([
|
||||
|
||||
tabContent.append(contentElement);
|
||||
|
||||
|
||||
// init tab =========================================================
|
||||
// init tab ===========================================================
|
||||
linkElement.on('click', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
@@ -482,8 +486,11 @@ define([
|
||||
liElement.remove();
|
||||
contentElement.remove();
|
||||
|
||||
// remove map instance from local cache
|
||||
Map.clearMapInstance(mapId);
|
||||
|
||||
if(findNewActiveTab === true){
|
||||
tabElement.find('a:first').tab('show');
|
||||
tabElement.find('.' + config.mapTabClass + ':not(.pull-right):first a').tab('show');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,6 +547,9 @@ define([
|
||||
// tab element already exists
|
||||
var tabElements = mapModuleElement.getMapTabElements();
|
||||
|
||||
// map ID that is currently active
|
||||
var activeMapId = 0;
|
||||
|
||||
// mapIds that are currently active
|
||||
var activeMapIds = [];
|
||||
|
||||
@@ -582,6 +592,15 @@ define([
|
||||
|
||||
var newTabElements = tabMapElement.addTab(data.config);
|
||||
|
||||
// check if there is any active map yet (this is not the case
|
||||
// when ALL maps are removed AND new maps are added in one call
|
||||
// e.g. character switch)
|
||||
if(tabMapElement.find('.' + config.mapTabClass + '.active:not(.pull-right)').length === 0){
|
||||
tabMapElement.find('.' + config.mapTabClass + ':not(.pull-right):first a').tab('show');
|
||||
|
||||
activeMapId = data.config.id;
|
||||
}
|
||||
|
||||
// set observer for manually triggered map events
|
||||
newTabElements.contentElement.setTabContentObserver();
|
||||
|
||||
@@ -596,7 +615,9 @@ define([
|
||||
});
|
||||
|
||||
// get current active map
|
||||
var activeMapId = Util.getMapModule().getActiveMap().data('id');
|
||||
if(activeMapId === 0){
|
||||
activeMapId = Util.getMapModule().getActiveMap().data('id');
|
||||
}
|
||||
var activeMapData = Util.getCurrentMapData(activeMapId);
|
||||
|
||||
if(activeMapData !== false){
|
||||
|
||||
@@ -14,7 +14,6 @@ define([
|
||||
'text!templates/modules/footer.html',
|
||||
'dialog/notification',
|
||||
'dialog/trust',
|
||||
'dialog/sharing_settings',
|
||||
'dialog/map_info',
|
||||
'dialog/account_settings',
|
||||
'dialog/manual',
|
||||
@@ -143,13 +142,13 @@ define([
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Sharing settings').prepend(
|
||||
}).html(' Settings').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-share-alt fa-fw'
|
||||
class: 'fa fa-gears fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSharingSettings');
|
||||
})
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
@@ -400,11 +399,6 @@ define([
|
||||
slideMenu.slidebars.toggle('right');
|
||||
});
|
||||
|
||||
// settings
|
||||
$('.' + config.headUserCharacterClass).find('a').on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
});
|
||||
|
||||
// active pilots
|
||||
$('.' + config.headActiveUserClass).find('a').on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
@@ -439,11 +433,8 @@ define([
|
||||
});
|
||||
|
||||
// set default values for map tracking checkbox
|
||||
if(CCP.isInGameBrowser() === false){
|
||||
mapTrackingCheckbox.bootstrapToggle('disable');
|
||||
}else{
|
||||
mapTrackingCheckbox.bootstrapToggle('on');
|
||||
}
|
||||
// -> always "enable"
|
||||
mapTrackingCheckbox.bootstrapToggle('on');
|
||||
|
||||
mapTrackingCheckbox.on('change', function(e) {
|
||||
var value = $(this).is(':checked');
|
||||
@@ -502,13 +493,6 @@ define([
|
||||
*/
|
||||
var setDocumentObserver = function(){
|
||||
|
||||
// tab close/reload detected
|
||||
window.addEventListener('beforeunload', function (e) {
|
||||
|
||||
// logout
|
||||
deleteLog();
|
||||
});
|
||||
|
||||
// on "full-screen" change event
|
||||
$(document).on('fscreenchange', function(e, state, elem){
|
||||
|
||||
@@ -526,12 +510,6 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowSharingSettings', function(e){
|
||||
// show sharing settings dialog
|
||||
$.fn.showSharingSettingsDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowSystemEffectInfo', function(e){
|
||||
// show system effects info box
|
||||
$.fn.showSystemEffectInfoDialog();
|
||||
@@ -670,12 +648,22 @@ define([
|
||||
title: 'Shutdown',
|
||||
headline: 'Emergency shutdown',
|
||||
text: [
|
||||
'Sorry! Under normal circumstances that should not happen',
|
||||
data.reason
|
||||
]
|
||||
],
|
||||
textSmaller: []
|
||||
}
|
||||
};
|
||||
|
||||
// add error information (if available)
|
||||
if(
|
||||
data.error &&
|
||||
data.error.length
|
||||
){
|
||||
for(var i = 0; i < data.error.length; i++){
|
||||
options.content.textSmaller.push(data.error[i].message);
|
||||
}
|
||||
}
|
||||
|
||||
$.fn.showNotificationDialog(options);
|
||||
|
||||
$(document).setProgramStatus('offline');
|
||||
@@ -752,7 +740,7 @@ define([
|
||||
newCharacterName = userData.character.name;
|
||||
|
||||
if(userData.character.log){
|
||||
newShipId = userData.character.log.ship.id;
|
||||
newShipId = userData.character.log.ship.typeId;
|
||||
newShipName = userData.character.log.ship.typeName;
|
||||
}
|
||||
}
|
||||
@@ -769,6 +757,9 @@ define([
|
||||
animateHeaderElement(userInfoElement, function(){
|
||||
userInfoElement.find('span').text( newCharacterName );
|
||||
userInfoElement.find('img').attr('src', Init.url.ccpImageServer + 'Character/' + newCharacterId + '_32.jpg' );
|
||||
|
||||
// init "character switch" popover
|
||||
userInfoElement.initCharacterSwitchPopover(userData);
|
||||
}, showCharacterElement);
|
||||
|
||||
// set new id for next check
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* user register/settings dialog
|
||||
* user settings/share dialog
|
||||
*/
|
||||
|
||||
define([
|
||||
@@ -12,22 +12,13 @@ define([
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
dialogWizardNavigationClass: 'pf-wizard-navigation', // class for wizard navigation bar
|
||||
|
||||
// select character dialog
|
||||
settingsDialogId: 'pf-settings-dialog', // id for "settings" dialog
|
||||
settingsImageWrapperClass: 'pf-dialog-image-wrapper', // class for image wrapper (animated)
|
||||
settingsImageInfoClass: 'pf-dialog-character-info', // class for character info layer (visible on hover)
|
||||
settingsMainClass: 'pf-dialog-character-main', // class for main character highlighting
|
||||
settingsNavigationButtonClass: 'pf-dialog-navigation-button', // class for all navigation buttons
|
||||
settingsFinishButtonClass: 'pf-dialog-finish-button', // class for "finish" button
|
||||
settingsPrevButtonClass: 'pf-dialog-prev-button', // class for "prev" button
|
||||
settingsNextButtonClass: 'pf-dialog-next-button', // class for "next" button
|
||||
settingsCloneApiRowClass: 'pf-dialog-api-row', // class for form row with API data (will be cloned)
|
||||
settingsCloneRowButtonClass: 'pf-dialog-clone-button', // class for clone button (api row)
|
||||
settingsDeleteRowButtonClass: 'pf-dialog-delete-button', // class for delete button (api row)
|
||||
settingsAccountContainerId: 'pf-settings-dialog-account', // id for the "account" container
|
||||
settingsShareContainerId: 'pf-settings-dialog-share', // id for the "share" container
|
||||
|
||||
// captcha
|
||||
captchaKeyUpdateAccount: 'SESSION.CAPTCHA.ACCOUNT.UPDATE', // key for captcha reason
|
||||
captchaImageWrapperId: 'pf-dialog-captcha-wrapper', // id for "captcha image" wrapper
|
||||
captchaImageId: 'pf-dialog-captcha-image', // id for "captcha image"
|
||||
|
||||
@@ -35,80 +26,9 @@ define([
|
||||
icon: {
|
||||
size: 'fa-2x'
|
||||
}
|
||||
},
|
||||
|
||||
// character status
|
||||
settingsCharacterStatusOwn : { // "own" -> my characters
|
||||
name: 'own',
|
||||
class: 'pf-user-status-own'
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* get active Tab link element for a dialog
|
||||
* @param dialog
|
||||
* @returns {JQuery|*}
|
||||
*/
|
||||
var getActiveTabElement = function(dialog){
|
||||
var navigationBarElement = $(dialog).find('.' + config.dialogWizardNavigationClass);
|
||||
var currentActiveTab = navigationBarElement.find('li.active');
|
||||
|
||||
return currentActiveTab;
|
||||
};
|
||||
|
||||
/**
|
||||
* init popovers in dialog
|
||||
* @param dialogElement
|
||||
*/
|
||||
var initPopover = function(dialogElement){
|
||||
|
||||
var apiCloneButtons = dialogElement.find('.' + config.settingsCloneRowButtonClass);
|
||||
var apiDeleteButtons = dialogElement.find('.' + config.settingsDeleteRowButtonClass);
|
||||
|
||||
var confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'left',
|
||||
btnCancelClass: 'btn btn-sm btn-default',
|
||||
btnCancelLabel: 'cancel',
|
||||
btnCancelIcon: 'fa fa-fw fa-ban'
|
||||
};
|
||||
|
||||
// add API key row
|
||||
var cloneConfirmationSettings = $.extend({
|
||||
title: 'Add additional key',
|
||||
btnOkClass: 'btn btn-sm btn-success',
|
||||
btnOkLabel: 'confirm',
|
||||
btnOkIcon: 'fa fa-fw fa-check',
|
||||
onConfirm: function(e) {
|
||||
var cloneRow = dialogElement.find('.' + config.settingsCloneApiRowClass).last();
|
||||
var newApiRow = cloneRow.clone();
|
||||
|
||||
newApiRow.find('.form-group').removeClass('has-success has-error');
|
||||
newApiRow.find('input').val('');
|
||||
cloneRow.after(newApiRow);
|
||||
|
||||
// init new row with popups
|
||||
initPopover(dialogElement);
|
||||
}
|
||||
}, confirmationSettings);
|
||||
|
||||
// delete API key row
|
||||
var deleteConfirmationSettings = $.extend({
|
||||
title: 'Delete key',
|
||||
btnOkClass: 'btn btn-sm btn-danger',
|
||||
btnOkLabel: 'delete',
|
||||
btnOkIcon: 'fa fa-fw fa-close',
|
||||
onConfirm: function(e, target) {
|
||||
$(target).parents('.row').remove();
|
||||
}
|
||||
}, confirmationSettings);
|
||||
|
||||
$(apiCloneButtons).confirmation(cloneConfirmationSettings);
|
||||
$(apiDeleteButtons).confirmation(deleteConfirmationSettings);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* show "register/settings" dialog
|
||||
* @param options
|
||||
@@ -122,213 +42,124 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
var reroutePath = '';
|
||||
|
||||
// check navigation buttons and show/hide them
|
||||
var checkNavigationButton = function(dialog){
|
||||
var navigationBarElement = $(dialog).find('.' + config.dialogWizardNavigationClass);
|
||||
var currentActiveTab = navigationBarElement.find('li.active');
|
||||
|
||||
var hidePrevButton = currentActiveTab.prevAll().length > 0 ? false : true;
|
||||
var hideNextButton = currentActiveTab.nextAll().length > 0 ? false : true;
|
||||
|
||||
if(hidePrevButton){
|
||||
$('.' + config.settingsPrevButtonClass).hide();
|
||||
}else{
|
||||
$('.' + config.settingsPrevButtonClass).show();
|
||||
}
|
||||
|
||||
if(hideNextButton){
|
||||
$('.' + config.settingsNextButtonClass).hide();
|
||||
}else{
|
||||
$('.' + config.settingsNextButtonClass).show();
|
||||
}
|
||||
};
|
||||
|
||||
requirejs(['text!templates/dialog/settings.html', 'mustache'], function(template, Mustache) {
|
||||
|
||||
// if this is a new registration there is no API key -> fake an empty API to make fields visible
|
||||
if(options.register === 1){
|
||||
Init.currentUserData = {};
|
||||
Init.currentUserData.api = [{
|
||||
keyId: '',
|
||||
vCode: ''
|
||||
}];
|
||||
}else if(Init.currentUserData.api === undefined){
|
||||
Init.currentUserData.api = [{
|
||||
keyId: '',
|
||||
vCode: ''
|
||||
}];
|
||||
}
|
||||
|
||||
var data = {
|
||||
id: config.settingsDialogId,
|
||||
register: options.register === 1 ? 1 : 0,
|
||||
invite : options.invite === 1 ? 1 : 0,
|
||||
navigationClass: config.dialogWizardNavigationClass,
|
||||
settingsAccountContainerId: config.settingsAccountContainerId,
|
||||
settingsShareContainerId: config.settingsShareContainerId,
|
||||
userData: Init.currentUserData,
|
||||
cloneApiRowClass: config.settingsCloneApiRowClass,
|
||||
cloneRowButtonClass: config.settingsCloneRowButtonClass,
|
||||
deleteRowButtonClass: config.settingsDeleteRowButtonClass,
|
||||
captchaImageWrapperId: config.captchaImageWrapperId,
|
||||
captchaImageId: config.captchaImageId,
|
||||
formErrorContainerClass: Util.config.formErrorContainerClass,
|
||||
formWarningContainerClass: Util.config.formWarningContainerClass
|
||||
ccpImageServer: Init.url.ccpImageServer
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, data);
|
||||
|
||||
var selectCharacterDialog = bootbox.dialog({
|
||||
title: options.register === 1 ? 'Registration' : 'Account settings',
|
||||
var accountSettingsDialog = bootbox.dialog({
|
||||
title: 'Account settings',
|
||||
message: content,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'finish',
|
||||
className: ['btn-success', 'pull-right', config.settingsFinishButtonClass].join(' '),
|
||||
callback: function(e){
|
||||
|
||||
if(options.register === 1){
|
||||
if(reroutePath !== undefined){
|
||||
// root user to main app
|
||||
window.location = reroutePath;
|
||||
}
|
||||
}else{
|
||||
// close dialog
|
||||
return true;
|
||||
}
|
||||
}
|
||||
label: 'cancel',
|
||||
className: 'btn-default'
|
||||
},
|
||||
prev: {
|
||||
label: '<i class="fa fa-fw fa-angle-left"></i>back',
|
||||
className: ['btn-default', 'pull-left', config.settingsNavigationButtonClass, config.settingsPrevButtonClass].join(' '),
|
||||
callback: function (e) {
|
||||
var currentActiveTab = getActiveTabElement(this);
|
||||
currentActiveTab.removeClass('finished');
|
||||
currentActiveTab.prev('li').find('a').tab('show');
|
||||
success: {
|
||||
label: '<i class="fa fa-check fa-fw"></i> save',
|
||||
className: 'btn-success',
|
||||
callback: function() {
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
next: {
|
||||
label: 'next<i class="fa fa-fw fa-angle-right"></i>',
|
||||
className: ['btn-primary', 'pull-right', config.settingsNavigationButtonClass, config.settingsNextButtonClass].join(' '),
|
||||
callback: function (e) {
|
||||
var dialogElement = $(this);
|
||||
var currentActiveTab = getActiveTabElement(dialogElement);
|
||||
var currentActiveLink = currentActiveTab.find('a');
|
||||
var tabContentElement = $(currentActiveLink.attr('href'));
|
||||
var form = tabContentElement.find('form');
|
||||
|
||||
var changeTab = function(){
|
||||
currentActiveTab.addClass('finished');
|
||||
currentActiveLink.removeClass('btn-danger btn-default');
|
||||
currentActiveLink.addClass('btn-primary');
|
||||
|
||||
currentActiveTab.next('li').find('a').tab('show');
|
||||
};
|
||||
// get the current active form
|
||||
var form = $('#' + config.settingsDialogId).find('form').filter(':visible');
|
||||
|
||||
// validate form
|
||||
form.validator('validate');
|
||||
|
||||
// check weather the form is valid
|
||||
var formValid = form.isValidForm();
|
||||
|
||||
if(!formValid){
|
||||
currentActiveTab.removeClass('disabled');
|
||||
currentActiveLink.removeClass('btn-default btn-primary');
|
||||
currentActiveLink.addClass('btn-danger');
|
||||
}else{
|
||||
if(formValid === true){
|
||||
var tabFormValues = form.getFormValues();
|
||||
|
||||
if(! $.isEmptyObject(tabFormValues) ){
|
||||
// send Tab data and store values
|
||||
var requestData = {
|
||||
formData: tabFormValues
|
||||
};
|
||||
|
||||
// send Tab data and store values
|
||||
var requestData = {
|
||||
settingsData: tabFormValues
|
||||
};
|
||||
accountSettingsDialog.find('.modal-content').showLoadingAnimation();
|
||||
|
||||
selectCharacterDialog.find('.modal-content').showLoadingAnimation();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.saveUserConfig,
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData){
|
||||
accountSettingsDialog.find('.modal-content').hideLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.saveUserConfig,
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData){
|
||||
selectCharacterDialog.find('.modal-content').hideLoadingAnimation();
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all data)
|
||||
if(
|
||||
responseData.error &&
|
||||
responseData.error.length > 0
|
||||
){
|
||||
form.showFormMessage(responseData.error);
|
||||
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all data)
|
||||
if(
|
||||
responseData.error &&
|
||||
responseData.error.length > 0
|
||||
){
|
||||
form.showFormMessage(responseData.error);
|
||||
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount', function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}else{
|
||||
// store new/updated user data -> update head
|
||||
if(responseData.userData){
|
||||
Util.setCurrentUserData(responseData.userData);
|
||||
}
|
||||
|
||||
// store reroute path after registration finished
|
||||
if(responseData.reroute){
|
||||
reroutePath = responseData.reroute;
|
||||
}
|
||||
|
||||
dialogElement.find('.alert').velocity('transition.slideDownOut',{
|
||||
duration: 500,
|
||||
complete: function(){
|
||||
// switch tab
|
||||
changeTab();
|
||||
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount', function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Util.showNotify({title: 'Account saved', type: 'success'});
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
selectCharacterDialog.find('.modal-content').hideLoadingAnimation();
|
||||
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': saveAccount', text: reason, type: 'error'});
|
||||
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all)
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount', function(){
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyUpdateAccount, function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}else{
|
||||
// store new/updated user data -> update head
|
||||
if(responseData.userData){
|
||||
Util.setCurrentUserData(responseData.userData);
|
||||
}
|
||||
|
||||
// check for DB errors
|
||||
if(jqXHR.status === 500){
|
||||
|
||||
if(jqXHR.responseText){
|
||||
var errorObj = $.parseJSON(jqXHR.responseText);
|
||||
|
||||
if(
|
||||
errorObj.error &&
|
||||
errorObj.error.length > 0
|
||||
){
|
||||
form.showFormMessage(errorObj.error);
|
||||
}
|
||||
form.find('.alert').velocity('transition.slideDownOut',{
|
||||
duration: 500,
|
||||
complete: function(){
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyUpdateAccount, function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if( options.register !== 1 ){
|
||||
$(document).setProgramStatus('problem');
|
||||
}
|
||||
Util.showNotify({title: 'Account saved', type: 'success'});
|
||||
|
||||
// close dialog/menu
|
||||
$(document).trigger('pf:closeMenu', [{}]);
|
||||
accountSettingsDialog.modal('hide');
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
accountSettingsDialog.find('.modal-content').hideLoadingAnimation();
|
||||
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': saveAccountSettings', text: reason, type: 'error'});
|
||||
|
||||
// set new captcha for any request
|
||||
// captcha is required for sensitive data (not for all)
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyUpdateAccount, function(){
|
||||
$('#captcha').resetFormFields();
|
||||
});
|
||||
|
||||
}else{
|
||||
// no request required -> change tab
|
||||
changeTab();
|
||||
}
|
||||
// check for DB errors
|
||||
if(jqXHR.status === 500){
|
||||
|
||||
if(jqXHR.responseText){
|
||||
var errorObj = $.parseJSON(jqXHR.responseText);
|
||||
|
||||
if(
|
||||
errorObj.error &&
|
||||
errorObj.error.length > 0
|
||||
){
|
||||
form.showFormMessage(errorObj.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).setProgramStatus('problem');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -338,163 +169,42 @@ define([
|
||||
});
|
||||
|
||||
// after modal is shown =======================================================================
|
||||
selectCharacterDialog.on('shown.bs.modal', function(e) {
|
||||
accountSettingsDialog.on('shown.bs.modal', function(e) {
|
||||
|
||||
var dialogElement = $(this);
|
||||
var tabLinkElements = dialogElement.find('a[data-toggle="tab"]');
|
||||
var form = dialogElement.find('form');
|
||||
|
||||
// request captcha image and show
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('createAccount');
|
||||
var captchaImageWrapperContainer = $('#' + config.captchaImageWrapperId);
|
||||
captchaImageWrapperContainer.showCaptchaImage(config.captchaKeyUpdateAccount);
|
||||
|
||||
// init captcha refresh button
|
||||
captchaImageWrapperContainer.find('i').on('click', function(){
|
||||
captchaImageWrapperContainer.showCaptchaImage(config.captchaKeyUpdateAccount);
|
||||
});
|
||||
|
||||
|
||||
// init dialog tooltips
|
||||
dialogElement.initTooltips();
|
||||
|
||||
// init popups
|
||||
initPopover( dialogElement );
|
||||
|
||||
// init form validation
|
||||
form.initFormValidation();
|
||||
});
|
||||
|
||||
// on Tab switch ======================================================================
|
||||
tabLinkElements.on('shown.bs.tab', function (e) {
|
||||
|
||||
// check navigation buttons (hide/show)
|
||||
checkNavigationButton(dialogElement);
|
||||
|
||||
$(e.target).removeClass('disabled');
|
||||
|
||||
// hide finish button
|
||||
dialogElement.find('.' + config.settingsFinishButtonClass).hide();
|
||||
|
||||
|
||||
if($(e.target).text() < $(e.relatedTarget).text()){
|
||||
var currentActiveTab = getActiveTabElement(dialogElement);
|
||||
var nextTabElements = currentActiveTab.nextAll();
|
||||
|
||||
// disable all next tabs
|
||||
currentActiveTab.removeClass('finished');
|
||||
nextTabElements.removeClass('finished');
|
||||
nextTabElements.find('a').removeClass('btn-primary btn-danger').addClass('btn-default disabled');
|
||||
}
|
||||
|
||||
if($(e.target).text() === '3'){
|
||||
|
||||
// load character tab -----------------------------------------------
|
||||
|
||||
requirejs(['text!templates/form/character_panel.html', 'mustache'], function(template, Mustache) {
|
||||
|
||||
// all characters for the current user
|
||||
var characters = Init.currentUserData.characters;
|
||||
// calculate grid class
|
||||
var characterCount = characters.length;
|
||||
var gridClass = ((12 / characterCount) < 4)? 4 : 12 / characterCount ;
|
||||
|
||||
// add character status information for each character
|
||||
var statusInfo = {};
|
||||
statusInfo.class = config.settingsCharacterStatusOwn.class;
|
||||
statusInfo.label = config.settingsCharacterStatusOwn.name;
|
||||
|
||||
var mainCharacter = 0;
|
||||
for(var i = 0; i < characters.length; i++){
|
||||
characters[i].status = statusInfo;
|
||||
|
||||
if(characters[i].isMain === 1){
|
||||
mainCharacter = characters[i].id;
|
||||
}else if(mainCharacter === 0){
|
||||
// mark at least one character as "main" if no main char was found
|
||||
// e.g. first account setup
|
||||
mainCharacter = characters[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
var characterTemplateData = {
|
||||
imageWrapperClass: config.settingsImageWrapperClass,
|
||||
imageInfoClass: config.settingsImageInfoClass,
|
||||
imageWrapperMainClass: config.settingsMainClass,
|
||||
charactersData: characters,
|
||||
gridClass: 'col-sm-' + gridClass,
|
||||
mainCharacter: mainCharacter
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, characterTemplateData);
|
||||
|
||||
var characterForm = dialogElement.find('#pf-dialog-settings-character form');
|
||||
|
||||
// add form HTML
|
||||
characterForm.html(content);
|
||||
|
||||
var imageWrapperElements = dialogElement.find('.' + config.settingsImageWrapperClass);
|
||||
|
||||
// special effects :)
|
||||
imageWrapperElements.velocity('stop').delay(100).velocity('transition.flipBounceXIn', {
|
||||
display: 'inline-block',
|
||||
stagger: 60,
|
||||
drag: true,
|
||||
duration: 400,
|
||||
complete: function(){
|
||||
// init new character tooltips
|
||||
dialogElement.initTooltips();
|
||||
}
|
||||
});
|
||||
|
||||
// Hover effect for character info layer
|
||||
imageWrapperElements.hoverIntent(function(e){
|
||||
var characterInfoElement = $(this).find('.' + config.settingsImageInfoClass);
|
||||
|
||||
characterInfoElement.velocity('finish').velocity({
|
||||
width: ['100%', [ 400, 15 ] ]
|
||||
},{
|
||||
easing: 'easeInSine'
|
||||
});
|
||||
}, function(e){
|
||||
var characterInfoElement = $(this).find('.' + config.settingsImageInfoClass);
|
||||
|
||||
characterInfoElement.velocity('finish').velocity({
|
||||
width: 0
|
||||
},{
|
||||
duration: 150,
|
||||
easing: 'easeInOutSine'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// click event on character image
|
||||
imageWrapperElements.on('click', function(e){
|
||||
var wrapperElement = $(this);
|
||||
var characterId = wrapperElement.data('id');
|
||||
|
||||
// update layout if character is selected
|
||||
if(characterId > 0){
|
||||
// update hidden field with new mainCharacterId
|
||||
dialogElement.find('input[name="mainCharacterId"]').val(characterId);
|
||||
|
||||
imageWrapperElements.removeClass( config.settingsMainClass );
|
||||
wrapperElement.addClass( config.settingsMainClass );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}else if($(e.target).text() === '4'){
|
||||
// show finish button
|
||||
dialogElement.find('.' + config.settingsFinishButtonClass).show();
|
||||
|
||||
// show success message
|
||||
dialogElement.find('h1').velocity('stop').delay(200).velocity('transition.flipBounceXIn', {
|
||||
duration: 500
|
||||
}).delay(100).velocity('callout.pulse');
|
||||
}
|
||||
// events for tab change
|
||||
accountSettingsDialog.find('.navbar a').on('shown.bs.tab', function(e){
|
||||
|
||||
// init "toggle" switches on current active tab
|
||||
accountSettingsDialog.find( $(this).attr('href') ).find('input[type="checkbox"]').bootstrapToggle({
|
||||
on: '<i class="fa fa-fw fa-check"></i> Enable',
|
||||
off: 'Disable <i class="fa fa-fw fa-ban"></i>',
|
||||
onstyle: 'success',
|
||||
offstyle: 'warning',
|
||||
width: 90,
|
||||
height: 30
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
@@ -15,6 +15,7 @@ define([
|
||||
deleteAccountId: 'pf-dialog-delete-account', // dialog id
|
||||
|
||||
// captcha
|
||||
captchaKeyDeleteAccount: 'SESSION.CAPTCHA.ACCOUNT.DELETE', // key for captcha reason
|
||||
captchaImageWrapperId: 'pf-dialog-captcha-wrapper' // id for "captcha image" wrapper
|
||||
};
|
||||
|
||||
@@ -82,8 +83,8 @@ define([
|
||||
){
|
||||
form.showFormMessage(responseData.error);
|
||||
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('deleteAccount', function(){
|
||||
form.find('[name="captcha"], [name="password"]').resetFormFields();
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyDeleteAccount, function(){
|
||||
form.find('[name="captcha"]').resetFormFields();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ define([
|
||||
// after modal is shown =======================================================================
|
||||
deleteAccountDialog.on('shown.bs.modal', function(e) {
|
||||
// request captcha image and show
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage('deleteAccount');
|
||||
$('#' + config.captchaImageWrapperId).showCaptchaImage(config.captchaKeyDeleteAccount);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -642,7 +642,6 @@ define([
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(usersData);
|
||||
|
||||
var userDataTable = userTable.dataTable( {
|
||||
pageLength: 20,
|
||||
@@ -670,7 +669,7 @@ console.log(usersData);
|
||||
data: 'log.ship',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
return '<img src="' + Init.url.ccpImageServer + 'Render/' + data.id + '_32.png" />';
|
||||
return '<img src="' + Init.url.ccpImageServer + 'Render/' + data.typeId + '_32.png" />';
|
||||
}
|
||||
}
|
||||
},{
|
||||
@@ -736,6 +735,16 @@ console.log(usersData);
|
||||
}
|
||||
},{
|
||||
targets: 7,
|
||||
title: 'station',
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
data: 'log.station',
|
||||
render: {
|
||||
_: 'name',
|
||||
sort: 'name'
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -754,7 +763,7 @@ console.log(usersData);
|
||||
});
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
targets: 9,
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
|
||||
@@ -20,7 +20,7 @@ define([
|
||||
dialogMapSettingsContainerId: 'pf-map-dialog-settings', // id for the "settings" container
|
||||
dialogMapDownloadContainerId: 'pf-map-dialog-download', // id for the "download" container
|
||||
|
||||
userSelectId: 'pf-map-dialog-user-select', // id for "user" select
|
||||
characterSelectId: 'pf-map-dialog-character-select', // id for "character" select
|
||||
corporationSelectId: 'pf-map-dialog-corporation-select', // id for "corporation" select
|
||||
allianceSelectId: 'pf-map-dialog-alliance-select', // id for "alliance" select
|
||||
|
||||
@@ -100,7 +100,7 @@ define([
|
||||
contentEditMap = $(contentEditMap);
|
||||
|
||||
// current map access info
|
||||
var accessUser = [];
|
||||
var accessCharacter = [];
|
||||
var accessCorporation = [];
|
||||
var accessAlliance = [];
|
||||
|
||||
@@ -112,7 +112,7 @@ define([
|
||||
contentEditMap.find('select[name="scopeId"]').val( mapData.config.scope.id );
|
||||
contentEditMap.find('select[name="typeId"]').val( mapData.config.type.id );
|
||||
|
||||
accessUser = mapData.config.access.user;
|
||||
accessCharacter = mapData.config.access.character;
|
||||
accessCorporation = mapData.config.access.corporation;
|
||||
accessAlliance = mapData.config.access.alliance;
|
||||
}
|
||||
@@ -145,17 +145,17 @@ define([
|
||||
hideDownloadTab: hideDownloadTab,
|
||||
|
||||
// settings tab --------------
|
||||
userSelectId: config.userSelectId,
|
||||
characterSelectId: config.characterSelectId,
|
||||
corporationSelectId: config.corporationSelectId,
|
||||
allianceSelectId: config.allianceSelectId,
|
||||
|
||||
// map access objects --------
|
||||
accessUser: accessUser,
|
||||
accessCharacter: accessCharacter,
|
||||
accessCorporation: accessCorporation,
|
||||
accessAlliance: accessAlliance,
|
||||
|
||||
// access limitations --------
|
||||
maxUser: Init.maxSharedCount.user,
|
||||
maxCharacter: Init.maxSharedCount.character,
|
||||
maxCorporation: Init.maxSharedCount.corporation,
|
||||
maxAlliance: Init.maxSharedCount.alliance,
|
||||
|
||||
@@ -287,7 +287,7 @@ define([
|
||||
// events for tab change
|
||||
mapInfoDialog.find('.navbar a').on('shown.bs.tab', function(e){
|
||||
|
||||
var selectElementUser = mapInfoDialog.find('#' + config.userSelectId);
|
||||
var selectElementCharacter = mapInfoDialog.find('#' + config.characterSelectId);
|
||||
var selectElementCorporation = mapInfoDialog.find('#' + config.corporationSelectId);
|
||||
var selectElementAlliance = mapInfoDialog.find('#' + config.allianceSelectId);
|
||||
|
||||
@@ -295,8 +295,8 @@ define([
|
||||
// "settings" tab
|
||||
initSettingsSelectFields(mapInfoDialog);
|
||||
}else{
|
||||
if( $(selectElementUser).data('select2') !== undefined ){
|
||||
$(selectElementUser).select2('destroy');
|
||||
if( $(selectElementCharacter).data('select2') !== undefined ){
|
||||
$(selectElementCharacter).select2('destroy');
|
||||
}
|
||||
|
||||
if( $(selectElementCorporation).data('select2') !== undefined ){
|
||||
@@ -550,14 +550,14 @@ define([
|
||||
*/
|
||||
var initSettingsSelectFields = function(mapInfoDialog){
|
||||
|
||||
var selectElementUser = mapInfoDialog.find('#' + config.userSelectId);
|
||||
var selectElementCharacter = mapInfoDialog.find('#' + config.characterSelectId);
|
||||
var selectElementCorporation = mapInfoDialog.find('#' + config.corporationSelectId);
|
||||
var selectElementAlliance = mapInfoDialog.find('#' + config.allianceSelectId);
|
||||
|
||||
// init corporation select live search
|
||||
selectElementUser.initAccessSelect({
|
||||
type: 'user',
|
||||
maxSelectionLength: Init.maxSharedCount.user
|
||||
// init character select live search
|
||||
selectElementCharacter.initAccessSelect({
|
||||
type: 'character',
|
||||
maxSelectionLength: Init.maxSharedCount.character
|
||||
});
|
||||
|
||||
// init corporation select live search
|
||||
@@ -575,7 +575,7 @@ define([
|
||||
|
||||
/**
|
||||
* shows the delete map Dialog
|
||||
* @param mapElement
|
||||
* @param mapData
|
||||
*/
|
||||
$.fn.showDeleteMapDialog = function(mapData){
|
||||
|
||||
|
||||
@@ -47,8 +47,6 @@ define([
|
||||
releasesDialog.find('ul.timeline').append(content);
|
||||
}
|
||||
|
||||
// console.log()
|
||||
|
||||
$('.timeline > li').velocity('transition.expandIn', {
|
||||
stagger: 300,
|
||||
duration: 240,
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* sharing settings dialog
|
||||
*/
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox'
|
||||
], function($, Init, Util, Render, bootbox) {
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
// select character dialog
|
||||
sharingDialogId: 'pf-sharing-dialog', // id for "sharing settings" dialog
|
||||
};
|
||||
|
||||
$.fn.showSharingSettingsDialog = function(){
|
||||
|
||||
var sharingDialogElement = $('#' + config.sharingDialogId);
|
||||
if(!sharingDialogElement.is(':visible')){
|
||||
|
||||
var userData = Util.getCurrentUserData();
|
||||
|
||||
if(userData){
|
||||
|
||||
requirejs([
|
||||
'text!templates/dialog/sharing_settings.html',
|
||||
'mustache'
|
||||
], function(templatSharingDialog, Mustache) {
|
||||
|
||||
var data = {
|
||||
id: config.sharingDialogId,
|
||||
ccpImageServer: Init.url.ccpImageServer,
|
||||
userData: userData
|
||||
};
|
||||
|
||||
// render "new map" tab content -------------------------------------------
|
||||
var contentSharingDialog = Mustache.render(templatSharingDialog, data);
|
||||
|
||||
var sharingSettingsDialog = bootbox.dialog({
|
||||
title: 'Sharing settings',
|
||||
message: $(contentSharingDialog),
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'cancel',
|
||||
className: 'btn-default'
|
||||
},
|
||||
success: {
|
||||
label: '<i class="fa fa-check fa-fw"></i> save',
|
||||
className: 'btn-success',
|
||||
callback: function() {
|
||||
|
||||
var form = $('#' + config.sharingDialogId).find('form');
|
||||
|
||||
var sharingSettingsData = {formData: form.getFormValues()};
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.saveSharingConfig,
|
||||
data: sharingSettingsData,
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
|
||||
if(data.userData !== undefined){
|
||||
// store current user data global (cache)
|
||||
Util.setCurrentUserData(data.userData);
|
||||
|
||||
$(document).trigger('pf:closeMenu', [{}]);
|
||||
$(sharingSettingsDialog).modal('hide');
|
||||
|
||||
// success
|
||||
Util.showNotify({title: 'Sharing settings saved', type: 'success'});
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': shareSettings', text: reason, type: 'warning'});
|
||||
$(document).setProgramStatus('problem');
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// after modal is shown ---------------------------------------------------
|
||||
sharingSettingsDialog.on('shown.bs.modal', function(e) {
|
||||
|
||||
$(this).find('input[type="checkbox"]').bootstrapToggle({
|
||||
on: '<i class="fa fa-fw fa-check"></i> Enable',
|
||||
off: 'Disable <i class="fa fa-fw fa-ban"></i>',
|
||||
onstyle: 'success',
|
||||
offstyle: 'warning',
|
||||
width: 90,
|
||||
height: 30
|
||||
});
|
||||
});
|
||||
});
|
||||
}else{
|
||||
Util.showNotify({title: 'No userData found', type: 'warning'});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -131,7 +131,7 @@ define([
|
||||
|
||||
/**
|
||||
* init a select element as an ajax based "select2" object for Access resources
|
||||
* user (private map), corporation (corp map), alliance (ally map)
|
||||
* character (private map), corporation (corp map), alliance (ally map)
|
||||
* @param options
|
||||
*/
|
||||
$.fn.initAccessSelect = function(options){
|
||||
@@ -162,8 +162,9 @@ define([
|
||||
var previewContent = '';
|
||||
|
||||
switch(options.type){
|
||||
case 'user':
|
||||
previewContent = '<i class="fa fa-lg fa-user"></i>';
|
||||
case 'character':
|
||||
imagePath = Init.url.ccpImageServer + 'Character/' + data.id + '_32.jpg';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
case 'corporation':
|
||||
imagePath = Init.url.ccpImageServer + 'Corporation/' + data.id + '_32.png';
|
||||
|
||||
@@ -150,57 +150,58 @@ define([
|
||||
dataType: 'json'
|
||||
}).done(function(systemGraphsData){
|
||||
|
||||
// create new (hidden) module container
|
||||
var moduleElement = $('<div>', {
|
||||
class: [config.moduleClass, config.systemGraphModuleClass].join(' '),
|
||||
css: {opacity: 0}
|
||||
});
|
||||
|
||||
// insert at the correct position
|
||||
if($(parentElement).children().length === 1){
|
||||
$(parentElement).append(moduleElement);
|
||||
}else{
|
||||
$(parentElement).find('>:first-child').after(moduleElement);
|
||||
}
|
||||
|
||||
// row element
|
||||
var rowElement = $('<div>', {
|
||||
class: 'row'
|
||||
});
|
||||
moduleElement.append(rowElement);
|
||||
|
||||
$.each(systemGraphsData, function(systemId, graphsData){
|
||||
$.each(graphsData, function(graphKey, graphData){
|
||||
|
||||
var colElement = $('<div>', {
|
||||
class: ['col-xs-12', 'col-sm-6', 'col-md-4'].join(' ')
|
||||
});
|
||||
|
||||
var headlineElement = $('<h5>').text( getInfoForGraph(graphKey, 'headline') );
|
||||
|
||||
colElement.append(headlineElement);
|
||||
|
||||
var graphElement = $('<div>', {
|
||||
class: config.systemGraphClass
|
||||
});
|
||||
|
||||
colElement.append(graphElement);
|
||||
|
||||
rowElement.append(colElement);
|
||||
initGraph(graphElement, graphKey, graphData, eventLine);
|
||||
if(systemGraphsData.length > 0){
|
||||
// create new (hidden) module container
|
||||
var moduleElement = $('<div>', {
|
||||
class: [config.moduleClass, config.systemGraphModuleClass].join(' '),
|
||||
css: {opacity: 0}
|
||||
});
|
||||
});
|
||||
|
||||
moduleElement.append($('<div>', {
|
||||
css: {'clear': 'both'}
|
||||
}));
|
||||
// insert at the correct position
|
||||
if($(parentElement).children().length === 1){
|
||||
$(parentElement).append(moduleElement);
|
||||
}else{
|
||||
$(parentElement).find('>:first-child').after(moduleElement);
|
||||
}
|
||||
|
||||
// show module
|
||||
moduleElement.velocity('transition.slideDownIn', {
|
||||
duration: Init.animationSpeed.mapModule,
|
||||
delay: Init.animationSpeed.mapModule
|
||||
});
|
||||
// row element
|
||||
var rowElement = $('<div>', {
|
||||
class: 'row'
|
||||
});
|
||||
moduleElement.append(rowElement);
|
||||
|
||||
$.each(systemGraphsData, function(systemId, graphsData){
|
||||
$.each(graphsData, function(graphKey, graphData){
|
||||
|
||||
var colElement = $('<div>', {
|
||||
class: ['col-xs-12', 'col-sm-6', 'col-md-4'].join(' ')
|
||||
});
|
||||
|
||||
var headlineElement = $('<h5>').text( getInfoForGraph(graphKey, 'headline') );
|
||||
|
||||
colElement.append(headlineElement);
|
||||
|
||||
var graphElement = $('<div>', {
|
||||
class: config.systemGraphClass
|
||||
});
|
||||
|
||||
colElement.append(graphElement);
|
||||
|
||||
rowElement.append(colElement);
|
||||
initGraph(graphElement, graphKey, graphData, eventLine);
|
||||
});
|
||||
});
|
||||
|
||||
moduleElement.append($('<div>', {
|
||||
css: {'clear': 'both'}
|
||||
}));
|
||||
|
||||
// show module
|
||||
moduleElement.velocity('transition.slideDownIn', {
|
||||
duration: Init.animationSpeed.mapModule,
|
||||
delay: Init.animationSpeed.mapModule
|
||||
});
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': System graph data', text: reason, type: 'warning'});
|
||||
|
||||
@@ -333,34 +333,34 @@ define([
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
dataType: 'jsonp'
|
||||
}).done(function(kbData){
|
||||
dataType: 'json'
|
||||
}).done(function(kbData) {
|
||||
|
||||
// the API wont return more than 200KMs ! - remember last bar block with complete KM information
|
||||
var lastCompleteDiffHourData = 0;
|
||||
|
||||
|
||||
// loop kills and count kills by hour
|
||||
for(var i = 0; i < kbData.length; i++){
|
||||
for (var i = 0; i < kbData.length; i++) {
|
||||
var killmailData = kbData[i];
|
||||
|
||||
var killDate = getDateObjectByTimeString(killmailData.killTime);
|
||||
|
||||
// get time diff
|
||||
var timeDiffMin = Math.round( ( serverDate - killDate ) / 1000 / 60 );
|
||||
var timeDiffHour = Math.round( timeDiffMin / 60 );
|
||||
var timeDiffMin = Math.round(( serverDate - killDate ) / 1000 / 60);
|
||||
var timeDiffHour = Math.round(timeDiffMin / 60);
|
||||
|
||||
// update chart data
|
||||
if(chartData[timeDiffHour]){
|
||||
if (chartData[timeDiffHour]) {
|
||||
chartData[timeDiffHour].kills++;
|
||||
|
||||
// add kill mail data
|
||||
if(chartData[timeDiffHour].killmails === undefined){
|
||||
if (chartData[timeDiffHour].killmails === undefined) {
|
||||
chartData[timeDiffHour].killmails = [];
|
||||
}
|
||||
chartData[timeDiffHour].killmails.push(killmailData);
|
||||
|
||||
if(timeDiffHour > lastCompleteDiffHourData){
|
||||
if (timeDiffHour > lastCompleteDiffHourData) {
|
||||
lastCompleteDiffHourData = timeDiffHour;
|
||||
}
|
||||
}
|
||||
@@ -368,7 +368,7 @@ define([
|
||||
}
|
||||
|
||||
// remove empty chart Data
|
||||
if(kbData.length >= maxKillmailCount){
|
||||
if (kbData.length >= maxKillmailCount) {
|
||||
chartData = chartData.splice(0, lastCompleteDiffHourData + 1);
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ define([
|
||||
cache.systemKillsGraphData[cacheKey].count = kbData.length;
|
||||
|
||||
// draw table
|
||||
drawGraph( cache.systemKillsGraphData[cacheKey] );
|
||||
drawGraph(cache.systemKillsGraphData[cacheKey]);
|
||||
|
||||
// show killmail information
|
||||
showKillmails(moduleElement, cache.systemKillsGraphData[cacheKey]);
|
||||
|
||||
@@ -1634,6 +1634,10 @@ define([
|
||||
// submit all fields within a table row
|
||||
var formFields = rowElement.find('.editable');
|
||||
|
||||
// the "toggle" makes sure to take care about open editable fields (e.g. description)
|
||||
// otherwise, changes would not be submitted in this field (not necessary)
|
||||
formFields.editable('toggle');
|
||||
|
||||
// submit all xEditable fields
|
||||
formFields.editable('submit', {
|
||||
url: Init.path.saveSignatureData,
|
||||
|
||||
@@ -317,15 +317,17 @@ define([
|
||||
|
||||
/**
|
||||
* init form elements for validation (bootstrap3 validation)
|
||||
* @returns {any|JQuery|*}
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.initFormValidation = function(){
|
||||
$.fn.initFormValidation = function(options){
|
||||
options = (typeof options === 'undefined')? {} : options;
|
||||
|
||||
return this.each(function(){
|
||||
var form = $(this);
|
||||
|
||||
// init form validation
|
||||
form.validator();
|
||||
form.validator(options);
|
||||
|
||||
// validation event listener
|
||||
form.on('valid.bs.validator', function(validatorObj){
|
||||
@@ -342,7 +344,6 @@ define([
|
||||
inputGroup.removeClass('has-success').addClass('has-error');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -545,6 +546,84 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* add character switch popover
|
||||
* @param userData
|
||||
*/
|
||||
$.fn.initCharacterSwitchPopover = function(userData){
|
||||
var elements = $(this);
|
||||
var eventNamespace = 'hideCharacterPopup';
|
||||
|
||||
requirejs(['text!templates/tooltip/character_switch.html', 'mustache'], function (template, Mustache) {
|
||||
|
||||
var data = {
|
||||
routes: Init.routes,
|
||||
userData: userData,
|
||||
otherCharacters: $.grep( userData.characters, function( character ) {
|
||||
// exclude current active character
|
||||
return character.id !== userData.character.id;
|
||||
})
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, data);
|
||||
|
||||
return elements.each(function() {
|
||||
var element = $(this);
|
||||
|
||||
// destroy "popover" and remove "click" event for animation
|
||||
element.popover('destroy').off();
|
||||
|
||||
// init popover and add specific class to it (for styling)
|
||||
element.popover({
|
||||
html: true,
|
||||
title: 'select character',
|
||||
trigger: 'click',
|
||||
placement: 'bottom',
|
||||
content: content,
|
||||
animation: false
|
||||
}).data('bs.popover').tip().addClass('pf-character-info-popover');
|
||||
|
||||
element.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var easeEffect = $(this).attr('data-easein');
|
||||
var popover = $(this).data('bs.popover').tip();
|
||||
var velocityOptions = {
|
||||
duration: CCP.isInGameBrowser() ? 0 : Init.animationSpeed.dialogEvents
|
||||
};
|
||||
|
||||
switch(easeEffect){
|
||||
case 'shake':
|
||||
case 'pulse':
|
||||
case 'tada':
|
||||
case 'flash':
|
||||
case 'bounce':
|
||||
case 'swing':
|
||||
popover.velocity('callout.' + easeEffect, velocityOptions);
|
||||
break;
|
||||
default:
|
||||
popover.velocity('transition.' + easeEffect, velocityOptions);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// hide popup on clicking "somewhere" outside
|
||||
$('body').off('click.' + eventNamespace).on('click.' + eventNamespace, function (e) {
|
||||
|
||||
//the 'is' for buttons that trigger popups
|
||||
//the 'has' for icons within a button that triggers a popup
|
||||
if (
|
||||
!$(element).is(e.target) &&
|
||||
$(element).has(e.target).length === 0 &&
|
||||
$('.popover').has(e.target).length === 0
|
||||
){
|
||||
$(element).popover('hide');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* add a wormhole tooltip with wh specific data to elements
|
||||
* @param tooltipData
|
||||
@@ -575,7 +654,6 @@ define([
|
||||
var popover = element.data('bs.popover');
|
||||
popover.options.content = content;
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1129,7 +1207,6 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
var getSystemEffectTable = function(data){
|
||||
|
||||
var table = '';
|
||||
|
||||
if(data.length > 0){
|
||||
|
||||
128
public/js/v1.0.0RC3/lib/validator.min.js
vendored
128
public/js/v1.0.0RC3/lib/validator.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -15,21 +15,6 @@
|
||||
</div>
|
||||
{{/userData.name}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="password" class="col-sm-3 control-label">Password</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter your password" data-placement="right">
|
||||
<input name="password" type="password" class="form-control" id="password" placeholder="" data-error="Field is required" autocomplete="off" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-lock"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
|
||||
@@ -55,27 +55,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{! user search ----------------------------------------------------- }}
|
||||
{{#accessUser.length}}
|
||||
{{! character search ------------------------------------------------ }}
|
||||
{{#accessCharacter.length}}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="{{userSelectId}}">Username</label>
|
||||
<label class="col-sm-2 control-label" for="{{characterSelectId}}">Character</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group" title="add/remove user">
|
||||
<label for="{{userSelectId}}"></label>
|
||||
<select id="{{userSelectId}}" name="mapUsers[]" multiple="multiple">
|
||||
{{#accessUser}}
|
||||
<div class="input-group" title="add/remove character">
|
||||
<label for="{{characterSelectId}}"></label>
|
||||
<select id="{{characterSelectId}}" name="mapCharacters[]" multiple="multiple">
|
||||
{{#accessCharacter}}
|
||||
<option value="{{id}}" selected>{{name}}</option>
|
||||
{{/accessUser}}
|
||||
{{/accessCharacter}}
|
||||
</select>
|
||||
<span class="help-block with-errors">Search user name (max {{maxUser}})</span>
|
||||
<span class="help-block with-errors">Search character name (max {{maxCharacter}})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/accessUser.length}}
|
||||
{{/accessCharacter.length}}
|
||||
|
||||
{{! corporation search ---------------------------------------------- }}
|
||||
{{#accessCorporation.length}}
|
||||
|
||||
@@ -10,5 +10,10 @@
|
||||
<h5 class="text-center">{{.}}</h5>
|
||||
{{/.}}
|
||||
{{/text}}
|
||||
{{#textSmaller}}
|
||||
{{#.}}
|
||||
<h4 class="text-center">{{.}}</h4>
|
||||
{{/.}}
|
||||
{{/textSmaller}}
|
||||
{{/content}}
|
||||
</div>
|
||||
|
||||
@@ -1,177 +1,90 @@
|
||||
<div id="{{id}}">
|
||||
|
||||
<div role="tabpanel">
|
||||
<ul class="text-center {{navigationClass}} row" role="tablist">
|
||||
<li class="col-sm-3 active">
|
||||
<a class="btn btn-default btn-circle btn-sm" data-toggle="tab" href="#pf-dialog-settings-account">1</a>
|
||||
<h6>Account Setup</h6>
|
||||
</li>
|
||||
<li class="col-sm-3">
|
||||
<a class="btn btn-default btn-circle btn-sm disabled" data-toggle="tab" href="#pf-dialog-settings-api">2</a>
|
||||
<h6>API Keys</h6>
|
||||
</li>
|
||||
<li class="col-sm-3">
|
||||
<a class="btn btn-default btn-circle btn-sm disabled" data-toggle="tab" href="#pf-dialog-settings-character">3</a>
|
||||
<h6>Characters</h6>
|
||||
</li>
|
||||
<li class="col-sm-3">
|
||||
<a class="btn btn-default btn-circle btn-sm disabled" data-toggle="tab" href="#pf-dialog-settings-done">4</a>
|
||||
<h6>Done</h6>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="tab-content">
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="navbar-header pull-left">
|
||||
<ul class="nav navbar-nav" role="tablist">
|
||||
<li class="active">
|
||||
<a role="tab" data-toggle="tab" data-name="account" href="#{{settingsAccountContainerId}}">
|
||||
<i class="fa fa-user fa-fw"></i> Account
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a role="tab" data-toggle="tab" data-name="share" href="#{{settingsShareContainerId}}">
|
||||
<i class="fa fa-share-alt fa-fw"></i> Share
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane fade in active" id="{{settingsAccountContainerId}}">
|
||||
{{! account tab ================================================================================================ }}
|
||||
<div role="tabpanel" class="tab-pane fade in active" id="pf-dialog-settings-account">
|
||||
<form role="form" class="form-horizontal">
|
||||
{{^register}}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Username</label>
|
||||
<div class="col-sm-9">
|
||||
<p class="form-control-static">{{userData.name}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<form role="form" class="form-horizontal">
|
||||
|
||||
{{! Username }}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Username</label>
|
||||
<div class="col-sm-9">
|
||||
<p class="form-control-static">
|
||||
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-dialog-icon-button collapsed" data-toggle="collapse" data-target="#collapseUsername" aria-expanded="false" aria-controls="collapseUsername"></i>
|
||||
{{userData.name}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{/register}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#register}}
|
||||
|
||||
{{#invite}}
|
||||
<div class="alert alert-info" style="margin-bottom: 20px">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><i class="fa fa-close"></i></button>
|
||||
<span class="txt-color txt-color-information">Invite active</span>
|
||||
<small>You need a "Registration Key" to complete registration</small>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="registrationKey" class="col-sm-3 control-label">Registration Key</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter your personal registration kay" data-placement="right">
|
||||
<input name="registrationKey" type="text" class="form-control" id="registrationKey" value="" placeholder="XXXXXX" data-error="Registration key required" data-minlength="40" data-minlength-error="Min. of 40 characters" autocomplete="off" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-certificate"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/invite}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-sm-3 control-label">Username</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Choose your unique username" data-placement="right">
|
||||
<input name="name" type="text" class="form-control" id="name" value="" placeholder="Your username" data-error="Username required" data-minlength="5" data-minlength-error="Min. of 5 characters" autocomplete="nickname" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/register}}
|
||||
|
||||
{{^register}}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Email</label>
|
||||
<div class="col-sm-9">
|
||||
<p class="form-control-static">
|
||||
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-dialog-icon-button collapsed" data-toggle="collapse" data-target="#collapseEmail" aria-expanded="false" aria-controls="collapseEmail"></i>
|
||||
{{userData.email}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/register}}
|
||||
|
||||
<div id="collapseEmail" class="{{^register}}collapse{{/register}}">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="email" class="col-sm-3 control-label">New Email</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter your email. It will be kept private!" data-placement="right">
|
||||
<input name="email" type="email" class="form-control" id="email" value="" placeholder="your@email.com" data-error="Email required" autocomplete="email" {{#register}}required{{/register}} >
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-envelope"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="email_confirm" class="col-sm-3 control-label">Confirm Email</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Confirm your email" data-placement="right">
|
||||
<input name="email_confirm" type="email" class="form-control" id="email_confirm" value="" placeholder="your@email.com" data-error="Email required" data-match="#email" data-match-error="Email fields do not match" autocomplete="email" {{#register}}required{{/register}}>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-envelope"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
<div id="collapseUsername" class="collapse">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-sm-3 control-label">New Username</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Choose your unique username" data-placement="right">
|
||||
<input name="name" type="text" class="form-control" id="name" value="" placeholder="Your username" data-error="Username required" data-minlength="5" data-minlength-error="Min. of 5 characters" data-username="true" autocomplete="nickname">
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{^register}}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Password</label>
|
||||
<div class="col-sm-9">
|
||||
<p class="form-control-static">
|
||||
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-dialog-icon-button collapsed"data-toggle="collapse" data-target="#collapsePassword" aria-expanded="false" aria-controls="collapsePassword"></i>
|
||||
<i class="fa fa-fw fa-ellipsis-h"></i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{! Email }}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Email</label>
|
||||
<div class="col-sm-9">
|
||||
<p class="form-control-static">
|
||||
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-dialog-icon-button collapsed" data-toggle="collapse" data-target="#collapseEmail" aria-expanded="false" aria-controls="collapseEmail"></i>
|
||||
{{#userData.email}}
|
||||
{{userData.email}}
|
||||
{{/userData.email}}
|
||||
{{^userData.email}}
|
||||
unknown
|
||||
{{/userData.email}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{/register}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="collapsePassword" class="{{^register}}collapse{{/register}}">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="password" class="col-sm-3 control-label">New Password</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter your password. Do not use your EVE password" data-placement="right">
|
||||
<input name="password" type="password" class="form-control" id="password" placeholder="" data-minlength="6" data-minlength-error="Min. of 6 characters" autocomplete="new-password" {{#register}}required{{/register}}>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-lock"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="password_confirm" class="col-sm-3 control-label">Confirm Password</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Confirm your password" data-placement="right">
|
||||
<input name="password_confirm" type="password" class="form-control" id="password_confirm" placeholder="" data-minlength="6" data-minlength-error="Min. of 6 characters" data-match="#password" data-match-error="Password fields do not match" autocomplete="new-password" {{#register}}required{{/register}}>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-lock"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
<div id="collapseEmail" class="collapse">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="email" class="col-sm-3 control-label">New Email</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter your email. It will be kept private!" data-placement="right">
|
||||
<input name="email" type="email" class="form-control" id="email" value="" placeholder="your@email.com" data-error="Email required" autocomplete="email" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-envelope"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,124 +93,137 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label"></label>
|
||||
<label for="email_confirm" class="col-sm-3 control-label">Confirm Email</label>
|
||||
<div class="col-sm-6">
|
||||
<p id="{{captchaImageWrapperId}}">
|
||||
<img id="{{captchaImageId}}" src="">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="captcha" class="col-sm-3 control-label">Captcha</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter the characters seen above" data-placement="right">
|
||||
<input name="captcha" type="text" class="form-control" id="captcha" placeholder="" data-minlength="6" data-minlength-error="Min. of 6 characters" autocomplete="off" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-refresh"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
<div class="input-group" title="Confirm your email" data-placement="right">
|
||||
<input name="email_confirm" type="email" class="form-control" id="email_confirm" value="" placeholder="your@email.com" data-error="Email required" data-match="#email" data-match-error="Email fields do not match" autocomplete="email" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-envelope"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="{{formErrorContainerClass}} alert alert-danger" style="display: none;">
|
||||
<span class="txt-color txt-color-danger">Error</span>
|
||||
<small> (important non-critical information)</small>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{! api tab ================================================================================================ }}
|
||||
<div role="tabpanel" class="tab-pane fade" id="pf-dialog-settings-api">
|
||||
<form role="form" class="form-horizontal">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-11">
|
||||
<blockquote>
|
||||
<p>
|
||||
API Key(s) are required to use <em class="pf-brand">pathfinder</em>.
|
||||
Don't have one? - Create a new key with an empty 'Access Mask' (8).
|
||||
{{! Captcha }}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label"></label>
|
||||
<div class="col-sm-9">
|
||||
<p id="{{captchaImageWrapperId}}" class="form-control-static">
|
||||
<i class="fa fa-fw fa-lg fa-refresh pull-right pf-dialog-icon-button collapsed"></i>
|
||||
<img id="{{captchaImageId}}" src="">
|
||||
</p>
|
||||
<small>Get your new/custom API Key from
|
||||
<a href="https://community.eveonline.com/support/api-key/CreatePredefined?accessMask=8" target="_blank">here</a>
|
||||
and come back to this page.
|
||||
</small>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#userData.api}}
|
||||
<div class="row {{cloneApiRowClass}}">
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="keyId" class="col-sm-4 control-label">Key ID</label>
|
||||
<div class="col-sm-8">
|
||||
<input name="keyId[]" type="text" value="{{keyId}}" class="form-control" id="keyId" placeholder="123456" data-error="Field is required" data-minlength="4" data-minlength-error="Min. of 4 characters" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5">
|
||||
<div class="form-group">
|
||||
<label for="vCode" class="col-sm-2 control-label">vCode</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="vCode[]" type="text" value="{{vCode}}" class="form-control" id="vCode" placeholder="XXXXXXXXXX" data-error="Field is required" data-minlength="64" data-minlength-error="Min. of 64 characters" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
|
||||
<button class="btn btn-danger collapsed pull-left {{deleteRowButtonClass}}">
|
||||
<i class="fa fa-close"></i>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-default collapsed pull-right {{cloneRowButtonClass}}">
|
||||
<i class="fa fa-fw fa-plus"></i> add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{/userData.api}}
|
||||
|
||||
<div class="{{formErrorContainerClass}} alert alert-danger" style="display: none;">
|
||||
<span class="txt-color txt-color-danger">Error</span>
|
||||
<small> (important non-critical information)</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="{{formWarningContainerClass}} alert alert-warning" style="display: none;">
|
||||
<span class="txt-color txt-color-warning">Warning</span>
|
||||
<small> (important non-critical information)</small>
|
||||
<div class="row">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="captcha" class="col-sm-3 control-label">Captcha</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group" title="Enter Captcha" data-placement="right">
|
||||
<input name="captcha" type="text" class="form-control" id="captcha" placeholder="" data-error="Captcha required" data-minlength="6" maxlength="6" autocomplete="off" required>
|
||||
<span class="input-group-addon"><i class="fa fa-fw fa-picture-o"></i></span>
|
||||
</div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{! character tab ================================================================================================ }}
|
||||
<div role="tabpanel" class="tab-pane fade" id="pf-dialog-settings-character">
|
||||
<form role="form" class="form-horizontal">
|
||||
|
||||
</form>
|
||||
</div>
|
||||
{{! finish tab ================================================================================================ }}
|
||||
<div role="tabpanel" class="tab-pane fade" id="pf-dialog-settings-done">
|
||||
<form role="form" class="form-horizontal">
|
||||
<h1 style="opacity: 0;" class="text-center txt-color txt-color-green"><strong><i class="fa fa-check fa-lg"></i> Complete</strong></h1>
|
||||
<h5 class="text-center">Click next to finish</h5>
|
||||
</form>
|
||||
</div>
|
||||
<div class="{{formErrorContainerClass}} alert alert-danger" style="display: none;">
|
||||
<span class="txt-color txt-color-danger">Error</span>
|
||||
<small> (important non-critical information)</small>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="{{settingsShareContainerId}}">
|
||||
{{! sharing tab ================================================================================================ }}
|
||||
|
||||
<form role="form" class="form-horizontal">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-11">
|
||||
<blockquote>
|
||||
<p>
|
||||
Before other pilots, corporations or alliances can invite you to their maps, you have to enable the associated option.
|
||||
</p>
|
||||
<small>Check out the "<a href="javascript:void(0);" onclick="$(document).triggerMenuEvent('Manual');">manual</a>" for more information
|
||||
</small>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#userData.character}}
|
||||
<h2 class="pf-dynamic-area"><img src="{{ccpImageServer}}Character/{{id}}_32.jpg"> Private maps "<em class="pf-map-type-private">{{name}}</em>"</h2>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox col-sm-10">
|
||||
<label for="privateSharing">
|
||||
<input id="privateSharing" type="checkbox" name="privateSharing" data-toggle="toggle" value="1" {{#shared}}checked{{/shared}}>
|
||||
map invite for private maps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#corporation}}
|
||||
<h2 class="pf-dynamic-area"><img src="{{ccpImageServer}}Corporation/{{id}}_32.png"> Corporation maps "<em class="pf-map-type-corporation">{{name}}</em>"</h2>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox col-sm-10">
|
||||
<label for="corporationSharing">
|
||||
<input id="corporationSharing" type="checkbox" name="corporationSharing" data-toggle="toggle" value="1" {{#shared}}checked{{/shared}}>
|
||||
map invite for corporation maps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/corporation}}
|
||||
|
||||
{{#alliance}}
|
||||
<h2 class="pf-dynamic-area"><img src="{{ccpImageServer}}Alliance/{{id}}_32.png"> Alliance maps "<em class="pf-map-type-alliance">{{name}}</em>"</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox col-sm-10">
|
||||
<label for="allianceSharing">
|
||||
<input id="allianceSharing" type="checkbox" name="allianceSharing" data-toggle="toggle" value="1" {{#shared}}checked{{/shared}}>
|
||||
map invite for alliance maps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{/alliance}}
|
||||
|
||||
<input type="hidden" name="share">
|
||||
|
||||
{{/userData.character}}
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,78 +0,0 @@
|
||||
<div id="{{id}}" >
|
||||
|
||||
<form role="form" class="form-horizontal">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-11">
|
||||
<blockquote>
|
||||
<p>
|
||||
Before other pilots, corporations or alliances can invite you to their maps, you have to enable the associated option.
|
||||
</p>
|
||||
<small>Check out the "<a href="javascript:void(0);" onclick="$(document).triggerMenuEvent('Manual');">manual</a>" for more information
|
||||
</small>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{#userData.character}}
|
||||
<h2 class="pf-dynamic-area"><img src="{{ccpImageServer}}Character/{{id}}_32.jpg"> Private maps "<em class="pf-map-type-private">{{userData.name}}</em>"</h2>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox col-sm-10">
|
||||
<label for="privateSharing">
|
||||
<input id="privateSharing" type="checkbox" name="privateSharing" data-toggle="toggle" value="1" {{#userData.shared}}checked{{/userData.shared}}>
|
||||
map invite for private maps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#corporation}}
|
||||
<h2 class="pf-dynamic-area"><img src="{{ccpImageServer}}Corporation/{{id}}_32.png"> Corporation maps "<em class="pf-map-type-corporation">{{name}}</em>"</h2>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox col-sm-10">
|
||||
<label for="corporationSharing">
|
||||
<input id="corporationSharing" type="checkbox" name="corporationSharing" data-toggle="toggle" value="1" {{#shared}}checked{{/shared}}>
|
||||
map invite for corporation maps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/corporation}}
|
||||
|
||||
{{#alliance}}
|
||||
<h2 class="pf-dynamic-area"><img src="{{ccpImageServer}}Alliance/{{id}}_32.png"> Alliance maps "<em class="pf-map-type-alliance">{{name}}</em>"</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox col-sm-10">
|
||||
<label for="allianceSharing">
|
||||
<input id="allianceSharing" type="checkbox" name="allianceSharing" data-toggle="toggle" value="1" {{#shared}}checked{{/shared}}>
|
||||
map invite for alliance maps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/alliance}}
|
||||
{{/userData.character}}
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -1,59 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-11">
|
||||
<blockquote>
|
||||
<p>
|
||||
Please choose your main character. <em>Pathfinder</em> will take these character if you use the <em>OGB</em>.
|
||||
The <em>IGB</em> will autodetect your current character.
|
||||
</p>
|
||||
<small>You can also change your main characters later on.
|
||||
</small>
|
||||
</blockquote>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row text-center">
|
||||
{{#charactersData}}
|
||||
<div class="col {{gridClass}}">
|
||||
<div class="pf-dynamic-area">
|
||||
<div data-id="{{id}}" class="{{imageWrapperClass}}
|
||||
{{#isMain}}
|
||||
{{imageWrapperMainClass}}
|
||||
{{/isMain}}
|
||||
">
|
||||
<div class="pf-dialog-image">
|
||||
<img class="pf-dialog-character-image" src="https://image.eveonline.com/Character/{{id}}_128.jpg" alt="{{characterName}}"/>
|
||||
|
||||
<div class="{{imageInfoClass}}">
|
||||
<div style="width: 128px">
|
||||
{{#corporation}}
|
||||
<img src="https://image.eveonline.com/Corporation/{{id}}_32.png"/>
|
||||
<div class="pf-dialog-character-info-text"><small>{{name}}</small></div>
|
||||
{{/corporation}}
|
||||
{{#alliance}}
|
||||
<img src="https://image.eveonline.com/Alliance/{{id}}_32.png"/>
|
||||
<div class="pf-dialog-character-info-text"><small>{{name}}</small></div>
|
||||
{{/alliance}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-dialog-character-name">
|
||||
<small>
|
||||
{{#status}}
|
||||
<i title="{{label}}" class="fa fa-fw fa-circle pf-user-status {{class}}"></i>
|
||||
{{/status}}
|
||||
{{name}}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/charactersData}}
|
||||
</div>
|
||||
|
||||
<div class="{{formWarningContainerClass}} alert alert-warning" style="display: none;">
|
||||
<span class="txt-color txt-color-warning">Warning</span>
|
||||
<small> (important non-critical information)</small>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="mainCharacterId" value="{{mainCharacter}}">
|
||||
@@ -12,7 +12,7 @@
|
||||
</svg>
|
||||
Menu
|
||||
</a>
|
||||
<p class="navbar-text {{userCharacterClass}}" title="settings">
|
||||
<p class="navbar-text {{userCharacterClass}}" title="switch character" data-easein="flipYIn">
|
||||
<a href="javascript:void(0);">
|
||||
<img class="{{userCharacterImageClass}}" src=""/>
|
||||
<span>{{! will be filled with current user name }}</span>
|
||||
|
||||
@@ -7,9 +7,14 @@
|
||||
</span>
|
||||
</h1>
|
||||
<p class="lead">
|
||||
Status: "<b>{{ @errorData->status }}</b>".
|
||||
Oooops, Something went wrong!
|
||||
You have experienced a technical error. We apologize.
|
||||
You have experienced a technical error. We apologize.<br><br>
|
||||
|
||||
Status: '{{ @errorData->status }}'<br>
|
||||
|
||||
<check if="{{ @errorData->message }}">
|
||||
Message: {{ @errorData->message }}
|
||||
</check>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="pf-system-info-popover">
|
||||
<div class="pf-character-info-popover">
|
||||
|
||||
<img class="pull-right" src="https://image.eveonline.com//Character/{{created.character.id}}_64.jpg">
|
||||
<img class="pull-right" src="https://image.eveonline.com//Character/{{created.character.id}}_32.jpg">
|
||||
|
||||
<h6>
|
||||
<small>
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<div style="height: 1px"> </div>
|
||||
|
||||
<img class="pull-right" src="https://image.eveonline.com//Character/{{updated.character.id}}_64.jpg">
|
||||
<img class="pull-right" src="https://image.eveonline.com//Character/{{updated.character.id}}_32.jpg">
|
||||
|
||||
<h6>
|
||||
<small>
|
||||
|
||||
11
public/templates/tooltip/character_switch.html
Normal file
11
public/templates/tooltip/character_switch.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="list-group">
|
||||
{{#otherCharacters}}
|
||||
<a class="list-group-item" href="{{routes.ssoLogin}}?characterId={{id}}">
|
||||
<img src="https://image.eveonline.com/Character/{{id}}_32.jpg" alt="{{name}}">
|
||||
{{name}}
|
||||
</a>
|
||||
{{/otherCharacters}}
|
||||
<a class="list-group-item" target="_self" href="{{routes.ssoLogin}}?characterId=-1">
|
||||
<i class="fa fa-user-plus fa-fw"></i>add new
|
||||
</a>
|
||||
</div>
|
||||
@@ -55,7 +55,7 @@
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="/public/css/pathfinder.css?{{ @PATHFINDER.VERSION }}">
|
||||
|
||||
</head>
|
||||
<body class="{{ @bodyClass }}" data-trusted="{{ @trusted }}" data-js-path="{{ @pathJs }}" data-script="{{ @jsView }}" data-invite="{{ @PATHFINDER.REGISTRATION.INVITE }}" data-version="{{ @PATHFINDER.VERSION }}">
|
||||
<body class="{{ @bodyClass }}" data-trusted="{{ @trusted }}" data-js-path="{{ @pathJs }}" data-script="{{ @jsView }}" data-version="{{ @PATHFINDER.VERSION }}">
|
||||
|
||||
<include if="{{ @pageContent }}" href="{{ @pageContent }}"/>
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row text-center">
|
||||
<div class="col-xs-12">
|
||||
<a class="pf-sso-login-button {{@registrationStatusButton}}" href="{{ 'sso','action=requestAuthorization' | alias }}" type="button" tabindex="3" title="{{@registrationStatusTitle}}"> </a><br>
|
||||
<a class="pf-sso-login-button {{@registrationStatusButton}}" target="_self" href="{{ 'sso','action=requestAuthorization' | alias }}" type="button" tabindex="3" title="{{@registrationStatusTitle}}"> </a><br>
|
||||
<a class="font-lg" target="_blank" href="http://community.eveonline.com/news/dev-blogs/eve-online-sso-and-what-you-need-to-know">What is this?</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -279,19 +279,6 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Invite (private mode)</td>
|
||||
<td class="text-right">
|
||||
<check if="{{ @PATHFINDER.REGISTRATION.INVITE }}">
|
||||
<true>
|
||||
<kbd class="txt-color txt-color-success">enabled</kbd>
|
||||
</true>
|
||||
<false>
|
||||
<kbd class="txt-color txt-color-warning">disabled</kbd>
|
||||
</false>
|
||||
</check>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max. invite limit</td>
|
||||
<td class="text-right"><kbd>{{ @PATHFINDER.REGISTRATION.INVITE_LIMIT }}</kbd></td>
|
||||
|
||||
@@ -77,13 +77,6 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// buttons ============================================================================
|
||||
// hide some button until they get triggered by JS
|
||||
.pf-dialog-finish-button, .pf-dialog-prev-button{
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// settings dialog ======================================================================
|
||||
@@ -94,131 +87,18 @@
|
||||
padding: 4px 7px 3px;
|
||||
}
|
||||
|
||||
// show add button only on last row
|
||||
.pf-dialog-api-row:not(:nth-last-child(3)) .pf-dialog-clone-button{
|
||||
display: none;
|
||||
}
|
||||
|
||||
// hide delete button if there is just a single api row
|
||||
.pf-dialog-api-row:nth-child(2):nth-last-child(3) .pf-dialog-delete-button{
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
// captcha image
|
||||
#pf-dialog-captcha-wrapper{
|
||||
margin: 0;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.pf-dynamic-area{
|
||||
display: inline-block;
|
||||
margin: 10px 5px 20px 5px;
|
||||
padding: 10px 10px 5px 10px;
|
||||
@include border-radius(10px);
|
||||
|
||||
// character images
|
||||
.pf-dialog-image-wrapper{
|
||||
opacity: 0;
|
||||
width: 128px;
|
||||
border: 2px solid $gray-light;
|
||||
@include border-radius(8px);
|
||||
@include transition( border-color 0.2s ease-out, box-shadow 0.2s ease-out);
|
||||
@include transform( translate3d(0, 0, 0) );
|
||||
will-change: border-color, transition;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
background-color: $gray-darker;
|
||||
box-sizing: content-box; // because of the borders and the fix img with of 128
|
||||
|
||||
// not main character star
|
||||
&:before{
|
||||
content: "\f005";
|
||||
font-family: FontAwesome;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
left: 6px;
|
||||
top: 4px;
|
||||
color: $gray-lighter;
|
||||
@include transition(color 0.2s ease-out);
|
||||
}
|
||||
|
||||
&.pf-dialog-character-main{
|
||||
border-color: $orange-dark;
|
||||
|
||||
&:hover{
|
||||
border-color: $orange;
|
||||
}
|
||||
|
||||
// mein character star
|
||||
&:before{
|
||||
color: $orange;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover{
|
||||
border-color: $teal-dark;
|
||||
@include box-shadow(0 4px 10px rgba(0,0,0, 0.4));
|
||||
|
||||
.pf-dialog-character-name{
|
||||
color: $teal-lighter;
|
||||
}
|
||||
|
||||
.pf-dialog-character-image{
|
||||
@include filter(grayscale(50%))
|
||||
}
|
||||
|
||||
&:before{
|
||||
color: $orange;
|
||||
}
|
||||
}
|
||||
|
||||
.pf-dialog-image{
|
||||
overflow: hidden;
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
position: relative;
|
||||
|
||||
// info element visible on hover
|
||||
.pf-dialog-character-info{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0; // trigger by js
|
||||
height: 100%;
|
||||
background: rgba($gray, 0.80);
|
||||
overflow: hidden;
|
||||
will-change: width, transition;
|
||||
padding: 10px 0;
|
||||
|
||||
.pf-dialog-character-info-text{
|
||||
line-height: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pf-dialog-character-name{
|
||||
font-size: 13px;
|
||||
line-height: 30px;
|
||||
border-top: 1px solid $gray-dark;
|
||||
@include transition( color 0.2s ease-out );
|
||||
}
|
||||
|
||||
.pf-dialog-character-image{
|
||||
@include transition(all 0.3s ease-out);
|
||||
@include filter(grayscale(0%));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// map settings dialog ====================================
|
||||
#pf-map-dialog{
|
||||
|
||||
#pf-map-dialog-user-select,
|
||||
#pf-map-dialog-character-select,
|
||||
#pf-map-dialog-corporation-select,
|
||||
#pf-map-dialog-alliance-select,{
|
||||
#pf-map-dialog-alliance-select{
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ em{
|
||||
// icon buttons =====================================================
|
||||
.pf-dialog-icon-button{
|
||||
cursor: pointer;
|
||||
margin-top: 2px;
|
||||
@include transition(color 0.15s ease-out);
|
||||
|
||||
&:not(.collapsed), &:hover{
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
|
||||
// popover =================================================================
|
||||
.pf-system-info-popover{
|
||||
.pf-character-info-popover{
|
||||
display: initial;
|
||||
|
||||
img{
|
||||
width: 39px
|
||||
.popover-content{
|
||||
padding: 0; // overwrite default popover padding
|
||||
}
|
||||
|
||||
h6{
|
||||
@@ -19,6 +19,34 @@
|
||||
margin-top: 7px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.list-group{
|
||||
margin: 0;
|
||||
|
||||
.list-group-item{
|
||||
color: $gray-dark;
|
||||
|
||||
&:hover{
|
||||
color: $gray-darkest;
|
||||
}
|
||||
|
||||
&.disabled{
|
||||
background-color: $gray;
|
||||
color: $gray-light;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
img{
|
||||
width: 30px;
|
||||
margin: -8px 10px -6px -8px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
i{
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// system info module ======================================================
|
||||
@@ -27,6 +55,7 @@
|
||||
// breadcrumb
|
||||
h5{
|
||||
text-transform: capitalize;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
// dynamic area specific for the description field
|
||||
|
||||
Reference in New Issue
Block a user