2019-05-09 18:54:39 +12:00
< ? php
2019-09-04 08:37:34 +12:00
global $utopia , $response , $projectDB , $providers ;
2019-05-09 18:54:39 +12:00
use Auth\Auth ;
use Auth\Validator\Password ;
use Utopia\Exception ;
2019-06-09 20:51:10 +12:00
use Utopia\Response ;
2019-05-09 18:54:39 +12:00
use Utopia\Validator\WhiteList ;
use Utopia\Validator\Email ;
use Utopia\Validator\Text ;
use Utopia\Validator\Range ;
use Utopia\Locale\Locale ;
use Database\Database ;
use Database\Validator\Authorization ;
use Database\Validator\UID ;
use DeviceDetector\DeviceDetector ;
use GeoIp2\Database\Reader ;
$utopia -> get ( '/v1/users' )
-> desc ( 'List Users' )
-> label ( 'scope' , 'users.read' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'listUsers' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/list-users.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'search' , '' , function () { return new Text ( 256 ); }, 'Search term to filter your list results.' , true )
-> param ( 'limit' , 25 , function () { return new Range ( 0 , 100 ); }, 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.' , true )
-> param ( 'offset' , 0 , function () { return new Range ( 0 , 2000 ); }, 'Results offset. The default value is 0. Use this param to manage pagination.' , true )
-> param ( 'orderType' , 'ASC' , function () { return new WhiteList ([ 'ASC' , 'DESC' ]); }, 'Order result by ASC or DESC order.' , true )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $search , $limit , $offset , $orderType ) use ( $response , $projectDB , $providers ) {
2019-05-09 18:54:39 +12:00
$results = $projectDB -> getCollection ([
'limit' => $limit ,
'offset' => $offset ,
'orderField' => 'registration' ,
'orderType' => $orderType ,
'orderCast' => 'int' ,
'search' => $search ,
'filters' => [
2019-09-07 05:10:41 +12:00
'$collection=' . Database :: SYSTEM_COLLECTION_USERS ,
2019-05-09 18:54:39 +12:00
],
]);
2019-09-04 08:37:34 +12:00
$oauthKeys = [];
2019-09-07 05:10:41 +12:00
foreach ( $providers as $key => $provider ) {
if ( ! $provider [ 'enabled' ]) {
2019-09-04 08:37:34 +12:00
continue ;
}
2019-09-07 05:10:41 +12:00
$oauthKeys [] = 'oauth' . ucfirst ( $key );
$oauthKeys [] = 'oauth' . ucfirst ( $key ) . 'AccessToken' ;
2019-09-04 08:37:34 +12:00
}
$results = array_map ( function ( $value ) use ( $oauthKeys ) { /* @var $value \Database\Document */
return $value -> getArrayCopy ( array_merge (
[
'$uid' ,
'email' ,
'registration' ,
'confirm' ,
'name' ,
2019-09-30 19:13:40 +13:00
],
$oauthKeys
2019-09-04 08:37:34 +12:00
));
2019-05-09 18:54:39 +12:00
}, $results );
$response -> json ([ 'sum' => $projectDB -> getSum (), 'users' => $results ]);
}
);
$utopia -> get ( '/v1/users/:userId' )
-> desc ( 'Get User' )
-> label ( 'scope' , 'users.read' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'getUser' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/get-user.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId ) use ( $response , $projectDB , $providers ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
2019-09-04 08:37:34 +12:00
$oauthKeys = [];
2019-09-07 05:10:41 +12:00
foreach ( $providers as $key => $provider ) {
if ( ! $provider [ 'enabled' ]) {
2019-09-04 08:37:34 +12:00
continue ;
}
2019-09-07 05:10:41 +12:00
$oauthKeys [] = 'oauth' . ucfirst ( $key );
$oauthKeys [] = 'oauth' . ucfirst ( $key ) . 'AccessToken' ;
2019-09-04 08:37:34 +12:00
}
$response -> json ( array_merge ( $user -> getArrayCopy ( array_merge (
[
'$uid' ,
'email' ,
'registration' ,
'confirm' ,
'name' ,
2019-09-30 19:13:40 +13:00
],
$oauthKeys
2019-09-04 08:37:34 +12:00
)), [ 'roles' => Authorization :: getRoles ()]));
2019-05-09 18:54:39 +12:00
}
);
$utopia -> get ( '/v1/users/:userId/prefs' )
-> desc ( 'Get User Prefs' )
-> label ( 'scope' , 'users.read' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'getUserPrefs' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/get-user-prefs.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId ) use ( $response , $projectDB ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
2019-09-07 05:10:41 +12:00
$prefs = $user -> getAttribute ( 'prefs' , '' );
2019-05-09 18:54:39 +12:00
2019-09-07 05:10:41 +12:00
if ( empty ( $prefs )) {
2019-08-09 16:49:36 +12:00
$prefs = '[]' ;
2019-05-09 18:54:39 +12:00
}
try {
$prefs = json_decode ( $prefs , true );
2019-09-07 05:10:41 +12:00
} catch ( \Exception $error ) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'Failed to parse prefs' , 500 );
}
$response -> json ( $prefs );
}
);
$utopia -> get ( '/v1/users/:userId/sessions' )
-> desc ( 'Get User Sessions' )
-> label ( 'scope' , 'users.read' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'getUserSessions' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/get-user-sessions.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId ) use ( $response , $projectDB ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
2019-09-07 05:10:41 +12:00
$tokens = $user -> getAttribute ( 'tokens' , []);
$reader = new Reader ( __DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb' );
$sessions = [];
$index = 0 ;
$countries = Locale :: getText ( 'countries' );
2019-05-09 18:54:39 +12:00
2019-09-07 05:10:41 +12:00
foreach ( $tokens as $token ) { /* @var $token Document */
if ( Auth :: TOKEN_TYPE_LOGIN != $token -> getAttribute ( 'type' )) {
2019-05-09 18:54:39 +12:00
continue ;
}
2019-09-07 05:10:41 +12:00
$userAgent = ( ! empty ( $token -> getAttribute ( 'userAgent' ))) ? $token -> getAttribute ( 'userAgent' ) : 'UNKNOWN' ;
2019-05-09 18:54:39 +12:00
$dd = new DeviceDetector ( $userAgent );
// OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
// $dd->skipBotDetection();
$dd -> parse ();
$sessions [ $index ] = [
2019-09-07 05:10:41 +12:00
'$uid' => $token -> getUid (),
'OS' => $dd -> getOs (),
'client' => $dd -> getClient (),
'device' => $dd -> getDevice (),
'brand' => $dd -> getBrand (),
'model' => $dd -> getModel (),
'ip' => $token -> getAttribute ( 'ip' , '' ),
'geo' => [],
2019-05-09 18:54:39 +12:00
];
try {
$record = $reader -> country ( $token -> getAttribute ( 'ip' , '' ));
$sessions [ $index ][ 'geo' ][ 'isoCode' ] = strtolower ( $record -> country -> isoCode );
$sessions [ $index ][ 'geo' ][ 'country' ] = ( isset ( $countries [ $record -> country -> isoCode ])) ? $countries [ $record -> country -> isoCode ] : Locale :: getText ( 'locale.country.unknown' );
2019-09-07 05:10:41 +12:00
} catch ( \Exception $e ) {
2019-05-09 18:54:39 +12:00
$sessions [ $index ][ 'geo' ][ 'isoCode' ] = '--' ;
$sessions [ $index ][ 'geo' ][ 'country' ] = Locale :: getText ( 'locale.country.unknown' );
}
2019-09-07 05:10:41 +12:00
++ $index ;
2019-05-09 18:54:39 +12:00
}
$response -> json ( $sessions );
}
);
$utopia -> get ( '/v1/users/:userId/logs' )
-> desc ( 'Get User Logs' )
-> label ( 'scope' , 'users.read' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'getUserLogs' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/get-user-logs.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId ) use ( $response , $register , $projectDB , $project ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
$ad = new \Audit\Adapter\MySQL ( $register -> get ( 'db' ));
2019-09-07 05:10:41 +12:00
$ad -> setNamespace ( 'app_' . $project -> getUid ());
2019-05-09 18:54:39 +12:00
$au = new \Audit\Audit ( $ad , $user -> getUid (), $user -> getAttribute ( 'type' ), '' , '' , '' );
2019-09-07 05:10:41 +12:00
$countries = Locale :: getText ( 'countries' );
2019-05-09 18:54:39 +12:00
$logs = $au -> getLogsByUser ( $user -> getUid (), $user -> getAttribute ( 'type' , 0 ));
2019-09-07 05:10:41 +12:00
$reader = new Reader ( __DIR__ . '/../db/GeoLite2/GeoLite2-Country.mmdb' );
$output = [];
2019-05-09 18:54:39 +12:00
2019-09-07 05:10:41 +12:00
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
2019-05-09 18:54:39 +12:00
$dd = new DeviceDetector ( $log [ 'userAgent' ]);
$dd -> skipBotDetection (); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
$dd -> parse ();
$output [ $i ] = [
2019-09-07 05:10:41 +12:00
'event' => $log [ 'event' ],
'ip' => $log [ 'ip' ],
'time' => strtotime ( $log [ 'time' ]),
'OS' => $dd -> getOs (),
'client' => $dd -> getClient (),
'device' => $dd -> getDevice (),
'brand' => $dd -> getBrand (),
'model' => $dd -> getModel (),
'geo' => [],
2019-05-09 18:54:39 +12:00
];
try {
$record = $reader -> country ( $log [ 'ip' ]);
$output [ $i ][ 'geo' ][ 'isoCode' ] = strtolower ( $record -> country -> isoCode );
$output [ $i ][ 'geo' ][ 'country' ] = $record -> country -> name ;
$output [ $i ][ 'geo' ][ 'country' ] = ( isset ( $countries [ $record -> country -> isoCode ])) ? $countries [ $record -> country -> isoCode ] : Locale :: getText ( 'locale.country.unknown' );
2019-09-07 05:10:41 +12:00
} catch ( \Exception $e ) {
2019-05-09 18:54:39 +12:00
$output [ $i ][ 'geo' ][ 'isoCode' ] = '--' ;
2019-09-07 05:10:41 +12:00
$output [ $i ][ 'geo' ][ 'country' ] = Locale :: getText ( 'locale.country.unknown' );
2019-05-09 18:54:39 +12:00
}
}
$response -> json ( $output );
}
);
$utopia -> post ( '/v1/users' )
-> desc ( 'Create User' )
-> label ( 'scope' , 'users.write' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'createUser' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/create-user.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'email' , '' , function () { return new Email (); }, 'User account email.' )
-> param ( 'password' , '' , function () { return new Password (); }, 'User account password.' )
-> param ( 'name' , '' , function () { return new Text ( 100 ); }, 'User account name.' , true )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $email , $password , $name ) use ( $response , $register , $projectDB , $providers ) {
2019-05-09 18:54:39 +12:00
$profile = $projectDB -> getCollection ([ // Get user by email address
'limit' => 1 ,
'first' => true ,
'filters' => [
2019-09-07 05:10:41 +12:00
'$collection=' . Database :: SYSTEM_COLLECTION_USERS ,
'email=' . $email ,
],
2019-05-09 18:54:39 +12:00
]);
2019-09-07 05:10:41 +12:00
if ( ! empty ( $profile )) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User already registered' , 400 );
}
$user = $projectDB -> createDocument ([
'$collection' => Database :: SYSTEM_COLLECTION_USERS ,
'$permissions' => [
'read' => [ '*' ],
'write' => [ 'user:{self}' ],
],
'email' => $email ,
'status' => Auth :: USER_STATUS_UNACTIVATED ,
'password' => Auth :: passwordHash ( $password ),
'password-update' => time (),
'registration' => time (),
'confirm' => false ,
'reset' => false ,
'name' => $name ,
]);
2019-09-07 05:10:41 +12:00
2019-09-04 08:37:34 +12:00
$oauthKeys = [];
2019-09-07 05:10:41 +12:00
foreach ( $providers as $key => $provider ) {
if ( ! $provider [ 'enabled' ]) {
2019-09-04 08:37:34 +12:00
continue ;
}
2019-09-07 05:10:41 +12:00
$oauthKeys [] = 'oauth' . ucfirst ( $key );
$oauthKeys [] = 'oauth' . ucfirst ( $key ) . 'AccessToken' ;
2019-09-04 08:37:34 +12:00
}
2019-05-09 18:54:39 +12:00
2019-06-09 20:51:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
2019-09-04 08:37:34 +12:00
-> json ( array_merge ( $user -> getArrayCopy ( array_merge ([
2019-06-09 20:51:10 +12:00
'$uid' ,
'status' ,
'email' ,
'registration' ,
'confirm' ,
'name' ,
2019-09-04 08:37:34 +12:00
], $oauthKeys )), [ 'roles' => Authorization :: getRoles ()]));
2019-05-09 18:54:39 +12:00
}
);
$utopia -> patch ( '/v1/users/:userId/status' )
2019-10-10 16:52:59 +13:00
-> desc ( 'Update User Status' )
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.write' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updateUserStatus' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/update-user-status.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
-> param ( 'status' , '' , function () { return new WhiteList ([ Auth :: USER_STATUS_ACTIVATED , Auth :: USER_STATUS_BLOCKED , Auth :: USER_STATUS_UNACTIVATED ]); }, 'User Status code. To activate the user pass ' . Auth :: USER_STATUS_ACTIVATED . ', to blocking the user pass ' . Auth :: USER_STATUS_BLOCKED . ' and for disabling the user pass ' . Auth :: USER_STATUS_UNACTIVATED )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId , $status ) use ( $response , $projectDB ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
$user = $projectDB -> updateDocument ( array_merge ( $user -> getArrayCopy (), [
'status' => $status ,
]));
2019-09-07 05:10:41 +12:00
if ( false === $user ) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'Failed saving user to DB' , 500 );
}
$response
-> json ( array ( 'result' => 'success' ));
}
);
2019-10-05 10:04:49 +13:00
$utopia -> patch ( '/v1/users/:userId/prefs' )
2019-10-10 16:52:59 +13:00
-> desc ( 'Update User Prefs' )
2019-10-05 10:04:49 +13:00
-> label ( 'scope' , 'users.write' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updateUserPrefs' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/update-user-prefs.md' )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
-> param ( 'prefs' , '' , function () { return new \Utopia\Validator\Mock (); }, 'Prefs key-value JSON object string.' )
2019-10-05 10:04:49 +13:00
-> action (
function ( $userId , $prefs ) use ( $response , $projectDB ) {
$user = $projectDB -> getDocument ( $userId );
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
throw new Exception ( 'User not found' , 404 );
}
$user = $projectDB -> updateDocument ( array_merge ( $user -> getArrayCopy (), [
'prefs' => json_encode ( array_merge ( json_decode ( $user -> getAttribute ( 'prefs' , '{}' ), true ), $prefs )),
]));
if ( false === $user ) {
throw new Exception ( 'Failed saving user to DB' , 500 );
}
$response -> json ( array ( 'result' => 'success' ));
}
);
2019-05-09 18:54:39 +12:00
$utopia -> delete ( '/v1/users/:userId/sessions/:session' )
-> desc ( 'Delete User Session' )
-> label ( 'scope' , 'users.write' )
-> label ( 'sdk.namespace' , 'users' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.method' , 'deleteUserSession' )
-> label ( 'sdk.description' , '/docs/references/users/delete-user-session.md' )
2019-05-09 18:54:39 +12:00
-> label ( 'abuse-limit' , 100 )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
-> param ( 'sessionId' , null , function () { return new UID (); }, 'User unique session ID.' )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId , $sessionId ) use ( $response , $request , $projectDB ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
$tokens = $user -> getAttribute ( 'tokens' , []);
2019-09-07 05:10:41 +12:00
foreach ( $tokens as $token ) { /* @var $token Document */
if ( $sessionId == $token -> getUid ()) {
if ( ! $projectDB -> deleteDocument ( $token -> getUid ())) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'Failed to remove token from DB' , 500 );
}
}
}
$response -> json ( array ( 'result' => 'success' ));
}
);
$utopia -> delete ( '/v1/users/:userId/sessions' )
-> desc ( 'Delete User Sessions' )
-> label ( 'scope' , 'users.write' )
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'deleteUserSessions' )
2019-10-09 21:31:51 +13:00
-> label ( 'sdk.description' , '/docs/references/users/delete-user-sessions.md' )
2019-05-09 18:54:39 +12:00
-> label ( 'abuse-limit' , 100 )
2019-10-07 09:10:52 +13:00
-> param ( 'userId' , '' , function () { return new UID (); }, 'User unique ID.' )
2019-05-09 18:54:39 +12:00
-> action (
2019-09-07 05:10:41 +12:00
function ( $userId ) use ( $response , $request , $projectDB ) {
2019-05-09 18:54:39 +12:00
$user = $projectDB -> getDocument ( $userId );
2019-09-07 05:10:41 +12:00
if ( empty ( $user -> getUid ()) || Database :: SYSTEM_COLLECTION_USERS != $user -> getCollection ()) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'User not found' , 404 );
}
$tokens = $user -> getAttribute ( 'tokens' , []);
2019-09-07 05:10:41 +12:00
foreach ( $tokens as $token ) { /* @var $token Document */
if ( ! $projectDB -> deleteDocument ( $token -> getUid ())) {
2019-05-09 18:54:39 +12:00
throw new Exception ( 'Failed to remove token from DB' , 500 );
}
}
$response -> json ( array ( 'result' => 'success' ));
}
2019-09-07 05:10:41 +12:00
);