- #84 CREST Login (WIP)

- New CREST controller
- Database restructuring
- improved type-casting for some controller functions
- New login process
- Fixed some bugs during the setup process (/setup root)
- Added CREST request caching by response headers
This commit is contained in:
Exodus4D
2016-03-12 16:32:15 +01:00
parent 6fae6088d8
commit 7e94ec4889
39 changed files with 1804 additions and 1465 deletions

View File

@@ -2,16 +2,16 @@
[ENVIRONMENT]
; project environment (DEVELOP, PRODUCTION).
; This effects: DB connection, Mail-Server connection
; This effects: DB connection, Mail-Server, SSO, CREST configurations in this file
; configuration below
SERVER = DEVELOP
[ENVIRONMENT.DEVELOP]
; base dir (Default: "auto-detect"
; base dir (Default: "auto-detect")
BASE =
; deployment URL e.g. http://localhost
; deployment URL (e.g. http://localhost)
URL = http://pathfinder.local
; Verbosity level of the stack trace
; level of debug/error stack trace
DEBUG = 3
; main db
DB_DNS = mysql:host=localhost;port=3306;dbname=
@@ -25,11 +25,13 @@ DB_CCP_NAME = eve_parallax_min
DB_CCP_USER = root
DB_CCP_PASS =
; CCP SSO settings
; CCP SSO settings (OAuth2) - visit: https://developers.eveonline.com/applications
CCP_CREST_URL = https://api-sisi.testeveonline.com
SSO_CCP_URL = https://sisilogin.testeveonline.com
SSO_CCP_CLIENT_ID =
SSO_CCP_SECRET_KEY =
; SMTP settings. see: https://developers.eveonline.com/applications
; SMTP settings (optional)
SMTP_HOST = localhost
SMTP_PORT = 25
SMTP_SCHEME = ""
@@ -40,10 +42,11 @@ SMTP_FROM = pathfinder@localhost.com
SMTP_ERROR = pathfinder@localhost.com
[ENVIRONMENT.PRODUCTION]
; base dir (Default: "auto-detect"
BASE = /www/htdocs/www.pathfinder-w.space
; deployment URL
; deployment URL (e.g. https://www.pathfinder-w.space)
URL = https://www.pathfinder-w.space
; Verbosity level of the stack trace
; level of debug/error stack trace
DEBUG = 0
; main db
DB_DNS = mysql:host=localhost;port=3306;dbname=
@@ -58,10 +61,12 @@ DB_CCP_USER =
DB_CCP_PASS =
; CCP SSO settings
CCP_CREST_URL = https://crest-tq.eveonline.com
SSO_CCP_URL = https://login.eveonline.com
SSO_CCP_CLIENT_ID =
SSO_CCP_SECRET_KEY =
; SMTP settings
; SMTP settings (optional)
SMTP_HOST = localhost
SMTP_PORT = 25
SMTP_SCHEME = TLS

View File

@@ -7,20 +7,21 @@
*/
namespace Controller;
use Controller\Api as Api;
use Model;
class AccessController extends Controller {
/**
* event handler
* @param $f3
* @param \Base $f3
*/
function beforeroute($f3) {
function beforeroute(\Base $f3) {
parent::beforeroute($f3);
// Any CMS route of a child class of this one, requires a
// valid logged in user!
$loginCheck = $this->_checkLogIn();
$loginCheck = $this->checkLogIn($f3);
if( !$loginCheck ){
// no user found or LogIn timer expired
@@ -30,16 +31,16 @@ class AccessController extends Controller {
/**
* checks weather a user is currently logged in
* @param \Base $f3
* @return bool
*/
private function _checkLogIn(){
private function checkLogIn($f3){
$loginCheck = false;
if($this->f3->get('SESSION.user.time') > 0){
if($f3->get(Api\User::SESSION_KEY_CHARACTER_TIME) > 0){
// check logIn time
$logInTime = new \DateTime();
$logInTime->setTimestamp($this->f3->get('SESSION.user.time'));
$logInTime->setTimestamp( $f3->get(Api\User::SESSION_KEY_CHARACTER_TIME) );
$now = new \DateTime();
$timeDiff = $now->diff($logInTime);
@@ -48,7 +49,7 @@ class AccessController extends Controller {
$minutes += $timeDiff->h * 60;
$minutes += $timeDiff->i;
if($minutes <= $this->f3->get('PATHFINDER.TIMER.LOGGED')){
if($minutes <= $f3->get('PATHFINDER.TIMER.LOGGED')){
$loginCheck = true;
}
}

View File

@@ -7,27 +7,26 @@
*/
namespace Controller\Api;
use Controller;
use Model;
class Connection extends \Controller\AccessController{
class Connection extends Controller\AccessController{
/**
* @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);
}
/**
* save a new connection or updates an existing (drag/drop) between two systems
* if a connection is changed (drag&drop) to another system. -> this function is called for update
* @param $f3
* @param \Base $f3
*/
public function save($f3){
public function save(\Base $f3){
$postData = (array)$f3->get('POST');
$newConnectionData = [];
@@ -38,10 +37,15 @@ class Connection extends \Controller\AccessController{
$mapData = (array)$postData['mapData'];
$connectionData = (array)$postData['connectionData'];
$user = $this->_getUser();
$activeCharacter = $this->getCharacter();
if($activeCharacter){
$user = $activeCharacter->getUser();
if($user){
// get map model and check map access
/**
* @var Model\MapModel $map
*/
$map = Model\BasicModel::getNew('MapModel');
$map->getById( (int)$mapData['id'] );
@@ -90,16 +94,22 @@ class Connection extends \Controller\AccessController{
echo json_encode($newConnectionData);
}
public function delete($f3){
/**
* delete connection
* @param \Base $f3
* @throws \Exception
*/
public function delete(\Base $f3){
$connectionIds = $f3->get('POST.connectionIds');
$activeCharacter = $this->getCharacter();
$user = $this->_getUser();
/**
* @var Model\ConnectionModel $connection
*/
$connection = Model\BasicModel::getNew('ConnectionModel');
foreach($connectionIds as $connectionId){
$connection->getById($connectionId);
$connection->delete($user);
$connection->delete( $activeCharacter->getUser() );
$connection->reset();
}

View File

@@ -7,6 +7,7 @@
*/
namespace Controller\Api;
use Controller;
use Model;
/**
@@ -14,25 +15,23 @@ use Model;
* Class Map
* @package Controller\Api
*/
class Map extends \Controller\AccessController {
class Map extends Controller\AccessController {
/**
* event handler
* @param $f3
* @param \Base $f3
*/
function beforeroute($f3) {
function beforeroute(\Base $f3) {
// set header for all routes
header('Content-type: application/json');
parent::beforeroute($f3);
}
/**
* Get all required static config data for program initialization
* @param $f3
* @param \Base $f3
*/
public function init($f3){
public function init(\Base $f3){
// expire time in seconds
$expireTimeHead = 60 * 60 * 12;
@@ -143,9 +142,9 @@ class Map extends \Controller\AccessController {
/**
* import new map data
* @param $f3
* @param \Base $f3
*/
public function import($f3){
public function import(\Base $f3){
$importData = (array)$f3->get('POST');
$return = (object) [];
@@ -155,13 +154,24 @@ class Map extends \Controller\AccessController {
isset($importData['typeId']) &&
count($importData['mapData']) > 0
){
$user = $this->_getUser();
$activeCharacter = $this->getCharacter();
if($user){
$activeCharacter = $user->getActiveUserCharacter();
if($activeCharacter){
$user = $activeCharacter->getUser();
/**
* @var $map Model\MapModel
*/
$map = Model\BasicModel::getNew('MapModel');
/**
* @var $system Model\SystemModel
*/
$system = Model\BasicModel::getNew('SystemModel');
/**
* @var $connection Model\ConnectionModel
*/
$connection = Model\BasicModel::getNew('ConnectionModel');
foreach($importData['mapData'] as $mapData){
@@ -194,8 +204,8 @@ class Map extends \Controller\AccessController {
$system->setData($systemData);
$system->mapId = $map;
$system->createdCharacterId = $activeCharacter->characterId;
$system->updatedCharacterId = $activeCharacter->characterId;
$system->createdCharacterId = $activeCharacter;
$system->updatedCharacterId = $activeCharacter;
$system->save();
$tempSystemIdMapping[$oldId] = $system->id;
@@ -228,13 +238,11 @@ class Map extends \Controller\AccessController {
if($map->isPrivate()){
$map->setAccess($user);
}elseif($map->isCorporation()){
$corporation = $activeCharacter->getCharacter()->getCorporation();
if($corporation){
if($corporation = $activeCharacter->getCorporation()){
$map->setAccess($corporation);
}
}elseif($map->isAlliance()){
$alliance = $activeCharacter->getCharacter()->getAlliance();
if($alliance){
if($alliance = $activeCharacter->getAlliance()){
$map->setAccess($alliance);
}
}
@@ -260,7 +268,7 @@ class Map extends \Controller\AccessController {
}
}else{
// user not found
$return->error[] = $this->getUserLoggedOffError();
$return->error[] = $this->getLogoutError();
}
}else{
// map data missing
@@ -276,19 +284,23 @@ class Map extends \Controller\AccessController {
/**
* save a new map or update an existing map
* @param $f3
* @param \Base $f3
*/
public function save($f3){
public function save(\Base $f3){
$formData = (array)$f3->get('POST.formData');
$return = (object) [];
$return->error = [];
if( isset($formData['id']) ){
$activeCharacter = $this->getCharacter(0);
$user = $this->_getUser(0);
if($activeCharacter){
$user = $activeCharacter->getUser();
if($user){
/**
* @var $map Model\MapModel
*/
$map = Model\BasicModel::getNew('MapModel');
$map->getById( (int)$formData['id'] );
@@ -311,6 +323,9 @@ class Map extends \Controller\AccessController {
// clear map access. In case something has removed from access list
$map->clearAccess();
/**
* @var $tempUser Model\UserModel
*/
$tempUser = Model\BasicModel::getNew('UserModel');
foreach($accessUsers as $userId){
@@ -331,90 +346,86 @@ class Map extends \Controller\AccessController {
// just in case he removed himself :)
$map->setAccess($user);
}elseif($map->isCorporation()){
$activeCharacter = $user->getActiveUserCharacter();
$corporation = $activeCharacter->getCorporation();
if($activeCharacter){
$corporation = $activeCharacter->getCharacter()->getCorporation();
if($corporation){
// the current user has to have a corporation when
// working on corporation maps!
if($corporation){
// the current user has to have a corporation when
// working on corporation maps!
// share map between corporations -> set access
if(isset($formData['mapCorporations'])){
// avoid abuse -> respect share limits
$accessCorporations = array_slice( $formData['mapCorporations'], 0, $f3->get('PATHFINDER.MAX_SHARED_CORPORATION') );
// share map between corporations -> set access
if(isset($formData['mapCorporations'])){
// avoid abuse -> respect share limits
$accessCorporations = array_slice( $formData['mapCorporations'], 0, $f3->get('PATHFINDER.MAX_SHARED_CORPORATION') );
// clear map access. In case something has removed from access list
$map->clearAccess();
// clear map access. In case something has removed from access list
$map->clearAccess();
/**
* @var $tempCorporation Model\CorporationModel
*/
$tempCorporation = Model\BasicModel::getNew('CorporationModel');
$tempCorporation = Model\BasicModel::getNew('CorporationModel');
foreach($accessCorporations as $corporationId){
$tempCorporation->getById( (int)$corporationId );
foreach($accessCorporations as $corporationId){
$tempCorporation->getById( (int)$corporationId );
if(
!$tempCorporation->dry() &&
$tempCorporation->shared == 1 // check if map shared is enabled
){
$map->setAccess($tempCorporation);
}
$tempCorporation->reset();
if(
!$tempCorporation->dry() &&
$tempCorporation->shared == 1 // check if map shared is enabled
){
$map->setAccess($tempCorporation);
}
}
// the corporation of the current user should always have access
$map->setAccess($corporation);
$tempCorporation->reset();
}
}
// the corporation of the current user should always have access
$map->setAccess($corporation);
}
}elseif($map->isAlliance()){
$activeCharacter = $user->getActiveUserCharacter();
$alliance = $activeCharacter->getAlliance();
if($activeCharacter){
$alliance = $activeCharacter->getCharacter()->getAlliance();
if($alliance){
// the current user has to have a alliance when
// working on alliance maps!
if($alliance){
// the current user has to have a alliance when
// working on alliance maps!
// share map between alliances -> set access
if(isset($formData['mapAlliances'])){
// avoid abuse -> respect share limits
$accessAlliances = array_slice( $formData['mapAlliances'], 0, $f3->get('PATHFINDER.MAX_SHARED_ALLIANCE') );
// share map between alliances -> set access
if(isset($formData['mapAlliances'])){
// avoid abuse -> respect share limits
$accessAlliances = array_slice( $formData['mapAlliances'], 0, $f3->get('PATHFINDER.MAX_SHARED_ALLIANCE') );
// clear map access. In case something has removed from access list
$map->clearAccess();
// clear map access. In case something has removed from access list
$map->clearAccess();
/**
* @var $tempAlliance Model\AllianceModel
*/
$tempAlliance = Model\BasicModel::getNew('AllianceModel');
$tempAlliance = Model\BasicModel::getNew('AllianceModel');
foreach($accessAlliances as $allianceId){
$tempAlliance->getById( (int)$allianceId );
foreach($accessAlliances as $allianceId){
$tempAlliance->getById( (int)$allianceId );
if(
!$tempAlliance->dry() &&
$tempAlliance->shared == 1 // check if map shared is enabled
){
$map->setAccess($tempAlliance);
}
$tempAlliance->reset();
if(
!$tempAlliance->dry() &&
$tempAlliance->shared == 1 // check if map shared is enabled
){
$map->setAccess($tempAlliance);
}
$tempAlliance->reset();
}
// the alliance of the current user should always have access
$map->setAccess($alliance);
}
// the alliance of the current user should always have access
$map->setAccess($alliance);
}
}
// reload the same map model (refresh)
// this makes sure all data is up2date
$map->getById( $map->id, 0 );
$return->mapData = $map->getData();
}else{
// map access denied
$captchaError = (object) [];
@@ -423,7 +434,6 @@ class Map extends \Controller\AccessController {
$return->error[] = $captchaError;
}
}
}else{
// map id field missing
$idError = (object) [];
@@ -437,17 +447,19 @@ class Map extends \Controller\AccessController {
/**
* delete a map and all dependencies
* @param $f3
* @param \Base $f3
*/
public function delete($f3){
public function delete(\Base $f3){
$mapData = (array)$f3->get('POST.mapData');
$activeCharacter = $this->getCharacter();
$user = $this->_getUser();
if($user){
if($activeCharacter){
/**
* @var $map Model\MapModel
*/
$map = Model\BasicModel::getNew('MapModel');
$map->getById($mapData['id']);
$map->delete($user);
$map->delete( $activeCharacter->getUser() );
}
echo json_encode([]);
@@ -455,34 +467,28 @@ class Map extends \Controller\AccessController {
/**
* update map data
* function is called continuously
* @param $f3
* -> function is called continuously (trigger) by any active client
* @param \Base $f3
*/
public function updateData($f3){
// 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;
public function updateData(\Base $f3){
$mapData = (array)$f3->get('POST.mapData');
$user = $this->_getUser();
$activeCharacter = $this->getCharacter();
$return = (object) [];
$return->error = [];
if($user){
// -> get active character
$activeCharacter = $user->getActiveUserCharacter();
if($activeCharacter){
$cacheKey = 'user_map_data_' . $activeCharacter->id;
// if there is any system/connection change data submitted -> save new data
if(
$f3->exists($cacheKey) === false ||
!$f3->exists($cacheKey) ||
!empty($mapData)
){
// get current map data ========================================================
$maps = $user->getMaps();
$maps = $activeCharacter->getUser()->getMaps();
// loop all submitted map data that should be saved
// -> currently there will only be ONE map data change submitted -> single loop
@@ -532,7 +538,7 @@ class Map extends \Controller\AccessController {
unset($systemData['updated']);
$system = $filteredMap->systems->current();
$system->setData($systemData);
$system->updatedCharacterId = $activeCharacter->characterId;
$system->updatedCharacterId = $activeCharacter;
$system->save();
// a system belongs to ONE map -> speed up for multiple maps
@@ -561,7 +567,7 @@ class Map extends \Controller\AccessController {
unset($connectionData['updated']);
$connection = $filteredMap->connections->current();
$connection->setData($connectionData);
$connection->save($user);
$connection->save();
// a connection belongs to ONE map -> speed up for multiple maps
unset($connectionData[$i]);
@@ -574,6 +580,11 @@ class Map extends \Controller\AccessController {
// format map Data for return
$return->mapData = self::getFormattedMapData($maps);
// 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;
$f3->set($cacheKey, $return, $responseTTL);
}else{
// get from cache
@@ -582,23 +593,24 @@ class Map extends \Controller\AccessController {
}else{
// user logged off
$return->error[] = $this->getUserLoggedOffError();
$return->error[] = $this->getLogoutError();
}
echo json_encode( $return );
}
/**
* get formatted map data
* @param $mapModels
* @return Model\MapModel[]
* @return array
*/
public static function getFormattedMapData($mapModels){
$mapData = [];
foreach($mapModels as $mapModel){
foreach($mapModels as &$mapModel){
/**
* @var $mapModel Model\MapModel
*/
$allMapData = $mapModel->getData();
$mapData[] = [
'config' => $allMapData->mapData,
'data' => [
@@ -613,33 +625,23 @@ class Map extends \Controller\AccessController {
/**
* update map data api
* function is called continuously
* @param $f3
* -> function is called continuously by any active client
* @param \Base $f3
*/
public function updateUserData($f3){
// cache time(s) should be equal or less than request trigger time
// prevent request flooding
$responseTTL = $f3->get('PATHFINDER.TIMER.UPDATE_SERVER_USER_DATA.DELAY') / 1000;
// if the cache key will be set -> cache request
$cacheKey = null;
public function updateUserData(\Base $f3){
$return = (object) [];
$return->error = [];
$activeCharacter = $this->getCharacter();
$user = $this->_getUser();
if($user){
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 (IGB data)
$user->updateCharacterLog(60 * 5);
// update current location
$activeCharacter->updateLog();
// if data is requested extend the cache key in order to get new data
$requestSystemData = (object) [];
@@ -649,12 +651,11 @@ class Map extends \Controller\AccessController {
// IMPORTANT for now -> just update a single map (save performance)
$mapIds = array_slice($mapIds, 0, 1);
// the userMasData is cached per map (this must be changed if multiple maps
// the userMapData is cached per map (this must be changed if multiple maps
// will be allowed in future...
$tempId = (int)$mapIds[0];
$cacheKey = 'user_data_' . $tempId . '_' . $requestSystemData->systemId;
if( $f3->exists($cacheKey) === false ){
if( !$f3->exists($cacheKey) ){
foreach($mapIds as $mapId){
$map = $user->getMap($mapId);
@@ -666,7 +667,7 @@ class Map extends \Controller\AccessController {
$system = $map->getSystem( $requestSystemData->systemId );
if( !is_null($system) ){
// data for the current selected system
// data for currently selected system
$return->system = $system->getData();
$return->system->signatures = $system->getSignaturesData();
}
@@ -674,6 +675,10 @@ 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;
// cache response
$f3->set($cacheKey, $return, $responseTTL);
}else{
@@ -683,17 +688,14 @@ 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();
}else{
// user logged off
$return->error[] = $this->getUserLoggedOffError();
$return->error[] = $this->getLogoutError();
}
echo json_encode( $return );
}

View File

@@ -14,14 +14,12 @@ class Signature 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);
}
/**
@@ -31,18 +29,18 @@ class Signature extends \Controller\AccessController{
public function getAll($f3){
$signatureData = [];
$systemIds = $f3->get('POST.systemIds');
$activeCharacter = $this->getCharacter();
$user = $this->_getUser();
/**
* @var Model\SystemModel $system
*/
$system = Model\BasicModel::getNew('SystemModel');
foreach($systemIds as $systemId){
$system->getById($systemId);
if(!$system->dry()){
// check access
if($system->hasAccess($user)){
if( $system->hasAccess($activeCharacter->getUser()) ){
$signatureData = $system->getSignaturesData();
}
}
@@ -74,11 +72,14 @@ class Signature extends \Controller\AccessController{
}
if( !is_null($signatureData) ){
$user = $this->_getUser();
$activeCharacter = $this->getCharacter();
if($user){
$activeUserCharacter = $user->getActiveUserCharacter();
$activeCharacter = $activeUserCharacter->getCharacter();
if($activeCharacter){
$user = $activeCharacter->getUser();
/**
* @var Model\SystemModel $system
*/
$system = Model\BasicModel::getNew('SystemModel');
// update/add all submitted signatures
@@ -173,23 +174,23 @@ class Signature extends \Controller\AccessController{
/**
* delete signatures
* @param $f3
* @param \Base $f3
*/
public function delete($f3){
$signatureIds = $f3->get('POST.signatureIds');
$activeCharacter = $this->getCharacter();
$user = $this->_getUser();
/**
* @var Model\SystemSignatureModel $signature
*/
$signature = Model\BasicModel::getNew('SystemSignatureModel');
foreach($signatureIds as $signatureId){
$signature->getById($signatureId);
$signature->delete($user);
$signature->delete( $activeCharacter->getUser() );
$signature->reset();
}
echo json_encode([]);
}
}

View File

@@ -63,9 +63,9 @@ class System extends \Controller\AccessController {
private $limitQuery = "";
/**
* @param $f3
* @param \Base $f3
*/
function beforeroute($f3) {
function beforeroute(\Base $f3) {
parent::beforeroute($f3);
@@ -92,7 +92,8 @@ class System extends \Controller\AccessController {
* get static system Data from CCPs Static DB export
* search column for IDs can be (solarSystemID, regionID, constellationID)
* @param array $columnIDs
* @return null
* @param string $column
* @return Model\SystemModel[]
* @throws \Exception
*/
protected function _getSystemModelByIds($columnIDs = [], $column = 'solarSystemID'){
@@ -110,10 +111,12 @@ class System extends \Controller\AccessController {
// format result
$mapper = new Mapper\CcpSystemsMapper($rows);
$ccpSystemsData = $mapper->getData();
foreach($ccpSystemsData as $ccpSystemData){
/**
* @var Model\SystemModel $system
*/
$system = Model\BasicModel::getNew('SystemModel');
$system->setData($ccpSystemData);
$systemModels[] = $system;
@@ -142,10 +145,10 @@ class System extends \Controller\AccessController {
/**
* search systems by name
* @param $f3
* @param $params
* @param \Base $f3
* @param array $params
*/
public function search($f3, $params){
public function search(\Base $f3, $params){
$ccpDB = $this->getDB('CCP');
@@ -172,10 +175,9 @@ class System extends \Controller\AccessController {
/**
* save a new system to a a map
* @param $f3
* @param \Base $f3
*/
public function save($f3){
public function save(\Base $f3){
$newSystemData = [];
$postData = (array)$f3->get('POST');
@@ -187,20 +189,21 @@ class System extends \Controller\AccessController {
isset($postData['systemData']) &&
isset($postData['mapData'])
){
$user = $this->_getUser();
$activeCharacter = $this->getCharacter();
if($user){
if($activeCharacter){
$user = $activeCharacter->getUser();
$systemData = (array)$postData['systemData'];
$mapData = (array)$postData['mapData'];
$activeCharacter = $user->getActiveUserCharacter();
if( isset($systemData['id']) ){
// update existing system
/**
* @var $system Model\SystemModel
*/
$system = Model\BasicModel::getNew('SystemModel');
$system->getById($systemData['id']);
if( !$system->dry() ){
if( $system->hasAccess($user) ){
// system model found
@@ -210,9 +213,11 @@ class System extends \Controller\AccessController {
}elseif( isset($mapData['id']) ){
// save NEW system
/**
* @var $map Model\MapModel
*/
$map = Model\BasicModel::getNew('MapModel');
$map->getById($mapData['id']);
if( !$map->dry() ){
if( $map->hasAccess($user) ){
@@ -221,7 +226,7 @@ class System extends \Controller\AccessController {
// get static system data (CCP DB)
$systemModel = array_values( $this->_getSystemModelByIds([$systemData['systemId']]) )[0];
$systemModel->createdCharacterId = $activeCharacter->characterId;
$systemModel->createdCharacterId = $activeCharacter;
}
}
@@ -229,50 +234,23 @@ class System extends \Controller\AccessController {
}
}
if( !is_null($systemModel) ){
// set/update system
$systemModel->setData($systemData);
$systemModel->updatedCharacterId = $activeCharacter->characterId;
$systemModel->updatedCharacterId = $activeCharacter;
$systemModel->save();
$newSystemData = $systemModel->getData();
}
echo json_encode($newSystemData);
}
/**
* delete systems and all its connections
* @param $f3
*/
public function delete($f3){
$systemIds = $f3->get('POST.systemIds');
$user = $this->_getUser();
if($user){
$system = Model\BasicModel::getNew('SystemModel');
foreach((array)$systemIds as $systemId){
$system->getById($systemId);
$system->delete($user);
$system->reset();
}
}
echo json_encode([]);
}
/**
* get system log data from CCP API import
* system Kills, Jumps,....
* @param $f3
* @param \Base $f3
*/
public function graphData($f3){
public function graphData(\Base $f3){
$graphData = [];
$systemIds = $f3->get('POST.systemIds');
@@ -288,7 +266,6 @@ class System extends \Controller\AccessController {
];
foreach($systemIds as $systemId){
foreach($logTables as $label => $ModelClass){
$systemLogModel = Model\BasicModel::getNew($ModelClass);
@@ -313,7 +290,6 @@ class System extends \Controller\AccessController {
$counter++;
}
}
}
}
@@ -322,25 +298,22 @@ class System extends \Controller\AccessController {
/**
* get system data for all systems within a constellation
* @param $f3
* @param $params
* @param \Base $f3
* @param array $params
*/
public function constellationData($f3, $params){
public function constellationData(\Base $f3, $params){
$return = (object) [];
$return->error = [];
$return->systemData = [];
$constellationId = 0;
$activeCharacter = $this->getCharacter();
$user = $this->_getUser();
if($user){
if($activeCharacter){
// check for search parameter
if( isset($params['arg1']) ){
$constellationId = (int)$params['arg1'];
}
$cacheKey = 'CACHE_CONSTELLATION_SYSTEMS_' . self::formatHiveKey($constellationId);
if($f3->exists($cacheKey)){
@@ -361,7 +334,29 @@ class System extends \Controller\AccessController {
echo json_encode($return);
}
/**
* delete systems and all its connections
* @param \Base $f3
*/
public function delete(\Base $f3){
$systemIds = $f3->get('POST.systemIds');
$activeCharacter = $this->getCharacter();
if($activeCharacter){
$user = $activeCharacter->getUser();
/**
* @var Model\SystemModel $system
*/
$system = Model\BasicModel::getNew('SystemModel');
foreach((array)$systemIds as $systemId){
$system->getById($systemId);
$system->delete($user);
$system->reset();
}
}
echo json_encode([]);
}
}

View File

@@ -15,87 +15,76 @@ use DB;
class User extends Controller\Controller{
// user specific session keys
const SESSION_KEY_USER = 'SESSION.USER';
const SESSION_KEY_USER_ID = 'SESSION.USER.ID';
const SESSION_KEY_USER_NAME = 'SESSION.USER.NAME';
// character specific session keys
const SESSION_KEY_CHARACTER = 'SESSION.CHARACTER';
const SESSION_KEY_CHARACTER_ID = 'SESSION.CHARACTER.ID';
const SESSION_KEY_CHARACTER_NAME = 'SESSION.CHARACTER.NAME';
const SESSION_KEY_CHARACTER_TIME = 'SESSION.CHARACTER.TIME';
const SESSION_KEY_CHARACTER_ACCESS_TOKEN = 'SESSION.CHARACTER.ACCESS_TOKEN';
const SESSION_KEY_CHARACTER_REFRESH_TOKEN = 'SESSION.CHARACTER.REFRESH_TOKEN';
// log text
const LOG_LOGGED_IN = 'userId: %s, userName: %s, charId: %s, charName: %s';
/**
* valid reasons for captcha images
* @var array
* @var string array
*/
private static $captchaReason = ['createAccount', 'deleteAccount'];
/**
* login function
* @param $f3
* login a valid character
* @param Model\CharacterModel $characterModel
* @return bool
*/
public function logIn($f3){
$data = $data = $f3->get('POST');
protected function loginByCharacter(Model\CharacterModel &$characterModel){
$login = false;
$return = (object) [];
$user = null;
if($data['loginData']){
$loginData = $data['loginData'];
$user = $this->logUserIn( $loginData['userName'], $loginData['userPassword'] );
}
// set "vague" error
if(is_null($user)){
$return->error = [];
$loginError = (object) [];
$loginError->type = 'login';
$return->error[] = $loginError;
}else{
// update/check api data
$user->updateApiData();
// route user to map app
$return->reroute = rtrim(self::getEnvironmentData('URL'), '/') . $f3->alias('map');
}
echo json_encode($return);
}
/**
* core function for user login
* @param $userName
* @param $password
* @return Model\UserModel|null
*/
private function logUserIn($userName, $password){
// try to verify user
$user = $this->_verifyUser($userName, $password);
if( !is_null($user)){
// user is verified -> ready for login
// set Session login
$dateTime = new \DateTime();
$this->f3->set('SESSION.user', [
'time' => $dateTime->getTimestamp(),
'name' => $user->name,
'id' => $user->id
if($user = $characterModel->getUser()){
// set user/character data to session -------------------
$this->f3->set(self::SESSION_KEY_USER, [
'ID' => $user->_id,
'NAME' => $user->name
]);
// save user login information
$user->touch('lastLogin');
$user->save();
$dateTime = new \DateTime();
$this->f3->set(self::SESSION_KEY_CHARACTER, [
'ID' => $characterModel->_id,
'NAME' => $characterModel->name,
'TIME' => $dateTime->getTimestamp()
]);
// save log
$logText = "id: %s, name: %s, ip: %s";
// save user login information ---------------------------
$characterModel->touch('lastLogin');
$characterModel->save();
// write login log --------------------------------------
self::getLogger( $this->f3->get('PATHFINDER.LOGFILES.LOGIN') )->write(
sprintf($logText, $user->id, $user->name, $this->f3->get('IP'))
sprintf(self::LOG_LOGGED_IN,
$user->_id,
$user->name,
$characterModel->_id,
$characterModel->name
)
);
$login = true;
}
return $user;
return $login;
}
/**
* get captcha image and store key to session
* @param $f3
* @param \Base $f3
*/
public function getCaptcha($f3){
public function getCaptcha(\Base $f3){
$data = $f3->get('POST');
$return = (object) [];
@@ -136,29 +125,22 @@ class User extends Controller\Controller{
/**
* delete the character log entry for the current active (main) character
* @param $f3
* @param \Base $f3
*/
public function deleteLog($f3){
$user = $this->_getUser();
if($user){
$activeUserCharacter = $user->getActiveUserCharacter();
if($activeUserCharacter){
$character = $activeUserCharacter->getCharacter();
if($characterLog = $character->getLog()){
$characterLog->erase();
}
public function deleteLog(\Base $f3){
$activeCharacter = $this->getCharacter();
if($activeCharacter){
if($characterLog = $activeCharacter->getLog()){
$characterLog->erase();
}
}
}
/**
* log the current user out + clear character system log data
* @param $f3
* @param \Base $f3
*/
public function logOut($f3){
public function logOut(\Base $f3){
$this->deleteLog($f3);
parent::logOut($f3);
}
@@ -166,9 +148,9 @@ class User extends Controller\Controller{
/**
* save/update "map sharing" configurations for all map types
* the user has access to
* @param $f3
* @param \Base $f3
*/
public function saveSharingConfig($f3){
public function saveSharingConfig(\Base $f3){
$data = $f3->get('POST');
$return = (object) [];
@@ -177,9 +159,10 @@ class User extends Controller\Controller{
$corporationSharing = 0;
$allianceSharing = 0;
$user = $this->_getUser();
$activeCharacter = $this->getCharacter();
if($user){
if($activeCharacter){
$user = $activeCharacter->getUser();
// form values
if(isset($data['formData'])){
@@ -202,22 +185,17 @@ class User extends Controller\Controller{
$user->save();
// update corp/ally ---------------------------------------------------------------
$corporation = $activeCharacter->getCorporation();
$alliance = $activeCharacter->getAlliance();
$activeUserCharacter = $user->getActiveUserCharacter();
if(is_object($corporation)){
$corporation->shared = $corporationSharing;
$corporation->save();
}
if(is_object($activeUserCharacter)){
$corporation = $activeUserCharacter->getCharacter()->getCorporation();
$alliance = $activeUserCharacter->getCharacter()->getAlliance();
if(is_object($corporation)){
$corporation->shared = $corporationSharing;
$corporation->save();
}
if(is_object($alliance)){
$alliance->shared = $allianceSharing;
$alliance->save();
}
if(is_object($alliance)){
$alliance->shared = $allianceSharing;
$alliance->save();
}
$return->userData = $user->getData();
@@ -282,9 +260,9 @@ class User extends Controller\Controller{
/**
* save/update user account data
* @param $f3
* @param \Base $f3
*/
public function saveAccount($f3){
public function saveAccount(\Base $f3){
$data = $f3->get('POST');
$return = (object) [];
@@ -308,7 +286,8 @@ class User extends Controller\Controller{
$settingsData = $data['settingsData'];
try{
$user = $this->_getUser(0);
$activeCharacter = $this->getCharacter(0);
$user = $activeCharacter->getUser();
// captcha is send -> check captcha
if(
@@ -320,7 +299,7 @@ class User extends Controller\Controller{
if($settingsData['captcha'] === $captcha){
// change/set sensitive user data requires captcha!
if($user === false){
if(is_null($user)){
// check if registration key invite function is enabled
if($f3->get('PATHFINDER.REGISTRATION.INVITE') === 1 ){
@@ -332,7 +311,7 @@ class User extends Controller\Controller{
}
// new user registration
$user = $mapType = Model\BasicModel::getNew('UserModel');
$user = Model\BasicModel::getNew('UserModel');
$loginAfterSave = true;
// set username
@@ -429,7 +408,7 @@ class User extends Controller\Controller{
}
// get fresh updated user object (API info may have has changed)
$user = $this->_getUser(0);
//$user = $this->_getUser(0);
}
// set main character
@@ -457,14 +436,13 @@ class User extends Controller\Controller{
// log user in (in case he is new
if($loginAfterSave){
$this->logUserIn( $user->name, $settingsData['password'] );
$this->logInByData( $user->name, $settingsData['password'] );
// return reroute path
$return->reroute = rtrim(self::getEnvironmentData('URL'), '/') . $this->f3->alias('map');
}
// get fresh updated user object
$user = $this->_getUser(0);
$newUserData = $user->getData();
}
}catch(Exception\ValidationException $e){
@@ -491,10 +469,10 @@ class User extends Controller\Controller{
/**
* send mail with registration key
* -> check INVITE in pathfinder.ini
* @param $f3
* @param \Base $f3
* @throws Exception
*/
public function sendInvite($f3){
public function sendInvite(\Base $f3){
$data = $f3->get('POST.settingsData');
$return = (object) [];
@@ -593,9 +571,9 @@ class User extends Controller\Controller{
/**
* delete current user account from DB
* @param $f3
* @param \Base $f3
*/
public function deleteAccount($f3){
public function deleteAccount(\Base $f3){
$data = $f3->get('POST.formData');
$return = (object) [];
@@ -609,8 +587,8 @@ class User extends Controller\Controller{
!empty($data['captcha']) &&
$data['captcha'] === $captcha
){
$user = $this->_getUser(0);
$activeCharacter = $this->getCharacter(0);
$user = $activeCharacter->getUser();
$validUser = $this->_verifyUser( $user->name, $data['password']);
if(

View File

@@ -7,15 +7,26 @@
*/
namespace Controller;
use Controller\Ccp as Ccp;
class AppController extends Controller {
/**
* show main login (index) page
* @param $f3
* event handler after routing
* @param \Base $f3
*/
public function init($f3) {
public function afterroute(\Base $f3){
parent::afterroute($f3);
// clear all SSO related temp data
$f3->clear(Ccp\Sso::SESSION_KEY_SSO);
}
/**
* show main login (index) page
* @param \Base $f3
*/
public function init(\Base $f3) {
// page title
$f3->set('pageTitle', 'Login');

View File

@@ -0,0 +1,604 @@
<?php
/**
* Created by PhpStorm.
* User: Exodus
* Date: 23.01.2016
* Time: 17:18
*
* Handles access to EVE-Online "CREST API" and "SSO" auth functions
* - Add your API credentials in "environment.ini"
* - Check "PATHFINDER.API" in "pathfinder.ini" for correct API URLs
* Hint: \Web::instance()->request automatically caches responses by their response "Cache-Control" header!
*/
namespace Controller\Ccp;
use Controller;
use Controller\Api as Api;
use Data\Mapper as Mapper;
use Model;
use Lib;
class Sso extends Api\User{
/**
* @var int timeout (seconds) for API calls
*/
const CREST_TIMEOUT = 3;
/**
* @var int expire time (seconds) for an valid "accessToken"
*/
const ACCESS_KEY_EXPIRE_TIME = 20 * 60;
// SSO specific session keys
const SESSION_KEY_SSO = 'SESSION.SSO';
const SESSION_KEY_SSO_ERROR = 'SESSION.SSO.ERROR';
const SESSION_KEY_SSO_STATE = 'SESSION.SSO.STATE';
// error messages
const ERROR_CCP_SSO_URL = 'Invalid "ENVIRONMENT.[ENVIRONMENT].SSO_CCP_URL" url. %s';
const ERROR_CCP_CREST_URL = 'Invalid "ENVIRONMENT.[ENVIRONMENT].CCP_CREST_URL" url. %s';
const ERROR_RESOURCE_DEPRECATED = 'Resource: %s has been marked as deprecated. %s';
const ERROR_ACCESS_TOKEN = 'Unable to get a valid "access_token. %s';
const ERROR_VERIFY_CHARACTER = 'Unable to verify character data. %s';
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';
/**
* CREST "Scopes" are used by pathfinder
* -> Enable scopes: https://developers.eveonline.com
* @var array
*/
private $requestScopes = [
// 'characterFittingsRead',
// 'characterFittingsWrite',
'characterLocationRead',
'characterNavigationWrite'
];
/**
* redirect user to CCP SSO page and request authorization
* @param \Base $f3
*/
public function requestAuthorization($f3){
// used for "state" check between request and callback
$state = bin2hex(mcrypt_create_iv(12, MCRYPT_DEV_URANDOM));
$f3->set(self::SESSION_KEY_SSO_STATE, $state);
$urlParams = [
'response_type' => 'code',
'redirect_uri' => Controller\Controller::getEnvironmentData('URL') . $f3->build('/sso/callbackAuthorization'),
'client_id' => Controller\Controller::getEnvironmentData('SSO_CCP_CLIENT_ID'),
'scope' => implode(' ', $this->requestScopes),
'state' => $state
];
$ssoAuthUrl = self::getAuthorizationEndpoint() . '?' . http_build_query($urlParams, '', '&', PHP_QUERY_RFC3986 );
$f3->status(302);
$f3->reroute($ssoAuthUrl);
}
/**
* callback handler for CCP SSO user Auth
* -> see requestAuthorization()
* @param \Base $f3
*/
public function callbackAuthorization($f3){
$getParams = (array)$f3->get('GET');
if($f3->exists(self::SESSION_KEY_SSO_STATE)){
// check response and validate 'state'
if(
isset($getParams['code']) &&
isset($getParams['state']) &&
!empty($getParams['code']) &&
!empty($getParams['state']) &&
$f3->get(self::SESSION_KEY_SSO_STATE) === $getParams['state']
){
// clear 'state' for new next request
$f3->clear(self::SESSION_KEY_SSO_STATE);
$accessData = $this->getCrestAccessData($getParams['code']);
if(
isset($accessData->accessToken) &&
isset($accessData->refreshToken)
){
// login succeeded -> get basic character data for current login
$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);
if(isset($characterData->character)){
// add "ownerHash" and CREST tokens
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
$characterData->character['crestAccessToken'] = $accessData->accessToken;
$characterData->character['crestRefreshToken'] = $accessData->refreshToken;
// add/update static character data
$characterModel = $this->updateCharacter($characterData);
if( !is_null($characterModel) ){
// check if character is authorized to log in
if($characterModel->isAuthorized()){
// character is authorized to log in
// -> update character log (current location,...)
$characterModel = $characterModel->updateLog();
// check if there is already a user created who owns this char
$user = $characterModel->getUser();
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();
/**
* @var Model\UserCharacterModel $userCharactersModel
*/
$userCharactersModel = Model\BasicModel::getNew('UserCharacterModel');
$userCharactersModel->userId = $user;
$userCharactersModel->characterId = $characterModel;
$userCharactersModel->save();
// get updated character model
$characterModel = $userCharactersModel->getCharacter();
}
// login by character
$loginCheck = $this->loginByCharacter($characterModel);
if($loginCheck){
// route to "map"
$f3->reroute('@map');
}else{
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_LOGIN_FAILED, $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.');
}
}
}
}
}
}
}
// on error -> route back to login form
$f3->reroute('@login');
}
/**
* get a valid "access_token" for oAuth 2.0 verification
* -> if $authCode is set -> request NEW "access_token"
* -> else check for existing (not expired) "access_token"
* -> else try to refresh auth and get fresh "access_token"
* @param bool $authCode
* @return null|\stdClass
*/
public function getCrestAccessData($authCode){
$accessData = null;
if( !empty($authCode) ){
// Authentication Code is set -> request new "accessToken"
$accessData = $this->verifyAuthorizationCode($authCode);
}else{
// Unable to get Token -> trigger error
self::getCrestLogger()->write(sprintf(self::ERROR_ACCESS_TOKEN, $authCode));
}
return $accessData;
}
/**
* verify authorization code, and get an "access_token" data
* @param $authCode
* @return \stdClass
*/
protected function verifyAuthorizationCode($authCode){
$requestParams = [
'grant_type' => 'authorization_code',
'code' => $authCode
];
return $this->requestAccessData($requestParams);
}
/**
* get new "access_token" by an existing "refresh_token"
* -> if "access_token" is expired, this function gets a fresh one
* @param $refreshToken
* @return \stdClass
*/
public function refreshAccessToken($refreshToken){
$requestParams = [
'grant_type' => 'refresh_token',
'refresh_token' => $refreshToken
];
return $this->requestAccessData($requestParams);
}
/**
* request an "access_token" AND "refresh_token" data
* -> this can either be done by sending a valid "authorization code"
* OR by providing a valid "refresh_token"
* @param $requestParams
* @return \stdClass
*/
protected function requestAccessData($requestParams){
$verifyAuthCodeUrl = self::getVerifyAuthorizationCodeEndpoint();
$verifyAuthCodeUrlParts = parse_url($verifyAuthCodeUrl);
$accessData = (object) [];
$accessData->accessToken = null;
$accessData->refreshToken = null;
if($verifyAuthCodeUrlParts){
$contentType = 'application/x-www-form-urlencoded';
$requestOptions = [
'timeout' => self::CREST_TIMEOUT,
'method' => 'POST',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Basic ' . $this->getAuthorizationHeader(),
'Content-Type: ' . $contentType,
'Host: ' . $verifyAuthCodeUrlParts['host']
]
];
// content (parameters to send with)
$requestOptions['content'] = http_build_query($requestParams);
$apiResponse = Lib\Web::instance()->request($verifyAuthCodeUrl, $requestOptions);
if($apiResponse['body']){
$authCodeRequestData = json_decode($apiResponse['body']);
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;
}
}else{
self::getCrestLogger()->write(
sprintf(
self::ERROR_ACCESS_TOKEN,
print_r($requestParams, true)
)
);
}
}else{
self::getCrestLogger()->write(
sprintf(self::ERROR_CCP_SSO_URL, __METHOD__)
);
}
return $accessData;
}
/**
* verify character data by "access_token"
* -> get some basic information (like character id)
* -> if more character information is required, use CREST endpoints request instead
* @param $accessToken
* @return mixed|null
*/
protected function verifyCharacterData($accessToken){
$verifyUserUrl = self::getVerifyUserEndpoint();
$verifyUrlParts = parse_url($verifyUserUrl);
$characterData = null;
if($verifyUrlParts){
$requestOptions = [
'timeout' => self::CREST_TIMEOUT,
'method' => 'GET',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Bearer ' . $accessToken,
'Host: ' . $verifyUrlParts['host']
]
];
$apiResponse = Lib\Web::instance()->request($verifyUserUrl, $requestOptions);
if($apiResponse['body']){
$characterData = json_decode($apiResponse['body']);
}else{
self::getCrestLogger()->write(sprintf(self::ERROR_VERIFY_CHARACTER, __METHOD__));
}
}else{
self::getCrestLogger()->write(sprintf(self::ERROR_CCP_SSO_URL, __METHOD__));
}
return $characterData;
}
/**
* get all available Endpoints
* @param $accessToken
* @return mixed|null
*/
protected function getEndpoints($accessToken){
$crestUrl = self::getCrestEndpoint();
$contentType = 'application/vnd.ccp.eve.Api-v3+json';
$endpoint = $this->getEndpoint($accessToken, $crestUrl, $contentType);
return $endpoint;
}
/**
* get a specific endpoint by its $resourceUrl
* @param $accessToken
* @param $resourceUrl
* @param string $contentType
* @return mixed|null
*/
protected function getEndpoint($accessToken, $resourceUrl, $contentType = ''){
$resourceUrlParts = parse_url($resourceUrl);
$endpoint = null;
if($resourceUrlParts){
$requestOptions = [
'timeout' => self::CREST_TIMEOUT,
'method' => 'GET',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Bearer ' . $accessToken,
'Host: login.eveonline.com',
'Host: ' . $resourceUrlParts['host']
]
];
// if specific contentType is required -> add it to request header
// CREST versioning can be done by calling different "Accept:" Headers
if( !empty($contentType) ){
$requestOptions['header'][] = 'Accept: ' . $contentType;
}
$apiResponse = Lib\Web::instance()->request($resourceUrl, $requestOptions);
if($apiResponse['headers']){
// check headers for error
$this->checkResponseHeaders($apiResponse['headers'], $requestOptions);
if($apiResponse['body']){
$endpoint = json_decode($apiResponse['body'], true);
}else{
self::getCrestLogger()->write(sprintf(self::ERROR_GET_ENDPOINT, __METHOD__));
}
}
}else{
self::getCrestLogger()->write(sprintf(self::ERROR_CCP_CREST_URL, __METHOD__));
}
return $endpoint;
}
/**
* recursively walk down the CREST API tree by a given $path array
* -> return "leaf" endpoint
* @param $accessToken
* @param $endpoint
* @param array $path
* @return null|string
*/
protected function walkEndpoint($accessToken, $endpoint, $path = []){
$targetEndpoint = null;
if( !empty($path) ){
$newNode = array_shift($path);
if(isset($endpoint[$newNode])){
$currentEndpoint = $endpoint[$newNode];
if(isset($currentEndpoint['href'])){
$newEndpoint = $this->getEndpoint($accessToken, $currentEndpoint['href']);
$targetEndpoint = $this->walkEndpoint($accessToken, $newEndpoint, $path);
}else{
// leaf found
$targetEndpoint = $currentEndpoint;
}
}else{
// endpoint not found
self::getCrestLogger()->write(sprintf(self::ERROR_FIND_ENDPOINT, $newNode));
}
}else{
$targetEndpoint = $endpoint;
}
return $targetEndpoint;
}
/**
* get character data
* @param $accessToken
* @return array
*/
protected function getCharacterData($accessToken){
$endpoints = $this->getEndpoints($accessToken);
$characterData = (object) [];
$endpoint = $this->walkEndpoint($accessToken, $endpoints, [
'decode',
'character'
]);
if( !empty($endpoint) ){
$characterData->character = (new Mapper\CrestCharacter($endpoint))->getData();
if(isset($endpoint['corporation'])){
$characterData->corporation = (new Mapper\CrestCorporation($endpoint['corporation']))->getData();
}
}
return $characterData;
}
/**
* get current character location data
* -> solarSystem data where character is currently active
* @param $accessToken
* @return object
*/
public function getCharacterLocationData($accessToken){
$endpoints = $this->getEndpoints($accessToken);
$locationData = (object) [];
$endpoint = $this->walkEndpoint($accessToken, $endpoints, [
'decode',
'character',
'location'
]);
if( !empty($endpoint) ){
if(isset($endpoint['solarSystem'])){
$locationData->system = (new Mapper\CrestSystem($endpoint['solarSystem']))->getData();
}
}
return $locationData;
}
/**
* update character
* @param $characterData
* @return \Model\CharacterModel
* @throws \Exception
*/
protected function updateCharacter($characterData){
$characterModel = null;
$corporationModel = null;
$allianceModel = null;
if( isset($characterData->corporation) ){
/**
* @var Model\CorporationModel $corporationModel
*/
$corporationModel = Model\BasicModel::getNew('CorporationModel');
$corporationModel->getById($characterData->corporation['id'], 0);
$corporationModel->copyfrom($characterData->corporation);
$corporationModel->save();
}
if( isset($characterData->alliance) ){
/**
* @var Model\AllianceModel $allianceModel
*/
$allianceModel = Model\BasicModel::getNew('AllianceModel');
$allianceModel->getById($characterData->alliance['id'], 0);
$allianceModel->copyfrom($characterData->alliance);
$allianceModel->save();
}
if( isset($characterData->character) ){
/**
* @var Model\CharacterModel $characterModel
*/
$characterModel = Model\BasicModel::getNew('CharacterModel');
$characterModel->getById($characterData->character['id'], 0);
$characterModel->copyfrom($characterData->character);
$characterModel->corporationId = $corporationModel;
$characterModel->allianceId = $allianceModel;
$characterModel = $characterModel->save();
}
return $characterModel;
}
/**
* check response "Header" data for errors
* @param $headers
* @param string $requestUrl
* @param string $contentType
*/
protected function checkResponseHeaders($headers, $requestUrl = '', $contentType = ''){
$headers = (array)$headers;
if(preg_grep ('/^X-Deprecated/i', $headers)){
self::getCrestLogger()->write(sprintf(self::ERROR_RESOURCE_DEPRECATED, $requestUrl, $contentType));
}
}
/**
* get "Authorization:" Header data
* -> This header is required for any Auth-required endpoints!
* @return string
*/
protected function getAuthorizationHeader(){
return base64_encode(
Controller\Controller::getEnvironmentData('SSO_CCP_CLIENT_ID') . ':'
. Controller\Controller::getEnvironmentData('SSO_CCP_SECRET_KEY')
);
}
/**
* get CCP CREST url from configuration file
* -> throw error if url is broken/missing
* @return string
*/
static function getCrestEndpoint(){
$url = '';
if( \Audit::instance()->url(self::getEnvironmentData('CCP_CREST_URL')) ){
$url = self::getEnvironmentData('CCP_CREST_URL');
}else{
$error = sprintf(self::ERROR_CCP_CREST_URL, __METHOD__);
self::getCrestLogger()->write($error);
\Base::instance()->error(502, $error);
}
return $url;
}
/**
* get CCP SSO url from configuration file
* -> throw error if url is broken/missing
* @return string
*/
static function getSsoUrlRoot(){
$url = '';
if( \Audit::instance()->url(self::getEnvironmentData('SSO_CCP_URL')) ){
$url = self::getEnvironmentData('SSO_CCP_URL');
}else{
$error = sprintf(self::ERROR_CCP_SSO_URL, __METHOD__);
self::getCrestLogger()->write($error);
\Base::instance()->error(502, $error);
}
return $url;
}
static function getAuthorizationEndpoint(){
return self::getSsoUrlRoot() . '/oauth/authorize';
}
static function getVerifyAuthorizationCodeEndpoint(){
return self::getSsoUrlRoot() . '/oauth/token';
}
static function getVerifyUserEndpoint(){
return self::getSsoUrlRoot() . '/oauth/verify';
}
/**
* get logger for CREST logging
* @return \Log
*/
static function getCrestLogger(){
return parent::getLogger('crest');
}
}

View File

@@ -1,184 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: exodus4d
* Date: 28.03.15
* Time: 17:01
*/
namespace Controller;
use Model;
/**
* CCP API controller
* Class CcpApiController
* @package Controller
*/
class CcpApiController extends Controller{
/**
* get HTTP request options for API (curl) request
* @return array
*/
protected function getRequestOptions(){
$requestOptions = [
'timeout' => 8,
'method' => 'POST',
'user_agent' => $this->getUserAgent(),
'follow_location' => false // otherwise CURLOPT_FOLLOWLOCATION will fail
];
return $requestOptions;
}
/**
* request character information from CCP API
* @param $keyID
* @param $vCode
* @return bool|\SimpleXMLElement
*/
public function requestCharacters($keyID, $vCode){
$apiPath = $this->getF3()->get('PATHFINDER.API.CCP_XML') . '/account/APIKeyInfo.xml.aspx';
$xml = false;
// build request URL
$options = $this->getRequestOptions();
$options['content'] = http_build_query( [
'keyID' => $keyID,
'vCode' => $vCode
]);
$apiResponse = \Web::instance()->request($apiPath, $options );
if($apiResponse['body']){
$xml = simplexml_load_string($apiResponse['body']);
}
return $xml;
}
/**
* update all character information for a given apiModel
* @param $userApiModel
* @return int
* @throws \Exception
*/
public function updateCharacters($userApiModel){
$xml = $this->requestCharacters($userApiModel->keyId, $userApiModel->vCode);
$characterCount = 0;
// important -> user API model must be up2date
// if not -> matched userCharacter cant be found
$userApiModel->getById($userApiModel->id, 0);
if($xml){
// request successful
$rowApiData = $xml->result->key->rowset;
if(
is_object($rowApiData) &&
$rowApiData->children()
){
$characterModel = Model\BasicModel::getNew('CharacterModel');
$corporationModel = Model\BasicModel::getNew('CorporationModel');
$allianceModel = Model\BasicModel::getNew('AllianceModel');
foreach($rowApiData->children() as $characterApiData){
// map attributes to array
$attributeData = current( $characterApiData->attributes() );
$newCharacter = true;
$characterId = (int)$attributeData['characterID'];
$characterModel->getById($characterId, 0);
$corporationModelTemp = null;
$allianceModelTemp = null;
// check if corporation already exists
if($attributeData['corporationID'] > 0){
$corporationModel->getById($attributeData['corporationID'], 0);
if( $corporationModel->dry() ){
$corporationModel->id = $attributeData['corporationID'];
$corporationModel->name = $attributeData['corporationName'];
$corporationModel->save();
}
$corporationModelTemp = $corporationModel;
}
// check if alliance already exists
if($attributeData['allianceID'] > 0){
$allianceModel->getById($attributeData['allianceID'], 0);
if( $allianceModel->dry() ){
$allianceModel->id = $attributeData['allianceID'];
$allianceModel->name = $attributeData['allianceName'];
$allianceModel->save();
}
$allianceModelTemp = $allianceModel;
}
if($userApiModel->userCharacters){
$userApiModel->userCharacters->rewind();
while($userApiModel->userCharacters->valid()){
$tempCharacterModel = $userApiModel->userCharacters->current()->getCharacter();
// character already exists -> update
if($tempCharacterModel->id == $characterId){
$characterModel = $tempCharacterModel;
// unset userCharacter -> all leftover models are no longer part of this API
// --> delete leftover models at the end
$userApiModel->userCharacters->offsetUnset($userApiModel->userCharacters->key());
$newCharacter = false;
break;
}else{
$userApiModel->userCharacters->next();
}
}
$userApiModel->userCharacters->rewind();
}
$characterModel->id = $characterId;
$characterModel->name = $attributeData['characterName'];
$characterModel->corporationId = $corporationModelTemp;
$characterModel->allianceId = $allianceModelTemp;
$characterModel->factionId = $attributeData['factionID'];
$characterModel->factionName = $attributeData['factionName'];
$characterModel->save();
if($newCharacter){
// new character for this API
$userCharactersModel = Model\BasicModel::getNew('UserCharacterModel', 0);
$userCharactersModel->userId = $userApiModel->userId;
$userCharactersModel->apiId = $userApiModel;
$userCharactersModel->characterId = $characterModel;
$userCharactersModel->save();
}
$corporationModel->reset();
$allianceModel->reset();
$characterModel->reset();
$characterCount++;
}
}
// delete leftover userCharacters from this API
if(count($userApiModel->userCharacters) > 0){
while($userApiModel->userCharacters->valid()){
$userApiModel->userCharacters->current()->erase();
$userApiModel->userCharacters->next();
}
}
}
return $characterCount;
}
}

View File

@@ -1,503 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: Exodus
* Date: 23.01.2016
* Time: 17:18
*
* Handles access to EVE-Online "CREST API" and "SSO" auth functions
* - Add your API credentials in "environment.ini"
* - Check "PATHFINDER.API" in "pathfinder.ini" for correct API URLs
* Hint: \Web::instance()->request automatically caches responses by their response "Cache-Control" header!
*/
namespace Controller;
use Data\Mapper as Mapper;
use Model;
class CcpSsoController extends Controller {
const SESSION_KEY_ACCESS_TOKEN = 'SESSION.sso.access_token';
const SESSION_KEY_REFRESH_TOKEN = 'SESSION.sso.refresh_token';
const ERROR_CCP_SSO_URL = 'Invalid "PATHFINDER.API.CCP_SSO" url. %s';
const ERROR_CCP_CREST_URL = 'Invalid "PATHFINDER.API.CCP_CREST" url. %s';
const ERROR_RESOURCE_DEPRECATED = 'Resource: %s has been marked deprecated. %s';
const ERROR_ACCESS_TOKEN = 'Unable to get a valid "access_token. %s';
const ERROR_VERIFY_CHARACTER = 'Unable to verify character data. %s';
const ERROR_GET_ENDPOINTS = 'Unable to get endpoints data. $s';
const ERROR_GET_ENDPOINT = 'Unable to get endpoint data. $s';
const ERROR_FIND_ENDPOINT = 'Unable to find endpoint: %s';
/**
* "Scopes" that are used by pathfinder
* -> Enable scopes: https://developers.eveonline.com
* @var array
*/
private $requestScopes = [
'characterLocationRead',
'characterNavigationWrite'
];
/**
* timeout for API calls
* @var int
*/
private $apiTimeout = 3;
/**
* redirect user to CCP SSO page and request authorization
* @param $f3
*/
public function requestAuthorization($f3){
// used for state check between request and callback
$state = bin2hex(mcrypt_create_iv(12, MCRYPT_DEV_URANDOM));
$f3->set('SESSION.sso.state', $state);
$urlParams = [
'response_type' => 'code',
'redirect_uri' => Controller::getEnvironmentData('URL') . $f3->build('/sso/callbackAuthorization'),
'client_id' => Controller::getEnvironmentData('SSO_CCP_CLIENT_ID'),
'scope' => implode(' ', $this->requestScopes),
'state' => $state
];
$ssoAuthUrl = self::getAuthorizationEndpoint() . '?' . http_build_query($urlParams, '', '&', PHP_QUERY_RFC3986 );
$f3->status(302);
$f3->reroute($ssoAuthUrl);
}
/**
* callback handler for CCP SSO user Auth
* -> see requestAuthorization()
* @param $f3
*/
public function callbackAuthorization($f3){
$getParams = (array)$f3->get('GET');
if($f3->exists('SESSION.sso.state')){
// check response and validate 'state'
if(
isset($getParams['code']) &&
isset($getParams['state']) &&
!empty($getParams['code']) &&
!empty($getParams['state']) &&
$f3->get('SESSION.sso.state') === $getParams['state']
){
// clear 'state' for new next request
$f3->clear('SESSION.sso.state');
$accessToken = $this->getAccessToken($getParams['code']);
if($accessToken){
$data = $this->verifyCharacterData($accessToken);
$characterData = $this->getCharacterData($accessToken);
$characterModel = $this->updateCharacter($characterData);
if( !is_null($characterModel) ){
// everything OK -> login succeeded
var_dump( $characterModel->cast() );
die();
}
}
}
}
// on error -> route back to login form
$this->getF3()->reroute('@login');
}
/**
* get a valid "access_token" for oAuth 2.0 verification
* -> if $authCode is set -> request NEW "access_token"
* -> else check for existing (not expired) "access_token"
* -> else try to refresh auth and get fresh "access_token"
* @param bool $authCode
* @return bool|mixed
*/
private function getAccessToken($authCode = false){
$accessToken = false;
if( !empty($authCode) ){
// Authentication Code is set -> request new Access Token -------------------------------------------------
// clear "old" token (if exist and still valid)
$this->getF3()->clear(self::SESSION_KEY_ACCESS_TOKEN);
$accessToken = $this->verifyAuthorizationCode($authCode);
}elseif($this->getF3()->exists(self::SESSION_KEY_ACCESS_TOKEN)){
// Access Token exists and not expired --------------------------------------------------------------------
$accessToken = $this->getF3()->get(self::SESSION_KEY_ACCESS_TOKEN);
}elseif($this->getF3()->exists(self::SESSION_KEY_REFRESH_TOKEN)){
// Refresh Token exists -> refresh Access Token -----------------------------------------------------------
$accessToken = $this->refreshAccessToken($this->getF3()->get(self::SESSION_KEY_REFRESH_TOKEN));
}else{
// Unable to get Token -> trigger error -------------------------------------------------------------------
$this->getLogger('error')->write(sprintf(self::ERROR_ACCESS_TOKEN, $authCode));
}
return $accessToken;
}
/**
* verify authorization code, and get an "access_token" data
* @param $authCode
* @return bool|mixed
*/
private function verifyAuthorizationCode($authCode){
$requestParams = [
'grant_type' => 'authorization_code',
'code' => $authCode
];
return $this->requestAccessToken($requestParams);
}
/**
* get new "access_token" by an existing "refresh_token"
* -> if "access_token" is expired, this function gets a fresh one
* @param $refreshToken
* @return bool|mixed
*/
private function refreshAccessToken($refreshToken){
$requestParams = [
'grant_type' => 'refresh_token',
'refresh_token' => $refreshToken
];
return $this->requestAccessToken($requestParams);
}
/**
* request an "access_token" AND "refresh_token" data
* -> this can either be done by sending a valid "authorization code"
* OR by providing a valid "refresh_token"
* @param $requestParams
* @return bool|mixed
*/
private function requestAccessToken($requestParams){
$verifyAuthCodeUrl = self::getVerifyAuthorizationCodeEndpoint();
$verifyAuthCodeUrlParts = parse_url($verifyAuthCodeUrl);
$accessToken = false;
if($verifyAuthCodeUrlParts){
$contentType = 'application/x-www-form-urlencoded';
$requestOptions = [
'timeout' => $this->apiTimeout,
'method' => 'POST',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Basic ' . $this->getAuthorizationHeader(),
'Content-Type: ' . $contentType,
'Host: ' . $verifyAuthCodeUrlParts['host']
]
];
// content (parameters to send with)
$requestOptions['content'] = http_build_query($requestParams);
$apiResponse = \Web::instance()->request($verifyAuthCodeUrl, $requestOptions);
if($apiResponse['body']){
$authCodeRequestData = json_decode($apiResponse['body']);
if(property_exists($authCodeRequestData, 'refresh_token')){
// this token is used to refresh/get a new access_token when expires
$this->getF3()->set(self::SESSION_KEY_REFRESH_TOKEN, $authCodeRequestData->refresh_token);
}
if(property_exists($authCodeRequestData, 'access_token')){
// this token is required for endpoints that require Auth
$accessToken = $this->getF3()->set(self::SESSION_KEY_ACCESS_TOKEN, $authCodeRequestData->access_token);
}
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_ACCESS_TOKEN, print_r($requestParams, true)));
}
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_CCP_SSO_URL, __METHOD__));
}
return $accessToken;
}
/**
* verify character data by "access_token"
* -> get some basic information (like character id)
* -> if more character information is required, use CREST endpoints request instead
* @param $accessToken
* @return bool|mixed
*/
private function verifyCharacterData($accessToken){
$verifyUserUrl = self::getVerifyUserEndpoint();
$verifyUrlParts = parse_url($verifyUserUrl);
$characterData = false;
if($verifyUrlParts){
$requestOptions = [
'timeout' => $this->apiTimeout,
'method' => 'GET',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Bearer ' . $accessToken,
'Host: ' . $verifyUrlParts['host']
]
];
$apiResponse = \Web::instance()->request($verifyUserUrl, $requestOptions);
if($apiResponse['body']){
$characterData = json_decode($apiResponse['body']);
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_VERIFY_CHARACTER, __METHOD__));
}
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_CCP_SSO_URL, __METHOD__));
}
return $characterData;
}
/**
* get all available Endpoints
* @param $accessToken
* @return bool|mixed
*/
private function getEndpoints($accessToken){
$crestUrl = self::getCrestEndpoint();
$endpointsData = false;
$crestUrlParts = parse_url($crestUrl);
if($crestUrlParts){
// represents API version
$contentType = 'application/vnd.ccp.eve.Api-v3+json';
$requestOptions = [
'timeout' => $this->apiTimeout,
'method' => 'GET',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Bearer ' . $accessToken,
'Accept: ' . $contentType,
'Host: ' . $crestUrlParts['host']
]
];
$apiResponse = \Web::instance()->request($crestUrl, $requestOptions);
if($apiResponse['headers']){
// check headers for error
$this->checkResponseHeaders($apiResponse['headers'], $crestUrl, $contentType);
if($apiResponse['body']){
$endpointsData = json_decode($apiResponse['body'], true);
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_GET_ENDPOINTS, __METHOD__));
}
}
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_CCP_CREST_URL, __METHOD__));
}
return $endpointsData;
}
private function walkEndpoint($accessToken, $endpoint, $path = []){
$targetEndpoint = null;
if( !empty($path) ){
$newNode = array_shift($path);
if(isset($endpoint[$newNode])){
$currentEndpoint = $endpoint[$newNode];
if(isset($currentEndpoint['href'])){
$newEndpoint = $this->getEndpoint($accessToken, $currentEndpoint['href']);
$targetEndpoint = $this->walkEndpoint($accessToken, $newEndpoint, $path);
}else{
// TODO leaf
$targetEndpoint = ' target:) ';
}
}else{
// endpoint not found
$this->getLogger('error')->write(sprintf(self::ERROR_FIND_ENDPOINT, $newNode));
}
}else{
$targetEndpoint = $endpoint;
}
return $targetEndpoint;
}
/**
* get a specific endpoint by its $resourceUrl
* @param $accessToken
* @param $resourceUrl
* @return mixed|null
*/
private function getEndpoint($accessToken, $resourceUrl){
$resourceUrlParts = parse_url($resourceUrl);
$endpoint = null;
if($resourceUrlParts){
$requestOptions = [
'timeout' => $this->apiTimeout,
'method' => 'GET',
'user_agent' => $this->getUserAgent(),
'header' => [
'Authorization: Bearer ' . $accessToken,
'Host: login.eveonline.com',
'Host: ' . $resourceUrlParts['host']
]
];
$apiResponse = \Web::instance()->request($resourceUrl, $requestOptions);
if($apiResponse['headers']){
// check headers for error
$this->checkResponseHeaders($apiResponse['headers'], $requestOptions);
if($apiResponse['body']){
$endpoint = json_decode($apiResponse['body'], true);
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_GET_ENDPOINT, __METHOD__));
}
}
}else{
$this->getLogger('error')->write(sprintf(self::ERROR_CCP_CREST_URL, __METHOD__));
}
return $endpoint;
}
/**
* get character data
* @param $accessToken
* @return array
*/
private function getCharacterData($accessToken){
$endpoints = $this->getEndpoints($accessToken);
$characterData = [];
$endpoint = $this->walkEndpoint($accessToken, $endpoints, [
'decode',
'character'
]);
if( !empty($endpoint) ){
$characterData['character'] = (new Mapper\CrestCharacter($endpoint))->getData();
if(isset($endpoint['corporation'])){
$characterData['corporation'] = (new Mapper\CrestCorporation($endpoint['corporation']))->getData();
}
}
return $characterData;
}
/*
private function getCharacterLocation($accessToken){
$endpoints = $this->getEndpoints($accessToken);
$endpoint = $this->walkEndpoint($accessToken, $endpoints, [
'decode',
'character',
'location'
]);
var_dump($endpoint);
die(' END getCharacterLocation() ');
$characterData = [];
return $characterData;
} */
/**
* update character
* @param $characterData
* @return \Model\CharacterModel
* @throws \Exception
*/
private function updateCharacter($characterData){
$characterModel = null;
$corporationModel = null;
$allianceModel = null;
if( !empty($characterData['corporation']) ){
$corporationModel = Model\BasicModel::getNew('CorporationModel');
$corporationModel->getById($characterData['corporation']['id'], 0);
$corporationModel->copyfrom($characterData['corporation']);
$corporationModel->save();
}
if( !empty($characterData['alliance']) ){
$allianceModel = Model\BasicModel::getNew('AllianceModel');
$allianceModel->getById($characterData['alliance']['id'], 0);
$allianceModel->copyfrom($characterData['alliance']);
$allianceModel->save();
}
if( !empty($characterData['character']) ){
$characterModel = Model\BasicModel::getNew('CharacterModel');
$characterModel->getById($characterData['character']['id'], 0);
$characterModel->copyfrom($characterData['character']);
$characterModel->corporationId = $corporationModel;
$characterModel->allianceId = $allianceModel;
$characterModel->save();
}
return $characterModel;
}
/**
* check response "Header" data for errors
* @param $headers
* @param string $requestUrl
* @param string $contentType
*/
private function checkResponseHeaders($headers, $requestUrl = '', $contentType = ''){
$headers = (array)$headers;
if(preg_grep ('/^X-Deprecated/i', $headers)){
$this->getLogger('error')->write(sprintf(self::ERROR_RESOURCE_DEPRECATED, $requestUrl, $contentType));
}
}
/**
* get "Authorization:" Header data
* -> This header is required for any Auth-required endpoints!
* @return string
*/
private function getAuthorizationHeader(){
return base64_encode(
Controller::getEnvironmentData('SSO_CCP_CLIENT_ID') . ':'
. Controller::getEnvironmentData('SSO_CCP_SECRET_KEY')
);
}
static function getAuthorizationEndpoint(){
return \Base::instance()->get('PATHFINDER.API.CCP_SSO') . '/oauth/authorize';
}
static function getVerifyAuthorizationCodeEndpoint(){
return \Base::instance()->get('PATHFINDER.API.CCP_SSO') . '/oauth/token';
}
static function getVerifyUserEndpoint(){
return \Base::instance()->get('PATHFINDER.API.CCP_SSO') . '/oauth/verify';
}
static function getCrestEndpoint(){
return \Base::instance()->get('PATHFINDER.API.CCP_CREST');
}
}

View File

@@ -7,50 +7,62 @@
*/
namespace Controller;
use Controller\Api as Api;
use Model;
use DB;
class Controller {
/**
* @var \Base
*/
protected $f3;
private $template;
/**
* @param mixed $template
* @var string template for render
*/
public function setTemplate($template){
protected $template;
/**
* @param string $template
*/
protected function setTemplate($template){
$this->template = $template;
}
/**
* @return mixed
* @return string
*/
public function getTemplate(){
protected function getTemplate(){
return $this->template;
}
/**
* set global f3 instance
* @param null $f3
* @return null|static
* set $f3 base object
* @param \Base $f3
*/
protected function getF3($f3 = null){
if(is_object($f3)){
$this->f3 = $f3;
}else{
$this->f3 = \Base::instance();
}
protected function setF3(\Base $f3){
$this->f3 = $f3;
}
/**
* get $f3 base object
* @return \Base
*/
protected function getF3(){
if( !($this->f3 instanceof \Base) ){
$this->setF3( \Base::instance() );
}
return $this->f3;
}
/**
* event handler for all "views"
* some global template variables are set in here
* @param $f3
* @param \Base $f3
*/
function beforeroute($f3) {
$this->getF3($f3);
function beforeroute(\Base $f3) {
$this->setF3($f3);
// initiate DB connection
DB\Database::instance('PF');
@@ -73,8 +85,9 @@ class Controller {
/**
* event handler after routing
* -> render view
* @param \Base $f3
*/
public function afterroute($f3){
public function afterroute(\Base $f3){
if($this->getTemplate()){
// Ajax calls don´t need a page render..
// this happens on client side
@@ -85,7 +98,7 @@ class Controller {
/**
* set change the DB connection
* @param string $database
* @return mixed|void
* @return DB\SQL
*/
protected function getDB($database = 'PF'){
return DB\Database::instance()->getDB($database);
@@ -96,49 +109,47 @@ class Controller {
*/
protected function initSession(){
// init DB Session (not file based)
if( $this->getDB('PF') instanceof \DB\SQL){
new \DB\SQL\Session($this->getDB('PF'));
if( $this->getDB('PF') instanceof DB\SQL){
new DB\SQL\Session($this->getDB('PF'));
}
}
/**
* get current user model
* get current character model
* @param int $ttl
* @return bool|null
* @return Model\CharacterModel|null
* @throws \Exception
*/
protected function _getUser($ttl = 5){
$user = false;
public function getCharacter($ttl = 5){
$character = null;
if( $this->f3->exists('SESSION.user.id') ){
$userId = (int)$this->f3->get('SESSION.user.id');
if( $this->getF3()->exists(Api\User::SESSION_KEY_CHARACTER_ID) ){
$characterId = (int)$this->getF3()->get(Api\User::SESSION_KEY_CHARACTER_ID);
if($characterId){
/**
* @var $characterModel \Model\CharacterModel
*/
$characterModel = Model\BasicModel::getNew('CharacterModel');
$characterModel->getById($characterId, $ttl);
if($userId > 0){
$userModel = Model\BasicModel::getNew('UserModel', $ttl);
$userModel->getById($userId, $ttl);
if( !$userModel->dry() ){
$user = $userModel;
if( !$characterModel->dry() ){
$character = &$characterModel;
}
}
}
return $user;
return $character;
}
/**
* log the current user out
* @param $f3
* log out current user
* @param \Base $f3
*/
public function logOut($f3){
public function logOut(\Base $f3){
// destroy session
$f3->clear('SESSION');
if( !$f3->get('AJAX') ){
// redirect to landing page
$f3->reroute('@login');
}else{
if( $f3->get('AJAX') ){
$params = $f3->get('POST');
$return = (object) [];
if(
@@ -148,33 +159,36 @@ class Controller {
$return->reroute = rtrim(self::getEnvironmentData('URL'), '/') . $f3->alias('login');
}else{
// no reroute -> errors can be shown
$return->error[] = $this->getUserLoggedOffError();
$return->error[] = $this->getLogoutError();
}
echo json_encode($return);
die();
}else{
// redirect to landing page
$f3->reroute('@login');
}
}
/**
* verifies weather a given username and password is valid
* @param $userName
* @param $password
* @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;
}
@@ -185,18 +199,16 @@ class Controller {
/**
* check weather the page is IGB trusted or not
* @return mixed
* @return boolean
*/
static function isIGBTrusted(){
$igbHeaderData = self::getIGBHeaderData();
return $igbHeaderData->trusted;
}
/**
* get all eve IGB specific header data
* @return object
* @return \stdClass
*/
static function getIGBHeaderData(){
$data = (object) [];
@@ -229,7 +241,6 @@ class Controller {
/**
* Helper function to return all headers because
* getallheaders() is not available under nginx
*
* @return array (string $key -> string $value)
*/
static function getRequestHeaders(){
@@ -261,7 +272,7 @@ class Controller {
/**
* get some server information
* @param int $ttl cache time (default: 1h)
* @return object
* @return \stdClass
*/
static function getServerData($ttl = 3600){
$f3 = \Base::instance();
@@ -308,25 +319,21 @@ class Controller {
*/
static function isIGB(){
$isIGB = false;
$igbHeaderData = self::getIGBHeaderData();
if(count($igbHeaderData->values) > 0){
$isIGB = true;
}
return $isIGB;
}
/**
* get error object is a user is not found/logged of
* @return object
* @return \stdClass
*/
protected function getUserLoggedOffError(){
protected function getLogoutError(){
$userError = (object) [];
$userError->type = 'error';
$userError->message = 'User not found';
return $userError;
}
@@ -341,8 +348,8 @@ class Controller {
/**
* get a log controller e.g. "debug"
* @param $loggerType
* @return mixed
* @param string $loggerType
* @return \Log
*/
static function getLogger($loggerType){
return LogController::getLogger($loggerType);
@@ -351,7 +358,7 @@ class Controller {
/**
* removes illegal characters from a Hive-key that are not allowed
* @param $key
* @return mixed
* @return string
*/
static function formatHiveKey($key){
$illegalCharacters = ['-', ' '];
@@ -360,8 +367,8 @@ class Controller {
/**
* get environment specific configuration data
* @param $key
* @return mixed|null
* @param string $key
* @return string|null
*/
static function getEnvironmentData($key){
$f3 = \Base::instance();
@@ -378,7 +385,7 @@ class Controller {
/**
* get current server environment status
* -> "DEVELOP" or "PRODUCTION"
* @return mixed
* @return string
*/
static function getEnvironment(){
$f3 = \Base::instance();
@@ -396,7 +403,7 @@ class Controller {
/**
* get required MySQL variable value
* @param $key
* @return mixed|null
* @return string|null
*/
static function getRequiredMySqlVariables($key){
$f3 = \Base::instance();
@@ -413,7 +420,7 @@ class Controller {
* get a program URL by alias
* -> if no $alias given -> get "default" route (index.php)
* @param null $alias
* @return bool
* @return bool|string
*/
protected function getRouteUrl($alias = null){
$url = false;
@@ -452,9 +459,9 @@ class Controller {
* onError() callback function
* -> on AJAX request -> return JSON with error information
* -> on HTTP request -> render error page
* @param $f3
* @param \Base $f3
*/
public function showError($f3){
public function showError(\Base $f3){
// set HTTP status
$errorCode = $f3->get('ERROR.code');
if(!empty($errorCode)){
@@ -510,8 +517,10 @@ class Controller {
/**
* Callback for framework "unload"
* check -> config.ini
* @param \Base $f3
* @return bool
*/
public function unload($f3){
public function unload(\Base $f3){
return true;
}

View File

@@ -8,8 +8,11 @@
namespace Controller;
class MapController extends \Controller\AccessController {
class MapController extends AccessController {
/**
* @param \Base $f3
*/
public function init($f3) {
// page title

View File

@@ -36,6 +36,7 @@ class Setup extends Controller {
'Model\ConnectionScopeModel',
'Model\UserMapModel',
'Model\CharacterMapModel',
'Model\AllianceMapModel',
'Model\CorporationMapModel',
@@ -76,9 +77,9 @@ class Setup extends Controller {
/**
* event handler for all "views"
* some global template variables are set in here
* @param $f3
* @param \Base $f3
*/
function beforeroute($f3) {
function beforeroute(\Base $f3) {
// page title
$f3->set('pageTitle', 'Setup');
@@ -92,7 +93,7 @@ class Setup extends Controller {
$f3->set('pathJs', 'public/js/' . $f3->get('PATHFINDER.VERSION') );
}
public function afterroute($f3) {
public function afterroute(\Base $f3) {
// js view (file)
$f3->set('jsView', 'setup');
@@ -103,7 +104,7 @@ class Setup extends Controller {
/**
* main setup route handler
* works as dispatcher for setup functions
* @param $f3
* @param \Base $f3
*/
public function init($f3){
$params = $f3->get('GET');
@@ -141,7 +142,7 @@ class Setup extends Controller {
/**
* get server information
* @param $f3
* @param \Base $f3
* @return array
*/
protected function getServerInformation($f3){
@@ -178,7 +179,7 @@ class Setup extends Controller {
/**
* check all required backend requirements
* (Fat Free Framework)
* @param $f3
* @param \Base $f3
* @return array
*/
protected function checkRequirements($f3){
@@ -288,7 +289,7 @@ class Setup extends Controller {
/**
* get database connection information
* @param $f3
* @param \Base $f3
* @param bool|false $exec
* @return array
*/
@@ -413,6 +414,7 @@ class Setup extends Controller {
$changedType = false;
$changedUnique = false;
$changedIndex = false;
$addConstraints = [];
// set (new) column information -------------------------------------------------------
$requiredTables[$requiredTableName]['fieldConf'][$columnName]['exists'] = true;
@@ -427,17 +429,22 @@ class Setup extends Controller {
$constraint = $col->newConstraint($constraintData);
$foreignKeyExists = $col->constraintExists($constraint);
// constraint information -> show in template
$requiredTables[$requiredTableName]['foreignKeys'][] = [
'exists' => $foreignKeyExists,
'keyName' => $constraint->getConstraintName()
];
$col->addConstraint($constraint);
if(!$foreignKeyExists){
if($foreignKeyExists){
// drop constraint and re-add again at the and, in case something has changed
$col->dropConstraint($constraint);
}else{
$tableStatusCheckCount++;
$foreignKeyStatusCheck = false;
}
$addConstraints[] = $constraint;
}
}
@@ -452,11 +459,21 @@ class Setup extends Controller {
$tableStatusCheckCount++;
}
// check if column unique changed -----------------------------------------------------
// check if column index changed ------------------------------------------------------
$indexUpdate = false;
$indexKey = (bool)$hasIndex;
$indexUnique = (bool)$hasUnique;
if($currentColIndex != $fieldConf['index']){
$changedIndex = true;
$columnStatusCheck = false;
$tableStatusCheckCount++;
$indexUpdate = true;
$indexKey = (bool) $fieldConf['index'];
}
// check if column unique changed -----------------------------------------------------
if($currentColIndexData['unique'] != $fieldConf['unique']){
$changedUnique = true;
$columnStatusCheck = false;
@@ -466,15 +483,6 @@ class Setup extends Controller {
$indexUnique =(bool)$fieldConf['unique'];
}
// check if column index changed ------------------------------------------------------
if($currentColIndex != $fieldConf['index']){
$changedIndex = true;
$columnStatusCheck = false;
$tableStatusCheckCount++;
$indexUpdate = true;
$indexKey = (bool) $fieldConf['index'];
}
// build table with changed columns ---------------------------------------------------
if(!$columnStatusCheck || !$foreignKeyStatusCheck){
@@ -495,6 +503,12 @@ class Setup extends Controller {
$tableModifier->updateColumn($columnName, $col);
}
// (re-)add constraints !after! index update is done
// otherwise index update will fail if there are existing constraints
foreach($addConstraints as $constraint){
$col->addConstraint($constraint);
}
$buildStatus = $tableModifier->build($exec);
if(
@@ -559,7 +573,7 @@ class Setup extends Controller {
}
/** check MySQL params
* @param $f3
* @param \Base $f3
* @param $db
* @return array
*/

View File

@@ -0,0 +1,18 @@
<?php
/**
* Created by PhpStorm.
* User: Exodus
* Date: 07.02.2016
* Time: 14:34
*/
namespace Data\Mapper;
class CrestSystem extends AbstractIterator {
protected static $map = [
'id' => 'id',
'name' => 'name'
];
}

View File

@@ -80,7 +80,7 @@ class TableModifier extends SQL\TableModifier {
public function dropConstraint($constraint){
if($constraint->isValid()){
$this->queries[] = "ALTER TABLE " . $this->db->quotekey($this->name) . "
DROP FOREIGN KEY " . $this->db->quotekey($constraint->getConstraintName());
DROP FOREIGN KEY " . $this->db->quotekey($constraint->getConstraintName()) . ";";
}else{
trigger_error(sprintf(self::TEXT_ConstraintNotValid, 'table: ' . $this->name . ' constraintName: ' . $constraint->getConstraintName()));
}
@@ -93,18 +93,13 @@ class TableModifier extends SQL\TableModifier {
public function addConstraint($constraint){
if($constraint->isValid()){
if($this->constraintExists($constraint)){
// drop constraint and re-add in case something has changed
$this->dropConstraint($constraint);
}
$this->queries[] = "
ALTER TABLE " . $this->db->quotekey($this->name) . "
ADD CONSTRAINT " . $this->db->quotekey($constraint->getConstraintName()) . "
FOREIGN KEY (" . implode(', ', $constraint->getKeys()) . ")
REFERENCES " . $this->db->quotekey($constraint->getReferencedTable()) . " (" . implode(', ', $constraint->getReferencedCols()) . ")
ON DELETE " . $constraint->getOnDelete() . "
ON UPDATE " . $constraint->getOnUpdate();
ON UPDATE " . $constraint->getOnUpdate() . ";";
}else{
trigger_error(sprintf(self::TEXT_ConstraintNotValid, 'table: ' . $this->name . ' constraintName: ' . $constraint->getConstraintName()));
}
@@ -120,7 +115,15 @@ class Column extends SQL\Column {
const TEXT_TableNameMissing = 'Table name missing for FOREIGN KEY in `%s`';
/**
* ass constraint to this column
* drop constraint from this column
* @param Constraint $constraint
*/
public function dropConstraint(Constraint $constraint){
$this->table->dropConstraint($constraint);
}
/**
* add constraint to this column
* @param Constraint $constraint
*/
public function addConstraint(Constraint $constraint){

112
app/main/lib/web.php Normal file
View File

@@ -0,0 +1,112 @@
<?php
/**
* Created by PhpStorm.
* User: Exodus
* Date: 12.03.2016
* Time: 12:28
*/
namespace Lib;
class Web extends \Web {
/**
* end of line
* @var string
*/
private $eol = "\r\n";
/**
* get status code from Header data array
* @param array $headers
* @return int
*/
protected function getStatuscodeFromHeaders($headers = []){
$statusCode = 0;
if(
preg_match(
'/HTTP\/1\.\d (\d{3}?)/',
implode($this->eol, $headers),
$matches
)
){
$statusCode = (int)$matches[1];
}
return $statusCode;
}
/**
* get cache time in seconds from Header data array
* @param array $headers
* @return int
*/
protected function getCacheTimeFromHeaders($headers = []){
$cacheTime = 0;
if(
preg_match(
'/Cache-Control:(.*?)max-age=([0-9]+)/',
implode($this->eol, $headers),
$matches
)
){
$cacheTime = (int)$matches[2];
}elseif(
preg_match(
'/Access-Control-Max-Age: ([0-9]+)/',
implode($this->eol, $headers),
$matches
)
){
$cacheTime = (int)$matches[1];
}
return $cacheTime;
}
/**
* get a unique cache kay for a request
* @param $url
* @param null $options
* @return string
*/
protected function getCacheKey($url, $options = null){
$f3 = \Base::instance();
$headers = isset($options['header']) ? implode($this->eol, (array) $options['header']) : '';
return $f3->hash(
$options['method'] . ' '
. $url . ' '
. $headers
).'.url';
}
/**
* perform curl() request
* -> caches response by returned HTTP Cache header data
* @param string $url
* @param array|null $options
* @return array|FALSE|mixed
*/
public function request($url,array $options = null) {
$f3 = \Base::instance();
if( !$f3->exists( $hash = $this->getCacheKey($url, $options) ) ){
$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);
}
}
}else{
$result = $f3->get($hash);
}
return $result;
}
}

View File

@@ -13,7 +13,7 @@ use Exception;
use Controller;
use DB;
class BasicModel extends \DB\Cortex {
abstract class BasicModel extends \DB\Cortex {
/**
* Hive key with DB object
@@ -81,15 +81,17 @@ class BasicModel extends \DB\Cortex {
$self->clearCacheData();
});
// model updated
$this->afterupdate( function($self){
$self->clearCacheData();
});
// model updated
$this->beforeinsert( function($self){
$self->beforeInsertEvent($self);
});
$this->aftererase( function($self){
$self->aftereraseEvent($self);
});
}
@@ -226,7 +228,7 @@ class BasicModel extends \DB\Cortex {
$cacheKey = null;
// set a model unique cache key if the model is saved
if( $this->_id > 0){
if( $this->id > 0){
// check if there is a given key prefix
// -> if not, use the standard key.
// this is useful for caching multiple data sets according to one row entry
@@ -338,11 +340,20 @@ class BasicModel extends \DB\Cortex {
}
/**
* function should be overwritten in child classes with access restriction
* @param $accessObject
* Event "Hook" function
* can be overwritten
* @return bool
*/
public function hasAccess($accessObject){
public function aftereraseEvent($self){
return true;
}
/**
* function should be overwritten in child classes with access restriction
* @param UserModel $user
* @return bool
*/
public function hasAccess(UserModel $user){
return true;
}
@@ -357,7 +368,7 @@ class BasicModel extends \DB\Cortex {
/**
* get cached data from this model
* @param string $dataCacheKeyPrefix - optional key prefix
* @return mixed|null
* @return \stdClass|null
*/
protected function getCacheData($dataCacheKeyPrefix = ''){
@@ -427,9 +438,9 @@ class BasicModel extends \DB\Cortex {
/**
* factory for all Models
* @param $model
* @param string $model
* @param int $ttl
* @return null
* @return BasicModel
* @throws \Exception
*/
public static function getNew($model, $ttl = 86400){
@@ -447,7 +458,7 @@ class BasicModel extends \DB\Cortex {
/**
* get the framework instance (singleton)
* @return static
* @return \Base
*/
public static function getF3(){
return \Base::instance();
@@ -455,7 +466,7 @@ class BasicModel extends \DB\Cortex {
/**
* debug log function
* @param $text
* @param string $text
*/
public static function log($text){
Controller\LogController::getLogger('debug')->write($text);

View File

@@ -14,6 +14,14 @@ class CharacterLogModel extends BasicModel {
protected $table = 'character_log';
/**
* caching for relational data
* -> 10s matches REST API - Expire: Header-Data
* for "Location" calls
* @var int
*/
protected $rel_ttl = 10;
protected $fieldConf = [
'active' => [
'type' => Schema::DT_BOOL,
@@ -68,6 +76,17 @@ class CharacterLogModel extends BasicModel {
});
}
/**
* set log data from object
* @param object $logData
*/
public function setData($logData){
if( !empty($logData->system) ){
$this->systemId = $logData->system['id'];
$this->systemName = $logData->system['name'];
}
}
/**
* get all character log data
* @return object

View File

@@ -0,0 +1,75 @@
<?php
/**
* Created by PhpStorm.
* User: Exodus
* Date: 07.02.2016
* Time: 12:31
*/
namespace Model;
use DB\SQL\Schema;
class CharacterMapModel extends BasicModel {
protected $table = 'character_map';
protected $fieldConf = [
'active' => [
'type' => Schema::DT_BOOL,
'nullable' => false,
'default' => 1,
'index' => true
],
'characterId' => [
'type' => Schema::DT_INT,
'index' => true,
'belongs-to-one' => 'Model\CharacterModel',
'constraint' => [
[
'table' => 'character',
'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(['characterId', 'mapId'], true);
}
return $status;
}
}

View File

@@ -8,6 +8,7 @@
namespace Model;
use Controller\Ccp;
use DB\SQL\Schema;
class CharacterModel extends BasicModel {
@@ -15,6 +16,10 @@ class CharacterModel extends BasicModel {
protected $table = 'character';
protected $fieldConf = [
'lastLogin' => [
'type' => Schema::DT_TIMESTAMP,
'index' => true
],
'active' => [
'type' => Schema::DT_BOOL,
'nullable' => false,
@@ -26,6 +31,22 @@ class CharacterModel extends BasicModel {
'nullable' => false,
'default' => ''
],
'ownerHash' => [
'type' => Schema::DT_VARCHAR128,
'nullable' => false,
'default' => ''
],
'crestAccessToken' => [
'type' => Schema::DT_VARCHAR256
],
'crestAccessTokenUpdated' => [
'type' => Schema::DT_TIMESTAMP,
'default' => Schema::DF_CURRENT_TIMESTAMP,
'index' => true
],
'crestRefreshToken' => [
'type' => Schema::DT_VARCHAR256
],
'corporationId' => [
'type' => Schema::DT_INT,
'index' => true,
@@ -57,6 +78,9 @@ class CharacterModel extends BasicModel {
'nullable' => false,
'default' => ''
],
'userCharacter' => [
'has-one' => ['Model\UserCharacterModel', 'characterId']
],
'characterLog' => [
'has-one' => ['Model\CharacterLogModel', 'characterId']
]
@@ -65,19 +89,17 @@ class CharacterModel extends BasicModel {
/**
* get character data
* @param bool|false $addCharacterLogData
* @return object
* @return \stdClass
*/
public function getData($addCharacterLogData = false){
// check if there is cached data
// temporary disabled (performance test)
$characterData = null; //$this->getCacheData();
$characterData = $this->getCacheData();
if(is_null($characterData)){
// no cached character data found
$characterData = (object) [];
$characterData->id = $this->id;
$characterData->name = $this->name;
@@ -106,18 +128,50 @@ class CharacterModel extends BasicModel {
return $characterData;
}
/**
* set unique "ownerHash" for this character
* -> Hash will change when character is transferred (sold)
* @param string $ownerHash
* @return string
*/
public function set_ownerHash($ownerHash){
if (
$this->hasUserCharacter() &&
$this->ownerHash !== $ownerHash
){
$this->userCharacter->erase();
}
return $ownerHash;
}
/**
* set CREST accessToken for current session
* -> update "tokenUpdated" column on change
* -> this is required for expire checking!
* @param string $accessToken
* @return string
*/
public function set_crestAccessToken($accessToken){
if($this->crestAccessToken !== $accessToken){
$this->touch('crestAccessTokenUpdated');
}
return $accessToken;
}
/**
* check whether this character has already a user assigned to it
* @return bool
*/
public function hasUserCharacter(){
return is_object($this->userCharacter);
}
/**
* check whether this character has a corporation
* @return bool
*/
public function hasCorporation(){
$hasCorporation = false;
if($this->corporationId){
$hasCorporation = true;
}
return $hasCorporation;
return is_object($this->corporationId);
}
/**
@@ -125,46 +179,177 @@ class CharacterModel extends BasicModel {
* @return bool
*/
public function hasAlliance(){
$hasAlliance = false;
return is_object($this->allianceId);
}
if($this->allianceId){
$hasAlliance = true;
/**
* @return UserModel|null
*/
public function getUser(){
$user = null;
if($this->hasUserCharacter()){
/**
* @var $user UserModel
*/
$user = $this->userCharacter->userId;
}
return $hasAlliance;
return $user;
}
/**
* get the corporation for this user
* @return mixed|null
* @return \Model\CorporationModel|null
*/
public function getCorporation(){
$corporation = null;
if($this->hasCorporation()){
$corporation = $this->corporationId;
}
return $corporation;
return $this->corporationId;
}
/**
* get the alliance of this user
* @return mixed|null
* @return \Model\AllianceModel|null
*/
public function getAlliance(){
$alliance = null;
return $this->allianceId;
}
if($this->hasAlliance()){
$alliance = $this->allianceId;
/**
* get CREST API "access_token" from OAuth
* @return bool|string
*/
private function getAccessToken(){
$accessToken = false;
// check if there is already an "accessToken" for this user
// check expire timer for stored "accessToken"
if(
!empty($this->crestAccessToken) &&
!empty($this->crestAccessTokenUpdated)
){
$timezone = new \DateTimeZone( $this->getF3()->get('TZ') );
$tokenTime = \DateTime::createFromFormat(
'Y-m-d H:i:s',
$this->crestAccessTokenUpdated,
$timezone
);
// add expire time buffer for this "accessToken"
// token should be marked as "deprecated" BEFORE it actually expires.
$timeBuffer = 2 * 60;
$tokenTime->add(new \DateInterval('PT' . (Ccp\Sso::ACCESS_KEY_EXPIRE_TIME - $timeBuffer) . 'S'));
$now = new \DateTime('now', $timezone);
if($tokenTime->getTimestamp() > $now->getTimestamp()){
$accessToken = $this->crestAccessToken;
}
}
return $alliance;
// if no "accessToken" was found -> get a fresh one by an existing "refreshToken"
if(
!$accessToken &&
!empty($this->crestRefreshToken)
){
// no accessToken found OR token is deprecated
$ssoController = new Ccp\Sso();
$accessData = $ssoController->refreshAccessToken($this->crestRefreshToken);
if(
isset($accessData->accessToken) &&
isset($accessData->refreshToken)
){
$this->crestAccessToken = $accessData->accessToken;
$this->save();
$accessToken = $this->crestAccessToken;
}
}
return $accessToken;
}
/**
* checks whether this character is authorized to log in
* -> check corp/ally whitelist config (pathfinder.ini)
* @return bool
*/
public function isAuthorized(){
$isAuthorized = false;
$f3 = self::getF3();
$whitelistCorporations = $whitelistAlliance = [];
if( !empty($f3->get('PATHFINDER.LOGIN.CORPORATION')) ){
$whitelistCorporations = array_map('trim',(array) $f3->get('PATHFINDER.LOGIN.CORPORATION') );
}
if( !empty($f3->get('PATHFINDER.LOGIN.ALLIANCE')) ){
$whitelistAlliance = array_map('trim',(array) $f3->get('PATHFINDER.LOGIN.ALLIANCE') );
}
if(
empty($whitelistCorporations) &&
empty($whitelistAlliance)
){
// no corp/ally restrictions set -> any character is allowed to login
$isAuthorized = true;
}else{
// check if character corporation is set in whitelist
if(
!empty($whitelistCorporations) &&
$this->hasCorporation() &&
in_array($this->getCorporation()->_id, $whitelistCorporations)
){
$isAuthorized = true;
}
// check if character alliance is set in whitelist
if(
!$isAuthorized &&
!empty($whitelistAlliance) &&
$this->hasAlliance() &&
in_array($this->getAlliance()->_id, $whitelistAlliance)
){
$isAuthorized = true;
}
}
return $isAuthorized;
}
/**
* update character log (active system, ...)
* -> CREST API request for character log data
* @return CharacterModel
*/
public function updateLog(){
$characterModel = $this;
$ssoController = new Ccp\Sso();
$locationData = $ssoController->getCharacterLocationData($this->getAccessToken());
if( empty((array)$locationData) ){
// character is not in-game
if(is_object($this->characterLog)){
// delete existing log
$this->characterLog->erase();
$characterModel = $this->save();
}
}else{
// character is currently in-game
if( !$characterLog = $this->getLog() ){
// create new log
$characterLog = $this->rel('characterLog');
$characterLog->characterId = $this;
}
$characterLog->setData($locationData);
$characterLog->save();
$this->characterLog = $characterLog;
$characterModel = $this->save();
}
return $characterModel;
}
/**
* get the character log entry for this character
* @return bool|null
* @return bool|CharacterLogModel
*/
public function getLog(){

View File

@@ -103,11 +103,11 @@ class ConnectionModel extends BasicModel{
/**
* check object for model access
* @param $accessObject
* @return bool
* @param UserModel $user
* @return mixed
*/
public function hasAccess($accessObject){
return $this->mapId->hasAccess($accessObject);
public function hasAccess(UserModel $user){
return $this->mapId->hasAccess($user);
}
/**
@@ -127,13 +127,13 @@ class ConnectionModel extends BasicModel{
/**
* delete a connection
* @param $accessObject
* @param UserModel $user
*/
public function delete($accessObject){
public function delete(UserModel $user){
if(!$this->dry()){
// check if editor has access
if($this->hasAccess($accessObject)){
if($this->hasAccess($user)){
$this->erase();
}
}

View File

@@ -8,6 +8,7 @@
namespace Model;
use Controller\Api\User;
use DB\SQL\Schema;
class MapModel extends BasicModel {
@@ -117,16 +118,14 @@ class MapModel extends BasicModel {
}
}
/**
* get map data
* -> this includes system and connection data as well!
* @return array
* @return \stdClass
*/
public function getData(){
// check if there is cached data
$mapDataAll = $this->getCacheData();
// check if there is cached data
$mapDataAll = $this->getCacheData();
if(is_null($mapDataAll)){
// no cached map data found
@@ -355,25 +354,34 @@ class MapModel extends BasicModel {
/**
* clear access for a given type of objects
* @param $clearKeys
* @param array $clearKeys
*/
public function clearAccess($clearKeys = ['user', 'corporation', 'alliance']){
foreach($clearKeys as $key){
switch($key){
case 'user':
foreach((array)$this->mapUsers as $obj){
$obj->erase();
foreach((array)$this->mapUsers as $userMapModel){
/**
* @var UserMapModel $userMapModel
*/
$userMapModel->erase();
};
break;
case 'corporation':
foreach((array)$this->mapCorporations as $obj){
$obj->erase();
foreach((array)$this->mapCorporations as $corporationMapModel){
/**
* @var CorporationMapModel $corporationMapModel
*/
$corporationMapModel->erase();
};
break;
case 'alliance':
foreach((array)$this->mapAlliances as $obj){
$obj->erase();
foreach((array)$this->mapAlliances as $allianceMapModel){
/**
* @var AllianceMapModel $allianceMapModel
*/
$allianceMapModel->erase();
};
break;
}
@@ -382,21 +390,16 @@ class MapModel extends BasicModel {
/**
* checks weather a user has access to this map or not
* @param $user
* @param UserModel $user
* @return bool
*/
public function hasAccess($user){
public function hasAccess(UserModel $user){
$hasAccess = false;
if(
!$this->dry() &&
$user instanceof UserModel
){
if( !$this->dry() ){
// get all maps the user has access to
// this includes corporation and alliance maps
$maps = $user->getMaps();
foreach($maps as $map){
if($map->id === $this->id){
$hasAccess = true;
@@ -411,7 +414,7 @@ class MapModel extends BasicModel {
/**
* get all user models that have access to this map
* note: This function is just for "private" maps
* @return array
* @return UserModel[]
*/
public function getUsers(){
$users = [];
@@ -431,7 +434,7 @@ class MapModel extends BasicModel {
/**
* get all character models that are currently online "viewing" this map
* @return array
* @return CharacterModel[]
*/
private function getCharacters(){
$characters = [];
@@ -439,24 +442,29 @@ class MapModel extends BasicModel {
if($this->isPrivate()){
$users = $this->getUsers();
// add active character for each user
foreach($users as $user){
// get all active character logs for a user
$tempActiveUserCharacters = $user->getActiveUserCharacters();
foreach($tempActiveUserCharacters as $tempActiveUserCharacter){
$characters[] = $tempActiveUserCharacter;
}
/**
* @var UserModel $user
*/
$characters = array_merge($characters, $user->getActiveCharacters());
}
}elseif($this->isCorporation()){
$corporations = $this->getCorporations();
foreach($corporations as $corporation){
/**
* @var CorporationModel $corporation
*/
$characters = array_merge($characters, $corporation->getCharacters());
}
}elseif($this->isAlliance()){
$alliances = $this->getAlliances();
foreach($alliances as $alliance){
/**
* @var AllianceModel $alliance
*/
$characters = array_merge($characters, $alliance->getCharacters());
}
}
@@ -531,16 +539,15 @@ class MapModel extends BasicModel {
return $alliances;
}
/**
* delete this map and all dependencies
* @param $accessObject
* @param UserModel $user
*/
public function delete($accessObject){
public function delete(UserModel $user){
if(!$this->dry()){
// check if editor has access
if($this->hasAccess($accessObject)){
// check if user has access
if($this->hasAccess($user)){
// all map related tables will be deleted on cascade
// delete map

View File

@@ -313,23 +313,23 @@ class SystemModel extends BasicModel {
/**
* check object for model access
* @param $accessObject
* @return bool
* @param UserModel $user
* @return mixed
*/
public function hasAccess($accessObject){
return $this->mapId->hasAccess($accessObject);
public function hasAccess(UserModel $user){
return $this->mapId->hasAccess($user);
}
/**
* delete a system from a map
* hint: signatures and connections will be deleted on cascade
* @param $accessObject
* @param UserModel $user
*/
public function delete($accessObject){
public function delete(UserModel $user){
if(! $this->dry()){
// check if user has access
if($this->hasAccess($accessObject)){
if($this->hasAccess($user)){
$this->erase();
}
}
@@ -367,14 +367,14 @@ class SystemModel extends BasicModel {
/**
* get Signature by id and check for access
* @param $accessObject
* @param UserModel $user
* @param $id
* @return bool|null
*/
public function getSignatureById($accessObject, $id){
public function getSignatureById(UserModel $user, $id){
$signature = null;
if($this->hasAccess($accessObject)){
if($this->hasAccess($user)){
$this->filter('signatures', ['active = ? AND id = ?', 1, $id]);
if($this->signatures){
$signature = reset( $this->signatures );
@@ -386,14 +386,14 @@ class SystemModel extends BasicModel {
/**
* get a signature by its "unique" 3-digit name
* @param $accessObject
* @param UserModel $user
* @param $name
* @return mixed|null
*/
public function getSignatureByName($accessObject, $name){
public function getSignatureByName(UserModel $user, $name){
$signature = null;
if($this->hasAccess($accessObject)){
if($this->hasAccess($user)){
$this->filter('signatures', ['active = ? AND name = ?', 1, $name]);
if($this->signatures){
$signature = reset( $this->signatures );

View File

@@ -151,18 +151,21 @@ class SystemSignatureModel extends BasicModel {
/**
* check object for model access
* @param $accessObject
* @param UserModel $user
* @return bool
*/
public function hasAccess($accessObject){
return $this->systemId->hasAccess($accessObject);
public function hasAccess(UserModel $user){
return $this->systemId->hasAccess($user);
}
public function delete($accessObject){
/**
* delete signature
* @param UserModel $user
*/
public function delete(UserModel $user){
if(!$this->dry()){
// check if editor has access
if($this->hasAccess($accessObject)){
if($this->hasAccess($user)){
$this->erase();
}
}

View File

@@ -60,15 +60,6 @@ class UserApiModel extends BasicModel {
return $apiData;
}
/**
* @return int
*/
public function updateCharacters(){
$apiController = new Controller\CcpApiController();
return $apiController->updateCharacters($this);
}
/**
* get all characters for this API
* @return array|mixed

View File

@@ -46,6 +46,7 @@ class UserCharacterModel extends BasicModel {
'characterId' => [
'type' => Schema::DT_INT,
'index' => true,
'unique' => true,
'belongs-to-one' => 'Model\CharacterModel',
'constraint' => [
[
@@ -79,34 +80,22 @@ class UserCharacterModel extends BasicModel {
}
/**
* get all character data
* @param $addCharacterLogData
* @return array
* event "Hook"
* -> remove user if there are no other characters bound to this user
* @param $self
* @return bool
*/
public function getData($addCharacterLogData = false){
// get characterModel
$characterModel = $this->getCharacter();
// get static character data
$characterData = $characterModel->getData($addCharacterLogData);
// add user specific character data
$characterData->isMain = $this->isMain;
// check for corporation
if( is_object( $characterModel->corporationId ) ){
$characterData->corporation = $characterModel->corporationId->getData();
public function aftereraseEvent($self){
if(
is_object($self->userId) &&
is_null($self->userId->userCharacters)
){
$self->userId->erase();
}
// check for alliance
if( is_object( $characterModel->allianceId ) ){
$characterData->alliance = $characterModel->allianceId->getData();
}
return $characterData;
return true;
}
/**
* check if this character is Main character or not
* @return bool

View File

@@ -10,6 +10,7 @@ namespace Model;
use DB\SQL\Schema;
use Controller;
use Controller\Api;
use Exception;
class UserModel extends BasicModel {
@@ -17,10 +18,6 @@ class UserModel extends BasicModel {
protected $table = 'user';
protected $fieldConf = [
'lastLogin' => [
'type' => Schema::DT_TIMESTAMP,
'index' => true
],
'active' => [
'type' => Schema::DT_BOOL,
'nullable' => false,
@@ -31,15 +28,12 @@ class UserModel extends BasicModel {
'type' => Schema::DT_VARCHAR128,
'nullable' => false,
'default' => '',
'index' => true,
'unique' => true
'index' => true
],
'email' => [
'type' => Schema::DT_VARCHAR128,
'nullable' => false,
'default' => '',
'index' => true,
'unique' => true
'default' => ''
],
'password' => [
'type' => Schema::DT_VARCHAR128,
@@ -69,11 +63,6 @@ class UserModel extends BasicModel {
'max' => 25
]
],
'email' => [
'length' => [
'min' => 5
]
],
'password' => [
'length' => [
'min' => 6
@@ -83,9 +72,9 @@ class UserModel extends BasicModel {
/**
* get all data for this user
* ! caution ! this function returns sensitive data!
* -> ! caution ! this function returns sensitive data! (e.g. email,..)
* -> user getSimpleData() for faster performance and public user data
* @return object
* @return \stdClass
*/
public function getData(){
@@ -98,24 +87,19 @@ class UserModel extends BasicModel {
// user shared info
$userData->shared = $this->shared;
// api data
$APIs = $this->getAPIs();
foreach($APIs as $api){
$userData->api[] = $api->getData();
}
// all chars
$userData->characters = [];
$userCharacters = $this->getUserCharacters();
foreach($userCharacters as $userCharacter){
$userData->characters[] = $userCharacter->getData();
$characters = $this->getCharacters();
foreach($characters as $character){
/**
* @var $character CharacterModel
*/
$userData->characters[] = $character->getData();
}
// set active character with log data
$activeUserCharacter = $this->getActiveUserCharacter();
if($activeUserCharacter){
$userData->character = $activeUserCharacter->getData(true);
}
$activeCharacter = $this->getActiveCharacter();
$userData->character = $activeCharacter->getData(true);
return $userData;
}
@@ -123,7 +107,7 @@ class UserModel extends BasicModel {
/**
* get public user data
* - check out getData() for all user data
* @return object
* @return \stdClass
*/
public function getSimpleData(){
$userData = (object) [];
@@ -135,11 +119,15 @@ class UserModel extends BasicModel {
/**
* validate and set a email address for this user
* @param $email
* @return mixed
* -> empty email is allowed!
* @param string $email
* @return string
*/
public function set_email($email){
if (\Audit::instance()->email($email) == false) {
if (
!empty($email) &&
\Audit::instance()->email($email) == false
) {
// no valid email address
$this->throwValidationError('email');
}
@@ -148,8 +136,8 @@ class UserModel extends BasicModel {
/**
* set a password hash for this user
* @param $password
* @return FALSE|string
* @param string $password
* @return string
*/
public function set_password($password){
if(strlen($password) < 6){
@@ -208,10 +196,9 @@ class UserModel extends BasicModel {
/**
* get all accessible map models for this user
* @return array
* @return MapModel[]
*/
public function getMaps(){
$f3 = self::getF3();
$this->filter(
'userMaps',
@@ -222,34 +209,29 @@ class UserModel extends BasicModel {
$maps = [];
if($this->userMaps){
$mapCountPrivate = 0;
foreach($this->userMaps as $userMap){
foreach($this->userMaps as &$userMap){
if(
$userMap->mapId->isActive() &&
$mapCountPrivate < $f3->get('PATHFINDER.MAX_MAPS_PRIVATE')
$mapCountPrivate < self::getF3()->get('PATHFINDER.MAX_MAPS_PRIVATE')
){
$maps[] = $userMap->mapId;
$maps[] = &$userMap->mapId;
$mapCountPrivate++;
}
}
}
$activeUserCharacter = $this->getActiveUserCharacter();
// get current active character
$controller = new Controller\Controller();
$activeCharacter = $controller->getCharacter();
$corporation = $activeCharacter->getCorporation();
$alliance = $activeCharacter->getAlliance();
if($activeUserCharacter){
$character = $activeUserCharacter->getCharacter();
$corporation = $character->getCorporation();
$alliance = $character->getAlliance();
if($alliance){
$maps = array_merge($maps, $alliance->getMaps());
}
if($alliance){
$allianceMaps = $alliance->getMaps();
$maps = array_merge($maps, $allianceMaps);
}
if($corporation){
$corporationMaps = $corporation->getMaps();
$maps = array_merge($maps, $corporationMaps);
}
if($corporation){
$maps = array_merge($maps, $corporation->getMaps());
}
return $maps;
@@ -257,13 +239,16 @@ class UserModel extends BasicModel {
/**
* get mapModel by id and check if user has access
* @param $mapId
* @return null
* @throws \Exception
* @param int $mapId
* @return MapModel|null
* @throws Exception
*/
public function getMap($mapId){
public function getMap(int $mapId){
/**
* @var $map MapModel
*/
$map = self::getNew('MapModel');
$map->getById( (int)$mapId );
$map->getById( $mapId );
$returnMap = null;
if($map->hasAccess($this)){
@@ -324,35 +309,14 @@ class UserModel extends BasicModel {
/**
* get all userCharacters models for a user
* characters will be checked/updated on login by CCP API call
* @return array|mixed
* @return UserCharacterModel[]
*/
public function getUserCharacters(){
$this->filter('userCharacters', ['active = ?', 1]);
$this->filter('apis', ['active = ?', 1]);
// if a user has multiple API keys saved for ONE character,
// skip double characters!
$userCharacters = [];
if($this->apis){
$this->apis->rewind();
while($this->apis->valid()){
$this->apis->current()->filter('userCharacters', ['active = ?', 1]);
if($this->apis->current()->userCharacters){
$this->apis->current()->userCharacters->rewind();
while($this->apis->current()->userCharacters->valid()){
$tempCharacterId = $this->apis->current()->userCharacters->current()->characterId->get('id');
if( !isset($userCharacters[ $tempCharacterId ]) ){
$userCharacters[ $tempCharacterId ] = $this->apis->current()->userCharacters->current();
}
$this->apis->current()->userCharacters->next();
}
}
$this->apis->next();
}
if($this->userCharacters){
$userCharacters = $this->userCharacters;
}
return $userCharacters;
@@ -377,82 +341,72 @@ class UserModel extends BasicModel {
}
/**
* get the active user character for this user
* either there is an active Character (IGB) or the character labeled as "main"
* @return null
* get the current active character for this user
* -> EITHER - the current active one for the current user
* -> OR - get the first active one
* @return null|CharacterModel
*/
public function getActiveUserCharacter(){
$activeUserCharacter = null;
public function getActiveCharacter(){
$activeCharacter = null;
$controller = new Controller\Controller();
$currentActiveCharacter = $controller->getCharacter();
$headerData = Controller\CcpApiController::getIGBHeaderData();
// check if IGB Data is available
if( !empty($headerData->values) ){
// search for the active character by IGB Header Data
$this->filter('userCharacters',
[
'active = :active AND characterId = :characterId',
':active' => 1,
':characterId' => intval($headerData->values['charid'])
],
['limit' => 1]
);
if($this->userCharacters){
// check if userCharacter has active log
$userCharacter = current($this->userCharacters);
if( $userCharacter->getCharacter()->getLog() ){
$activeUserCharacter = $userCharacter;
}
if(
!is_null($currentActiveCharacter) &&
$currentActiveCharacter->getUser()->_id === $this->id
){
$activeCharacter = &$currentActiveCharacter;
}else{
// set "first" found as active for this user
if($activeCharacters = $this->getActiveCharacters()){
$activeCharacter = &$activeCharacters[0];
}
}
// if no active character is found
// e.g. not online in IGB
// -> get main Character
if(is_null($activeUserCharacter)){
$activeUserCharacter = $this->getMainUserCharacter();
}
return $activeUserCharacter;
return $activeCharacter;
}
/**
* get all active user characters (with log entry)
* hint: a user can have multiple active characters
* @return array
* get all characters for this user
* @return CharacterModel[]
*/
public function getActiveUserCharacters(){
public function getCharacters(){
$userCharacters = $this->getUserCharacters();
$characters = [];
foreach($userCharacters as $userCharacter){
/**
* @var $userCharacter UserCharacterModel
*/
if( $currentCharacter = $userCharacter->getCharacter() ){
// check if userCharacter has a valid character
// -> this should never fail!
$characters[] = $currentCharacter;
}
}
return $characters;
}
/**
* get all active characters (with log entry)
* hint: a user can have multiple active characters
* @return CharacterModel[]
*/
public function getActiveCharacters(){
$userCharacters = $this->getUserCharacters();
$activeUserCharacters = [];
$activeCharacters = [];
foreach($userCharacters as $userCharacter){
$characterLog = $userCharacter->getCharacter()->getLog();
if($characterLog){
$activeUserCharacters[] = $userCharacter;
/**
* @var $userCharacter UserCharacterModel
*/
$characterModel = $userCharacter->getCharacter();
if($characterLog = $characterModel->getLog()){
$activeCharacters[] = $characterModel;
}
}
return $activeUserCharacters;
}
/**
* update/check API information.
* request API information from CCP
*/
public function updateApiData(){
$this->filter('apis', ['active = ?', 1]);
if($this->apis){
$this->apis->rewind();
while($this->apis->valid()){
$this->apis->current()->updateCharacters();
$this->apis->next();
}
}
return $activeCharacters;
}
/**
@@ -460,8 +414,10 @@ class UserModel extends BasicModel {
* @param int $ttl cache time in seconds
* @throws \Exception
*/
/*
public function updateCharacterLog($ttl = 0){
$headerData = Controller\CcpApiController::getIGBHeaderData();
$headerData = Controller\Controller::getIGBHeaderData();
// check if IGB Data is available
if( !empty($headerData->values) ){
@@ -551,6 +507,7 @@ class UserModel extends BasicModel {
}
}
}
*/
}

View File

@@ -34,6 +34,11 @@ INVITE = 0
; the limit of registration keys. Increase it to hand out more keys
INVITE_LIMIT = 50
[PATHFINDER.LOGIN]
CORPORATION = 1000166
ALLIANCE =
; View ============================================================================================
[PATHFINDER.VIEW]
; static page templates
@@ -102,11 +107,6 @@ DELETE_ACCOUNT = delete_account
; API =============================================================================================
[PATHFINDER.API]
; CCP SSO OAuth 2.0
CCP_SSO = https://login.eveonline.com
; CCP CREST API
CCP_CREST = https://crest-tq.eveonline.com
; CCP_CREST = https://api-sisi.testeveonline.com
; CCP XML APIv2
CCP_XML = https://api.eveonline.com
; GitHub Developer API

View File

@@ -7,7 +7,7 @@ GET @setup: /setup = Controller\Setup->in
; login (index) page
GET @login: / = Controller\AppController->init, 0
; CCP SSO redirect
GET @sso: /sso/@action = Controller\CcpSsoController->@action, 0
GET @sso: /sso/@action = Controller\Ccp\Sso->@action, 0
; map page
GET @map: /map = Controller\MapController->init, 0

View File

@@ -642,7 +642,7 @@ define([
}
}
}
console.log(usersData);
var userDataTable = userTable.dataTable( {
pageLength: 20,

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 174 KiB

View File

@@ -642,7 +642,7 @@ define([
}
}
}
console.log(usersData);
var userDataTable = userTable.dataTable( {
pageLength: 20,

View File

@@ -75,31 +75,21 @@
<h2><span class="text-primary">Please</span> log in</h2>
</div>
</div>
<form id="pf-login-form" class="" role="form" method="post" action="#">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-sm-3 col-sm-offset-3">
<div class="form-group">
<input type="text" class="form-control" name="userName" id="userName" placeholder="Username" autocomplete="off" tabindex="1" data-error="Username required" autofocus required>
<div class="help-block with-errors text-left"></div>
</div>
</div>
<div class="col-xs-12 col-sm-3">
<div class="form-group">
<input type="password" class="form-control" name="userPassword" id="userPassword" placeholder="Password" autocomplete="off" tabindex="2" data-error="Password required" required>
<div class="help-block with-errors text-left"></div>
</div>
</div>
</div>
</div>
{* login message container *}
<div class="container-fluid">
<div class="row ">
<div id="pf-login-message-container" class="col-sm-8 col-sm-offset-2"></div>
<check if="{{ @SESSION.SSO.ERROR }}">
<div class="container-fluid">
<div class="row ">
<div class="col-sm-8 col-sm-offset-2">
<div class="alert alert-danger" >
<span class="txt-color txt-color-danger">Access denied</span>
<small>{{ @SESSION.SSO.ERROR }}</small>
</div>
</div>
</div>
</div>
</div>
</check>
{* check for setup mode *}
<check if="{{ array_key_exists('/setup', @ROUTES) && @PATHFINDER.SHOW_SETUP_WARNING }}">
@@ -130,23 +120,20 @@
</div>
</check>
{* signUp/logIn buttons *}
<div class="row text-center">
<div class="col-xs-12 col-sm-6 col-sm-offset-3">
<div class="col-xs-6 col-sm-4 col-sm-offset-2" data-placement="left" title="{{@registrationStatusTitle}}">
<button type="button" class="pf-register-button btn-block btn btn-primary {{@registrationStatusButton}}" tabindex="-1"><i class="fa fa-fw fa-user-plus"></i> Sign up</button>
</div>
<div class="col-xs-6 col-sm-4">
<button type="submit" class="pf-login-button btn-block btn btn-success" tabindex="3"><i class="fa fa-fw fa-sign-in"></i> Log in</button>
{* SSO login *}
<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}}">&nbsp;</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>
</div>
</form>
</div>
</section>
<a href="{{ 'sso','action=requestAuthorization' | alias }}">SSO login</a>
{* features/ gallery *}
<section id="pf-landing-gallery">

View File

@@ -314,9 +314,45 @@
// login ----------------------------------------------------------------------
#pf-landing-login{
padding-top: 40px;
padding-bottom: 30px;
.row{
margin-bottom: 0px;
margin-bottom: 0;
}
.pf-sso-login-button{
position: relative;
display: inline-block;
width: 270px;
height: 45px;
border: none;
margin-bottom: 10px;
background-color: transparent;
background-image: url("#{$base-url}/landing/eve_sso_login_buttons_large_black_hover.png");
cursor: pointer;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
@include transition(box-shadow 0.12s ease-out);
will-change: box-shadow;
&:after {
content: ' ';
position: absolute;
width: 270px;
height: 45px;
left: 0;
top: 0;
background-image: url("#{$base-url}/landing/eve_sso_login_buttons_large_black.png");
@include transition(opacity 0.12s ease-in-out);
will-change: opacity;
}
&:hover {
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.2);
&:after{
opacity: 0;
}
}
}
}