2019-05-09 18:54:39 +12:00
< ? php
2021-05-07 10:31:05 +12:00
use Appwrite\Auth\Auth ;
use Appwrite\Auth\Validator\Password ;
2022-06-09 00:50:31 +12:00
use Appwrite\Auth\Validator\Phone ;
2022-01-19 00:05:04 +13:00
use Appwrite\Detector\Detector ;
2022-05-26 01:36:25 +12:00
use Appwrite\Event\Delete ;
use Appwrite\Event\Event ;
2022-01-19 00:05:04 +13:00
use Appwrite\Network\Validator\Email ;
use Appwrite\Utopia\Database\Validator\CustomId ;
2022-08-19 12:09:34 +12:00
use Appwrite\Utopia\Database\Validator\Queries ;
2022-08-16 07:35:50 +12:00
use Appwrite\Utopia\Database\Validator\Queries\Users ;
2022-08-23 07:12:30 +12:00
use Appwrite\Utopia\Database\Validator\Query\Limit ;
use Appwrite\Utopia\Database\Validator\Query\Offset ;
2021-05-07 10:31:05 +12:00
use Appwrite\Utopia\Response ;
2020-06-29 05:31:21 +12:00
use Utopia\App ;
2019-12-29 22:47:55 +13:00
use Utopia\Audit\Audit ;
2022-01-19 00:05:04 +13:00
use Utopia\Config\Config ;
2022-12-15 04:42:25 +13:00
use Utopia\Database\Helpers\ID ;
2022-12-15 05:04:06 +13:00
use Utopia\Database\Helpers\Permission ;
use Utopia\Database\Helpers\Role ;
2022-05-26 01:36:25 +12:00
use Utopia\Locale\Locale ;
2022-02-09 05:56:03 +13:00
use Appwrite\Extend\Exception ;
2021-05-07 10:31:05 +12:00
use Utopia\Database\Document ;
2022-07-13 01:32:39 +12:00
use Utopia\Database\DateTime ;
2021-05-07 10:31:05 +12:00
use Utopia\Database\Exception\Duplicate ;
use Utopia\Database\Validator\UID ;
2021-08-20 21:57:46 +12:00
use Utopia\Database\Database ;
use Utopia\Database\Query ;
2021-08-29 04:25:48 +12:00
use Utopia\Database\Validator\Authorization ;
2022-01-19 00:05:04 +13:00
use Utopia\Validator\Assoc ;
use Utopia\Validator\WhiteList ;
use Utopia\Validator\Text ;
use Utopia\Validator\Boolean ;
2022-05-26 01:36:25 +12:00
use MaxMind\Db\Reader ;
2022-06-14 21:05:46 +12:00
use Utopia\Validator\Integer ;
2022-12-18 22:08:51 +13:00
use Appwrite\Auth\Validator\PasswordHistory ;
2022-12-26 23:22:49 +13:00
use Appwrite\Auth\Validator\PasswordDictionary ;
2019-05-09 18:54:39 +12:00
2022-08-13 04:01:25 +12:00
/** TODO: Remove function when we move to using utopia/platform */
2022-12-18 17:38:27 +13:00
function createUser ( string $hash , mixed $hashOptions , string $userId , ? string $email , ? string $password , ? string $phone , string $name , Document $project , Database $dbForProject , Event $events ) : Document
2022-06-14 23:08:54 +12:00
{
2022-06-14 03:11:31 +12:00
$hashOptionsObject = ( \is_string ( $hashOptions )) ? \json_decode ( $hashOptions , true ) : $hashOptions ; // Cast to JSON array
2022-12-18 17:38:27 +13:00
$passwordHistory = $project -> getAttribute ( 'auths' , [])[ 'passwordHistory' ] ? ? 0 ;
2022-08-17 01:02:28 +12:00
2022-08-17 01:03:38 +12:00
if ( ! empty ( $email )) {
2022-08-17 01:02:28 +12:00
$email = \strtolower ( $email );
}
2022-06-14 03:11:31 +12:00
try {
2022-08-19 16:49:34 +12:00
$userId = $userId == 'unique()'
? ID :: unique ()
: ID :: custom ( $userId );
2022-08-17 01:03:38 +12:00
2022-12-16 23:29:20 +13:00
$password = ( ! empty ( $password )) ? ( $hash === 'plaintext' ? Auth :: passwordHash ( $password , $hash , $hashOptionsObject ) : $password ) : null ;
2022-06-14 03:11:31 +12:00
$user = $dbForProject -> createDocument ( 'users' , new Document ([
'$id' => $userId ,
2022-08-19 16:49:34 +12:00
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: user ( $userId )),
Permission :: delete ( Role :: user ( $userId )),
],
2022-06-14 03:11:31 +12:00
'email' => $email ,
'emailVerification' => false ,
2022-08-17 01:02:28 +12:00
'phone' => $phone ,
'phoneVerification' => false ,
2022-06-14 03:11:31 +12:00
'status' => true ,
2022-12-16 23:29:20 +13:00
'password' => $password ,
2023-02-20 14:51:56 +13:00
'passwordHistory' => is_null ( $password ) && $passwordHistory === 0 ? [] : [ $password ],
'passwordUpdate' => ( ! empty ( $password )) ? DateTime :: now () : null ,
2022-06-14 03:11:31 +12:00
'hash' => $hash === 'plaintext' ? Auth :: DEFAULT_ALGO : $hash ,
2022-10-11 12:27:03 +13:00
'hashOptions' => $hash === 'plaintext' ? Auth :: DEFAULT_ALGO_OPTIONS : $hashOptionsObject + [ 'type' => $hash ],
2022-08-19 16:20:19 +12:00
'registration' => DateTime :: now (),
2022-06-14 03:11:31 +12:00
'reset' => false ,
'name' => $name ,
'prefs' => new \stdClass (),
'sessions' => null ,
'tokens' => null ,
'memberships' => null ,
2022-08-17 01:02:28 +12:00
'search' => implode ( ' ' , [ $userId , $email , $phone , $name ])
2022-06-14 03:11:31 +12:00
]));
} catch ( Duplicate $th ) {
2022-08-15 04:23:30 +12:00
throw new Exception ( Exception :: USER_ALREADY_EXISTS );
2022-06-14 03:11:31 +12:00
}
2022-08-17 19:05:37 +12:00
$events -> setParam ( 'userId' , $user -> getId ());
2022-06-14 03:11:31 +12:00
return $user ;
}
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: post ( '/v1/users' )
2020-02-05 19:31:34 +13:00
-> desc ( 'Create User' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].create' )
2020-02-05 19:31:34 +13:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-14 02:55:27 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2020-02-05 19:31:34 +13:00
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'create' )
-> label ( 'sdk.description' , '/docs/references/users/create-user.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-08-17 01:02:28 +12:00
-> param ( 'email' , null , new Email (), 'User email.' , true )
-> param ( 'phone' , null , new Phone (), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.' , true )
2023-02-20 20:08:27 +13:00
-> param ( 'password' , '' , fn ( $project , $passwordsDictionary ) => new PasswordDictionary ( $passwordsDictionary , $project -> getAttribute ( 'auths' , [])[ 'passwordDictionary' ] ? ? false ), 'Plain text user password. Must be at least 8 chars.' , true , [ 'project' , 'passwordsDictionary' ])
2020-09-11 02:40:14 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-12-26 23:22:49 +13:00
-> action ( function ( string $userId , ? string $email , ? string $phone , ? string $password , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
2022-12-26 18:24:26 +13:00
2022-12-18 17:38:27 +13:00
$user = createUser ( 'plaintext' , '{}' , $userId , $email , $password , $phone , $name , $project , $dbForProject , $events );
2022-04-04 18:30:07 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2020-12-27 05:54:42 +13:00
});
2020-02-05 19:31:34 +13:00
2022-08-13 03:55:58 +12:00
App :: post ( '/v1/users/bcrypt' )
2022-06-17 21:25:28 +12:00
-> desc ( 'Create User with Bcrypt Password' )
2022-06-14 21:05:46 +12:00
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'createBcryptUser' )
-> label ( 'sdk.description' , '/docs/references/users/create-bcrypt-user.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2020-09-11 02:40:14 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
2022-06-17 21:25:28 +12:00
-> param ( 'password' , '' , new Password (), 'User password hashed using Bcrypt.' )
2020-09-11 02:40:14 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
$user = createUser ( 'bcrypt' , '{}' , $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2020-02-05 19:31:34 +13:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2022-06-14 21:05:46 +12:00
});
2020-02-05 19:31:34 +13:00
2022-08-15 04:29:07 +12:00
App :: post ( '/v1/users/md5' )
2022-06-14 21:05:46 +12:00
-> desc ( 'Create User with MD5 Password' )
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'createMD5User' )
-> label ( 'sdk.description' , '/docs/references/users/create-md5-user.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-06-14 21:05:46 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
-> param ( 'password' , '' , new Password (), 'User password hashed using MD5.' )
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2022-06-14 21:05:46 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
$user = createUser ( 'md5' , '{}' , $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2022-06-14 21:05:46 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2022-06-14 21:05:46 +12:00
});
2022-08-15 04:29:07 +12:00
App :: post ( '/v1/users/argon2' )
2022-06-14 21:05:46 +12:00
-> desc ( 'Create User with Argon2 Password' )
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'createArgon2User' )
-> label ( 'sdk.description' , '/docs/references/users/create-argon2-user.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-06-14 21:05:46 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
-> param ( 'password' , '' , new Password (), 'User password hashed using Argon2.' )
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2022-06-14 21:05:46 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
$user = createUser ( 'argon2' , '{}' , $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2022-06-14 21:05:46 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2022-06-14 21:05:46 +12:00
});
2022-08-15 04:29:07 +12:00
App :: post ( '/v1/users/sha' )
2022-06-14 21:05:46 +12:00
-> desc ( 'Create User with SHA Password' )
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'createSHAUser' )
-> label ( 'sdk.description' , '/docs/references/users/create-sha-user.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-06-14 21:05:46 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
-> param ( 'password' , '' , new Password (), 'User password hashed using SHA.' )
2022-06-14 22:40:51 +12:00
-> param ( 'passwordVersion' , '' , new WhiteList ([ 'sha1' , 'sha224' , 'sha256' , 'sha384' , 'sha512/224' , 'sha512/256' , 'sha512' , 'sha3-224' , 'sha3-256' , 'sha3-384' , 'sha3-512' ]), " Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512' " , true )
2022-06-14 21:05:46 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2022-06-14 21:05:46 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $passwordVersion , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
2022-06-14 21:05:46 +12:00
$options = '{}' ;
2022-06-14 23:08:54 +12:00
if ( ! empty ( $passwordVersion )) {
2022-06-14 22:40:51 +12:00
$options = '{"version":"' . $passwordVersion . '"}' ;
2020-06-30 23:09:28 +12:00
}
2020-02-05 19:31:34 +13:00
2022-12-18 17:38:27 +13:00
$user = createUser ( 'sha' , $options , $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2021-08-16 19:56:18 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2022-06-14 21:05:46 +12:00
});
2022-08-15 04:29:07 +12:00
App :: post ( '/v1/users/phpass' )
2022-06-14 21:05:46 +12:00
-> desc ( 'Create User with PHPass Password' )
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'createPHPassUser' )
-> label ( 'sdk.description' , '/docs/references/users/create-phpass-user.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or pass the string `ID.unique()`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-06-14 21:05:46 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
-> param ( 'password' , '' , new Password (), 'User password hashed using PHPass.' )
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2022-06-14 21:05:46 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
$user = createUser ( 'phpass' , '{}' , $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2022-06-14 21:05:46 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2022-06-14 21:05:46 +12:00
});
2022-08-15 04:29:07 +12:00
App :: post ( '/v1/users/scrypt' )
2022-06-17 21:25:28 +12:00
-> desc ( 'Create User with Scrypt Password' )
2022-06-14 21:05:46 +12:00
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
2022-06-17 21:25:28 +12:00
-> label ( 'sdk.method' , 'createScryptUser' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.description' , '/docs/references/users/create-scrypt-user.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-06-14 21:05:46 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
2022-06-17 21:25:28 +12:00
-> param ( 'password' , '' , new Password (), 'User password hashed using Scrypt.' )
2022-06-25 00:30:39 +12:00
-> param ( 'passwordSalt' , '' , new Text ( 128 ), 'Optional salt used to hash password.' )
2022-09-29 16:52:57 +13:00
-> param ( 'passwordCpu' , 8 , new Integer (), 'Optional CPU cost used to hash password.' )
-> param ( 'passwordMemory' , 14 , new Integer (), 'Optional memory cost used to hash password.' )
-> param ( 'passwordParallel' , 1 , new Integer (), 'Optional parallelization cost used to hash password.' )
-> param ( 'passwordLength' , 64 , new Integer (), 'Optional hash length used to hash password.' )
2022-06-14 21:05:46 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2022-06-14 21:05:46 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $passwordSalt , int $passwordCpu , int $passwordMemory , int $passwordParallel , int $passwordLength , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
2022-06-25 00:30:39 +12:00
$options = [
'salt' => $passwordSalt ,
'costCpu' => $passwordCpu ,
'costMemory' => $passwordMemory ,
'costParallel' => $passwordParallel ,
'length' => $passwordLength
];
2022-06-14 23:08:54 +12:00
2022-12-18 17:38:27 +13:00
$user = createUser ( 'scrypt' , \json_encode ( $options ), $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2022-06-14 21:05:46 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2022-06-14 21:05:46 +12:00
});
2022-08-15 04:29:07 +12:00
App :: post ( '/v1/users/scrypt-modified' )
2022-06-17 21:25:28 +12:00
-> desc ( 'Create User with Scrypt Modified Password' )
2022-06-14 21:05:46 +12:00
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].create' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.create' )
2022-08-17 22:01:16 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.create' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
2022-06-17 21:25:28 +12:00
-> label ( 'sdk.method' , 'createScryptModifiedUser' )
2022-06-14 22:40:51 +12:00
-> label ( 'sdk.description' , '/docs/references/users/create-scrypt-modified-user.md' )
2022-06-14 21:05:46 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2023-01-21 11:22:16 +13:00
-> param ( 'userId' , '' , new CustomId (), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-06-14 21:05:46 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
2022-06-17 21:25:28 +12:00
-> param ( 'password' , '' , new Password (), 'User password hashed using Scrypt Modified.' )
2022-06-14 21:05:46 +12:00
-> param ( 'passwordSalt' , '' , new Text ( 128 ), 'Salt used to hash password.' )
-> param ( 'passwordSaltSeparator' , '' , new Text ( 128 ), 'Salt separator used to hash password.' )
-> param ( 'passwordSignerKey' , '' , new Text ( 128 ), 'Signer key used to hash password.' )
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' , true )
-> inject ( 'response' )
2022-12-18 17:38:27 +13:00
-> inject ( 'project' )
2022-06-14 21:05:46 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-12-18 17:38:27 +13:00
-> action ( function ( string $userId , string $email , string $password , string $passwordSalt , string $passwordSaltSeparator , string $passwordSignerKey , string $name , Response $response , Document $project , Database $dbForProject , Event $events ) {
$user = createUser ( 'scryptMod' , '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}' , $userId , $email , $password , null , $name , $project , $dbForProject , $events );
2022-04-04 18:30:07 +12:00
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $user , Response :: MODEL_USER );
2020-12-27 05:54:42 +13:00
});
2020-02-05 19:31:34 +13:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/users' )
2019-05-09 18:54:39 +12:00
-> desc ( 'List Users' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.read' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.read' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'list' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/list-users.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER_LIST )
2022-08-16 07:35:50 +12:00
-> param ( 'queries' , [], new Users (), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode ( ', ' , Users :: ALLOWED_ATTRIBUTES ), true )
2020-09-11 02:40:14 +12:00
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-25 22:28:13 +12:00
-> action ( function ( array $queries , string $search , Response $response , Database $dbForProject ) {
2021-05-07 10:31:05 +12:00
2022-08-16 07:35:50 +12:00
$queries = Query :: parseQueries ( $queries );
2021-08-07 00:36:48 +12:00
2022-08-12 11:53:52 +12:00
if ( ! empty ( $search )) {
2022-08-16 07:35:50 +12:00
$queries [] = Query :: search ( 'search' , $search );
2021-08-07 00:36:48 +12:00
}
2022-08-16 07:35:50 +12:00
// Get cursor document if there was a cursor query
2022-08-31 11:31:43 +12:00
$cursor = Query :: getByType ( $queries , Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE );
$cursor = reset ( $cursor );
2022-08-30 23:55:23 +12:00
if ( $cursor ) {
2022-08-16 07:35:50 +12:00
/** @var Query $cursor */
$userId = $cursor -> getValue ();
$cursorDocument = $dbForProject -> getDocument ( 'users' , $userId );
2021-08-15 06:56:28 +12:00
2022-08-12 11:53:52 +12:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-16 07:35:50 +12:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " User ' { $userId } ' for the 'cursor' value not found. " );
2022-08-12 11:53:52 +12:00
}
2022-08-16 07:35:50 +12:00
$cursor -> setValue ( $cursorDocument );
2021-08-15 06:56:28 +12:00
}
2022-08-16 07:35:50 +12:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ([
2022-08-16 07:35:50 +12:00
'users' => $dbForProject -> find ( 'users' , $queries ),
2022-08-12 11:53:52 +12:00
'total' => $dbForProject -> count ( 'users' , $filterQueries , APP_LIMIT_COUNT ),
2020-10-31 08:53:27 +13:00
]), Response :: MODEL_USER_LIST );
2020-12-27 05:54:42 +13:00
});
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/users/:userId' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Get User' )
2020-06-29 00:18:16 +12:00
-> groups ([ 'api' , 'users' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.read' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.read' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2020-06-29 00:18:16 +12:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'get' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/get-user.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-17 14:35:55 +12:00
-> action ( function ( string $userId , Response $response , Database $dbForProject ) {
2022-08-16 05:33:44 +12:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
if ( $user -> isEmpty ()) {
2022-10-15 05:17:00 +13:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2022-08-16 05:33:44 +12:00
}
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
2022-08-16 05:33:44 +12:00
});
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/users/:userId/prefs' )
2020-01-23 19:27:19 +13:00
-> desc ( 'Get User Preferences' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.read' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.read' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'getPrefs' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/get-user-prefs.md' )
2020-11-13 00:54:16 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-22 01:37:51 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_PREFERENCES )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , Response $response , Database $dbForProject ) {
2019-05-09 18:54:39 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2019-05-09 18:54:39 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2021-01-11 00:55:59 +13:00
$prefs = $user -> getAttribute ( 'prefs' , new \stdClass ());
2019-05-09 18:54:39 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ( $prefs ), Response :: MODEL_PREFERENCES );
2020-12-27 05:54:42 +13:00
});
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/users/:userId/sessions' )
2022-09-14 10:13:04 +12:00
-> desc ( 'List User Sessions' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.read' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.read' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2022-09-14 10:13:04 +12:00
-> label ( 'sdk.method' , 'listSessions' )
-> label ( 'sdk.description' , '/docs/references/users/list-user-sessions.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_SESSION_LIST )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2020-12-27 05:54:42 +13:00
-> inject ( 'locale' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , Response $response , Database $dbForProject , Locale $locale ) {
2019-05-09 18:54:39 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2020-06-30 23:09:28 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2021-02-20 01:12:47 +13:00
$sessions = $user -> getAttribute ( 'sessions' , []);
2020-06-30 23:09:28 +12:00
2022-05-24 02:54:50 +12:00
foreach ( $sessions as $key => $session ) {
2021-02-20 01:12:47 +13:00
/** @var Document $session */
2019-05-09 18:54:39 +12:00
2022-05-24 02:54:50 +12:00
$countryName = $locale -> getText ( 'countries.' . strtolower ( $session -> getAttribute ( 'countryCode' )), $locale -> getText ( 'locale.country.unknown' ));
2021-07-23 08:15:01 +12:00
$session -> setAttribute ( 'countryName' , $countryName );
2021-02-20 01:12:47 +13:00
$session -> setAttribute ( 'current' , false );
2019-05-09 18:54:39 +12:00
2021-02-20 01:12:47 +13:00
$sessions [ $key ] = $session ;
2019-05-09 18:54:39 +12:00
}
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ([
2021-05-27 22:09:14 +12:00
'sessions' => $sessions ,
2022-02-27 22:57:09 +13:00
'total' => count ( $sessions ),
2020-10-31 08:53:27 +13:00
]), Response :: MODEL_SESSION_LIST );
2021-12-28 01:45:23 +13:00
});
2019-05-09 18:54:39 +12:00
2022-05-13 01:20:06 +12:00
App :: get ( '/v1/users/:userId/memberships' )
2022-09-14 08:58:28 +12:00
-> desc ( 'List User Memberships' )
2022-05-13 01:20:06 +12:00
-> groups ([ 'api' , 'users' ])
-> label ( 'scope' , 'users.read' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.read' )
2022-05-13 01:20:06 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
2022-09-14 08:58:28 +12:00
-> label ( 'sdk.method' , 'listMemberships' )
-> label ( 'sdk.description' , '/docs/references/users/list-user-memberships.md' )
2022-05-13 01:20:06 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_MEMBERSHIP_LIST )
-> param ( 'userId' , '' , new UID (), 'User ID.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2022-05-26 01:36:25 +12:00
-> action ( function ( string $userId , Response $response , Database $dbForProject ) {
2022-05-13 01:20:06 +12:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2022-05-13 01:20:06 +12:00
}
2022-05-24 02:54:50 +12:00
$memberships = array_map ( function ( $membership ) use ( $dbForProject , $user ) {
2022-05-13 01:20:06 +12:00
$team = $dbForProject -> getDocument ( 'teams' , $membership -> getAttribute ( 'teamId' ));
$membership
-> setAttribute ( 'teamName' , $team -> getAttribute ( 'name' ))
-> setAttribute ( 'userName' , $user -> getAttribute ( 'name' ))
2022-05-13 02:26:12 +12:00
-> setAttribute ( 'userEmail' , $user -> getAttribute ( 'email' ));
2022-05-13 01:20:06 +12:00
return $membership ;
}, $user -> getAttribute ( 'memberships' , []));
$response -> dynamic ( new Document ([
'memberships' => $memberships ,
'total' => count ( $memberships ),
]), Response :: MODEL_MEMBERSHIP_LIST );
});
2020-06-29 05:31:21 +12:00
App :: get ( '/v1/users/:userId/logs' )
2022-09-14 09:05:03 +12:00
-> desc ( 'List User Logs' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.read' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.read' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2022-09-14 09:05:03 +12:00
-> label ( 'sdk.method' , 'listLogs' )
-> label ( 'sdk.description' , '/docs/references/users/list-user-logs.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_LOG_LIST )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2022-08-23 07:12:30 +12:00
-> param ( 'queries' , [], new Queries ( new Limit (), new Offset ()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset' , true )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2020-12-27 05:54:42 +13:00
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-25 22:28:13 +12:00
-> action ( function ( string $userId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2020-06-30 23:09:28 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2020-06-30 23:09:28 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2022-08-19 12:09:34 +12:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 23:55:23 +12:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-19 12:09:34 +12:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2021-12-28 01:45:23 +13:00
$audit = new Audit ( $dbForProject );
2021-11-17 03:54:29 +13:00
2022-04-21 02:03:40 +12:00
$logs = $audit -> getLogsByUser ( $user -> getId (), $limit , $offset );
2020-06-30 23:09:28 +12:00
$output = [];
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
2021-12-13 06:55:38 +13:00
$detector = new Detector ( $log [ 'userAgent' ]);
$detector -> skipBotDetection (); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
2020-06-30 23:09:28 +12:00
2021-12-13 06:55:38 +13:00
$os = $detector -> getOS ();
$client = $detector -> getClient ();
$device = $detector -> getDevice ();
2020-10-31 08:53:27 +13:00
$output [ $i ] = new Document ([
2020-06-30 23:09:28 +12:00
'event' => $log [ 'event' ],
'ip' => $log [ 'ip' ],
2021-06-13 06:39:59 +12:00
'time' => $log [ 'time' ],
2021-12-13 06:55:38 +13:00
'osCode' => $os [ 'osCode' ],
'osName' => $os [ 'osName' ],
'osVersion' => $os [ 'osVersion' ],
'clientType' => $client [ 'clientType' ],
'clientCode' => $client [ 'clientCode' ],
'clientName' => $client [ 'clientName' ],
'clientVersion' => $client [ 'clientVersion' ],
'clientEngine' => $client [ 'clientEngine' ],
'clientEngineVersion' => $client [ 'clientEngineVersion' ],
'deviceName' => $device [ 'deviceName' ],
'deviceBrand' => $device [ 'deviceBrand' ],
2021-12-13 06:59:12 +13:00
'deviceModel' => $device [ 'deviceModel' ]
2020-10-31 08:53:27 +13:00
]);
$record = $geodb -> get ( $log [ 'ip' ]);
if ( $record ) {
2022-05-24 02:54:50 +12:00
$output [ $i ][ 'countryCode' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), false ) ? \strtolower ( $record [ 'country' ][ 'iso_code' ]) : '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), $locale -> getText ( 'locale.country.unknown' ));
2020-10-31 08:53:27 +13:00
} else {
$output [ $i ][ 'countryCode' ] = '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'locale.country.unknown' );
2019-05-09 18:54:39 +12:00
}
}
2021-11-17 03:54:29 +13:00
$response -> dynamic ( new Document ([
2022-04-21 02:03:40 +12:00
'total' => $audit -> countLogsByUser ( $user -> getId ()),
2021-11-17 03:54:29 +13:00
'logs' => $output ,
]), Response :: MODEL_LOG_LIST );
2020-12-27 05:54:42 +13:00
});
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: patch ( '/v1/users/:userId/status' )
2019-10-10 16:52:59 +13:00
-> desc ( 'Update User Status' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].update.status' )
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.update' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-16 21:00:28 +12:00
-> label ( 'audits.userId' , '{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'updateStatus' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/update-user-status.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
-> param ( 'status' , null , new Boolean ( true ), 'User Status. To activate the user pass `true` and to block the user pass `false`.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , bool $status , Response $response , Database $dbForProject , Event $events ) {
2019-05-09 18:54:39 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2019-05-09 18:54:39 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user -> setAttribute ( 'status' , ( bool ) $status ));
2019-10-21 19:01:07 +13:00
2022-04-04 18:30:07 +12:00
$events
2022-08-25 20:38:43 +12:00
-> setParam ( 'userId' , $user -> getId ());
2022-04-04 18:30:07 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
2020-12-27 05:54:42 +13:00
});
2019-05-09 18:54:39 +12:00
2021-05-30 19:03:51 +12:00
App :: patch ( '/v1/users/:userId/verification' )
-> desc ( 'Update Email Verification' )
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].update.verification' )
2021-05-30 19:03:51 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'verification.update' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-05-30 19:03:51 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
2022-06-15 03:41:58 +12:00
-> label ( 'sdk.method' , 'updateEmailVerification' )
2022-06-21 02:47:49 +12:00
-> label ( 'sdk.description' , '/docs/references/users/update-user-email-verification.md' )
2021-05-30 19:03:51 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
-> param ( 'emailVerification' , false , new Boolean (), 'User email verification status.' )
2021-05-30 19:03:51 +12:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , bool $emailVerification , Response $response , Database $dbForProject , Event $events ) {
2021-05-30 19:03:51 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2021-05-30 19:03:51 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2021-05-30 19:03:51 +12:00
}
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user -> setAttribute ( 'emailVerification' , $emailVerification ));
2019-05-09 18:54:39 +12:00
2022-04-04 18:30:07 +12:00
$events
2022-08-25 20:38:43 +12:00
-> setParam ( 'userId' , $user -> getId ());
2022-04-04 18:30:07 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
2020-12-27 05:54:42 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-10 07:11:49 +12:00
App :: patch ( '/v1/users/:userId/verification/phone' )
2022-06-09 00:50:31 +12:00
-> desc ( 'Update Phone Verification' )
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].update.verification' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'verification.update' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2022-06-09 00:50:31 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updatePhoneVerification' )
-> label ( 'sdk.description' , '/docs/references/users/update-user-phone-verification.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
-> param ( 'userId' , '' , new UID (), 'User ID.' )
-> param ( 'phoneVerification' , false , new Boolean (), 'User phone verification status.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , bool $phoneVerification , Response $response , Database $dbForProject , Event $events ) {
2022-06-09 00:50:31 +12:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2022-06-09 00:50:31 +12:00
}
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user -> setAttribute ( 'phoneVerification' , $phoneVerification ));
$events
2022-08-25 20:38:43 +12:00
-> setParam ( 'userId' , $user -> getId ());
2022-06-09 00:50:31 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
});
2021-08-29 23:13:58 +12:00
App :: patch ( '/v1/users/:userId/name' )
-> desc ( 'Update Name' )
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].update.name' )
2021-08-29 23:13:58 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.update' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-16 21:00:28 +12:00
-> label ( 'audits.userId' , '{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-08-29 23:13:58 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updateName' )
-> label ( 'sdk.description' , '/docs/references/users/update-user-name.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2021-08-29 23:13:58 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'User name. Max length: 128 chars.' )
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-08-09 02:32:54 +12:00
-> action ( function ( string $userId , string $name , Response $response , Database $dbForProject , Event $events ) {
2021-10-08 21:39:37 +13:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2021-08-29 23:13:58 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2021-08-29 23:13:58 +12:00
}
2022-04-26 22:07:33 +12:00
$user
-> setAttribute ( 'name' , $name )
2022-08-25 21:34:36 +12:00
-> setAttribute ( 'search' , \implode ( ' ' , [ $user -> getId (), $user -> getAttribute ( 'email' , '' ), $name , $user -> getAttribute ( 'phone' , '' )]));
;
2022-04-26 22:07:33 +12:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user );
2021-08-29 23:13:58 +12:00
2022-08-09 02:32:54 +12:00
$events -> setParam ( 'userId' , $user -> getId ());
2021-08-29 23:13:58 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
});
App :: patch ( '/v1/users/:userId/password' )
-> desc ( 'Update Password' )
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].update.password' )
2021-08-29 23:13:58 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.update' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-16 21:00:28 +12:00
-> label ( 'audits.userId' , '{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-08-29 23:13:58 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updatePassword' )
-> label ( 'sdk.description' , '/docs/references/users/update-user-password.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2023-02-20 20:08:27 +13:00
-> param ( 'password' , '' , fn ( $project , $passwordsDictionary ) => new PasswordDictionary ( $passwordsDictionary , $project -> getAttribute ( 'auths' , [])[ 'passwordDictionary' ] ? ? false ), 'New user password. Must be at least 8 chars.' , false , [ 'project' , 'passwordsDictionary' ])
2021-08-29 23:13:58 +12:00
-> inject ( 'response' )
2022-12-16 23:47:08 +13:00
-> inject ( 'project' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-12-26 23:22:49 +13:00
-> action ( function ( string $userId , string $password , Response $response , Document $project , Database $dbForProject , Event $events ) {
2021-08-29 23:13:58 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2021-08-29 23:13:58 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2021-08-29 23:13:58 +12:00
}
2022-12-26 18:52:49 +13:00
$newPassword = Auth :: passwordHash ( $password , Auth :: DEFAULT_ALGO , Auth :: DEFAULT_ALGO_OPTIONS );
2022-12-16 23:47:08 +13:00
$historyLimit = $project -> getAttribute ( 'auths' , [])[ 'passwordHistory' ] ? ? 0 ;
$history = [];
2022-12-18 19:31:14 +13:00
if ( $historyLimit > 0 ) {
2022-12-16 23:47:08 +13:00
$history = $user -> getAttribute ( 'passwordHistory' , []);
2022-12-18 22:08:51 +13:00
$validator = new PasswordHistory ( $history , $user -> getAttribute ( 'hash' ), $user -> getAttribute ( 'hashOptions' ));
if ( ! $validator -> isValid ( $password )) {
throw new Exception ( Exception :: USER_PASSWORD_RECENTLY_USED , 'The password was recently used' , 409 );
2022-12-16 23:47:08 +13:00
}
2022-12-18 19:28:19 +13:00
2022-12-16 23:47:08 +13:00
$history [] = $newPassword ;
2022-12-19 18:07:41 +13:00
array_slice ( $history , ( count ( $history ) - $historyLimit ), $historyLimit );
2022-12-16 23:22:39 +13:00
}
2021-10-08 21:39:37 +13:00
$user
2022-12-16 23:29:20 +13:00
-> setAttribute ( 'password' , $newPassword )
2023-02-20 14:51:56 +13:00
-> setAttribute ( 'passwordHistory' , $history )
-> setAttribute ( 'passwordUpdate' , DateTime :: now ())
2022-06-14 00:53:28 +12:00
-> setAttribute ( 'hash' , Auth :: DEFAULT_ALGO )
2023-02-20 14:51:56 +13:00
-> setAttribute ( 'hashOptions' , Auth :: DEFAULT_ALGO_OPTIONS );
2021-10-08 21:39:37 +13:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user );
2021-08-29 23:13:58 +12:00
2022-08-09 02:32:54 +12:00
$events -> setParam ( 'userId' , $user -> getId ());
2021-08-29 23:13:58 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
});
App :: patch ( '/v1/users/:userId/email' )
-> desc ( 'Update Email' )
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].update.email' )
2021-08-29 23:13:58 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.update' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-16 21:00:28 +12:00
-> label ( 'audits.userId' , '{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-08-29 23:13:58 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updateEmail' )
-> label ( 'sdk.description' , '/docs/references/users/update-user-email.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2021-08-29 23:13:58 +12:00
-> param ( 'email' , '' , new Email (), 'User email.' )
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-08-09 02:32:54 +12:00
-> action ( function ( string $userId , string $email , Response $response , Database $dbForProject , Event $events ) {
2021-08-29 23:13:58 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2021-08-29 23:13:58 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2021-08-29 23:13:58 +12:00
}
2021-10-08 06:57:23 +13:00
$email = \strtolower ( $email );
2022-04-26 22:07:33 +12:00
$user
-> setAttribute ( 'email' , $email )
2022-06-09 00:50:31 +12:00
-> setAttribute ( 'emailVerification' , false )
2022-08-25 20:38:43 +12:00
-> setAttribute ( 'search' , \implode ( ' ' , [ $user -> getId (), $email , $user -> getAttribute ( 'name' , '' ), $user -> getAttribute ( 'phone' , '' )]));
2022-04-26 22:07:33 +12:00
2021-08-30 00:00:25 +12:00
try {
2022-04-26 22:07:33 +12:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user );
2022-05-24 02:54:50 +12:00
} catch ( Duplicate $th ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_EMAIL_ALREADY_EXISTS );
2021-08-29 23:13:58 +12:00
}
2022-08-16 03:19:59 +12:00
$events -> setParam ( 'userId' , $user -> getId ());
2022-06-09 00:50:31 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
});
2022-06-14 00:43:17 +12:00
App :: patch ( '/v1/users/:userId/phone' )
2022-06-09 00:50:31 +12:00
-> desc ( 'Update Phone' )
-> groups ([ 'api' , 'users' ])
-> label ( 'event' , 'users.[userId].update.phone' )
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.update' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'user/{response.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2022-06-09 00:50:31 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'updatePhone' )
-> label ( 'sdk.description' , '/docs/references/users/update-user-phone.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
-> param ( 'userId' , '' , new UID (), 'User ID.' )
-> param ( 'number' , '' , new Phone (), 'User phone number.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-08-09 02:32:54 +12:00
-> action ( function ( string $userId , string $number , Response $response , Database $dbForProject , Event $events ) {
2022-06-09 00:50:31 +12:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2022-06-09 00:50:31 +12:00
}
$user
-> setAttribute ( 'phone' , $number )
-> setAttribute ( 'phoneVerification' , false )
2022-08-25 21:34:36 +12:00
-> setAttribute ( 'search' , implode ( ' ' , [ $user -> getId (), $user -> getAttribute ( 'name' , '' ), $user -> getAttribute ( 'email' , '' ), $number ]));
;
2022-06-09 00:50:31 +12:00
try {
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user );
} catch ( Duplicate $th ) {
2022-10-05 07:18:15 +13:00
throw new Exception ( Exception :: USER_PHONE_ALREADY_EXISTS );
2022-06-09 00:50:31 +12:00
}
2022-08-09 02:32:54 +12:00
$events -> setParam ( 'userId' , $user -> getId ());
2022-06-09 00:50:31 +12:00
2021-08-29 23:13:58 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
});
2022-04-04 18:30:07 +12:00
2022-08-13 02:10:41 +12:00
App :: patch ( '/v1/users/:userId/verification' )
-> desc ( 'Update Email Verification' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2022-08-13 02:10:41 +12:00
-> label ( 'event' , 'users.[userId].update.verification' )
2019-10-05 10:04:49 +13:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'verification.update' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{request.userId}' )
2022-08-16 21:00:28 +12:00
-> label ( 'audits.userId' , '{request.userId}' )
2022-08-17 21:34:40 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-10-05 10:04:49 +13:00
-> label ( 'sdk.namespace' , 'users' )
2022-08-13 02:10:41 +12:00
-> label ( 'sdk.method' , 'updateEmailVerification' )
-> label ( 'sdk.description' , '/docs/references/users/update-user-email-verification.md' )
2020-11-13 00:54:16 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2022-06-09 00:50:31 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_USER )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2022-08-13 02:10:41 +12:00
-> param ( 'emailVerification' , false , new Boolean (), 'User email verification status.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-08-17 21:34:40 +12:00
-> action ( function ( string $userId , bool $emailVerification , Response $response , Database $dbForProject , Event $events ) {
2019-10-05 10:04:49 +13:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2019-10-05 10:04:49 +13:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2020-01-20 09:38:00 +13:00
2022-08-13 02:10:41 +12:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user -> setAttribute ( 'emailVerification' , $emailVerification ));
2019-10-21 19:01:07 +13:00
2022-08-12 01:19:05 +12:00
$events -> setParam ( 'userId' , $user -> getId ());
2021-08-29 23:13:58 +12:00
$response -> dynamic ( $user , Response :: MODEL_USER );
});
2020-06-29 05:31:21 +12:00
App :: patch ( '/v1/users/:userId/prefs' )
2020-01-23 19:27:19 +13:00
-> desc ( 'Update User Preferences' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].update.prefs' )
2019-10-05 10:04:49 +13:00
-> label ( 'scope' , 'users.write' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.update' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-10-05 10:04:49 +13:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'updatePrefs' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/update-user-prefs.md' )
2020-11-13 00:54:16 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-22 01:37:51 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_PREFERENCES )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2020-09-11 02:40:14 +12:00
-> param ( 'prefs' , '' , new Assoc (), 'Prefs key-value JSON object.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-04-04 18:30:07 +12:00
-> inject ( 'events' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , array $prefs , Response $response , Database $dbForProject , Event $events ) {
2019-10-05 10:04:49 +13:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2019-10-05 10:04:49 +13:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2020-01-20 09:38:00 +13:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> updateDocument ( 'users' , $user -> getId (), $user -> setAttribute ( 'prefs' , $prefs ));
2019-10-21 19:01:07 +13:00
2022-04-04 18:30:07 +12:00
$events
2022-08-25 20:38:43 +12:00
-> setParam ( 'userId' , $user -> getId ());
2022-04-04 18:30:07 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ( $prefs ), Response :: MODEL_PREFERENCES );
2020-12-27 05:54:42 +13:00
});
2019-10-05 10:04:49 +13:00
2020-06-29 05:31:21 +12:00
App :: delete ( '/v1/users/:userId/sessions/:sessionId' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Delete User Session' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].sessions.[sessionId].delete' )
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'session.delete' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{request.userId}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'sessions.{scope}.requests.delete' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'deleteSession' )
2019-10-08 20:09:35 +13:00
-> label ( 'sdk.description' , '/docs/references/users/delete-user-session.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2022-09-19 22:05:42 +12:00
-> param ( 'sessionId' , '' , new UID (), 'Session ID.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2020-12-27 05:54:42 +13:00
-> inject ( 'events' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , string $sessionId , Response $response , Database $dbForProject , Event $events ) {
2019-05-09 18:54:39 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2019-05-09 18:54:39 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2022-04-04 21:59:32 +12:00
$session = $dbForProject -> getDocument ( 'sessions' , $sessionId );
2021-02-20 02:59:36 +13:00
2022-05-24 02:54:50 +12:00
if ( $session -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_SESSION_NOT_FOUND );
2019-05-09 18:54:39 +12:00
}
2022-04-04 21:59:32 +12:00
$dbForProject -> deleteDocument ( 'sessions' , $session -> getId ());
2022-04-26 22:36:49 +12:00
$dbForProject -> deleteCachedDocument ( 'users' , $user -> getId ());
2022-04-04 18:30:07 +12:00
$events
-> setParam ( 'userId' , $user -> getId ())
2022-10-28 06:32:49 +13:00
-> setParam ( 'sessionId' , $sessionId )
-> setPayload ( $response -> output ( $session , Response :: MODEL_SESSION ));
2022-04-04 18:30:07 +12:00
2020-10-31 08:53:27 +13:00
$response -> noContent ();
2020-12-27 05:54:42 +13:00
});
2019-05-09 18:54:39 +12:00
2020-06-29 05:31:21 +12:00
App :: delete ( '/v1/users/:userId/sessions' )
2019-05-09 18:54:39 +12:00
-> desc ( 'Delete User Sessions' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].sessions.[sessionId].delete' )
2019-05-09 18:54:39 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'session.delete' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{user.$id}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'sessions.{scope}.requests.delete' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.namespace' , 'users' )
2020-01-31 05:18:46 +13:00
-> label ( 'sdk.method' , 'deleteSessions' )
2019-10-09 21:31:51 +13:00
-> label ( 'sdk.description' , '/docs/references/users/delete-user-sessions.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2021-12-11 01:27:11 +13:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2020-12-27 05:54:42 +13:00
-> inject ( 'events' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , Response $response , Database $dbForProject , Event $events ) {
2019-05-09 18:54:39 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2019-05-09 18:54:39 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-06-30 23:09:28 +12:00
}
2019-05-09 18:54:39 +12:00
2021-07-17 22:04:43 +12:00
$sessions = $user -> getAttribute ( 'sessions' , []);
2022-08-25 20:38:43 +12:00
foreach ( $sessions as $key => $session ) {
/** @var Document $session */
2021-12-28 01:45:23 +13:00
$dbForProject -> deleteDocument ( 'sessions' , $session -> getId ());
2022-05-11 00:13:53 +12:00
//TODO: fix this
2021-07-17 22:04:43 +12:00
}
2022-04-04 21:59:32 +12:00
$dbForProject -> deleteCachedDocument ( 'users' , $user -> getId ());
2019-05-09 18:54:39 +12:00
2020-12-07 11:14:57 +13:00
$events
2022-04-04 18:30:07 +12:00
-> setParam ( 'userId' , $user -> getId ())
2022-08-25 20:38:43 +12:00
-> setPayload ( $response -> output ( $user , Response :: MODEL_USER ));
2022-04-04 18:30:07 +12:00
2020-10-31 08:53:27 +13:00
$response -> noContent ();
2020-12-27 05:54:42 +13:00
});
2020-08-30 08:40:40 +12:00
App :: delete ( '/v1/users/:userId' )
-> desc ( 'Delete User' )
-> groups ([ 'api' , 'users' ])
2022-04-04 18:30:07 +12:00
-> label ( 'event' , 'users.[userId].delete' )
2020-08-30 08:40:40 +12:00
-> label ( 'scope' , 'users.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'user.delete' )
2022-08-13 21:59:34 +12:00
-> label ( 'audits.resource' , 'user/{request.userId}' )
2022-08-11 13:43:02 +12:00
-> label ( 'usage.metric' , 'users.{scope}.requests.delete' )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2020-08-30 08:40:40 +12:00
-> label ( 'sdk.namespace' , 'users' )
2021-04-13 23:01:33 +12:00
-> label ( 'sdk.method' , 'delete' )
-> label ( 'sdk.description' , '/docs/references/users/delete.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-01 02:24:01 +12:00
-> param ( 'userId' , '' , new UID (), 'User ID.' )
2020-12-27 05:54:42 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2020-12-27 05:54:42 +13:00
-> inject ( 'events' )
-> inject ( 'deletes' )
2022-08-11 13:43:02 +12:00
-> action ( function ( string $userId , Response $response , Database $dbForProject , Event $events , Delete $deletes ) {
2022-04-04 18:30:07 +12:00
2021-12-28 01:45:23 +13:00
$user = $dbForProject -> getDocument ( 'users' , $userId );
2020-08-30 08:40:40 +12:00
2022-05-16 21:58:17 +12:00
if ( $user -> isEmpty ()) {
2022-08-16 18:59:03 +12:00
throw new Exception ( Exception :: USER_NOT_FOUND );
2020-08-30 08:40:40 +12:00
}
2021-10-06 03:29:43 +13:00
// clone user object to send to workers
$clone = clone $user ;
2022-05-16 21:58:17 +12:00
$dbForProject -> deleteDocument ( 'users' , $userId );
2020-08-30 08:40:40 +12:00
2020-10-31 08:53:27 +13:00
$deletes
2022-04-18 08:34:32 +12:00
-> setType ( DELETE_TYPE_DOCUMENT )
2022-08-25 20:38:43 +12:00
-> setDocument ( $clone );
2020-10-31 08:53:27 +13:00
2020-12-07 11:14:57 +13:00
$events
2022-04-04 18:30:07 +12:00
-> setParam ( 'userId' , $user -> getId ())
2022-08-25 20:38:43 +12:00
-> setPayload ( $response -> output ( $clone , Response :: MODEL_USER ));
2021-10-06 03:29:43 +13:00
2020-08-30 08:40:40 +12:00
$response -> noContent ();
2020-12-27 05:54:42 +13:00
});
2021-08-20 21:57:46 +12:00
App :: get ( '/v1/users/usage' )
2021-08-21 00:10:52 +12:00
-> desc ( 'Get usage stats for the users API' )
2021-08-20 21:57:46 +12:00
-> groups ([ 'api' , 'users' ])
-> label ( 'scope' , 'users.read' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
-> label ( 'sdk.namespace' , 'users' )
-> label ( 'sdk.method' , 'getUsage' )
2021-08-27 06:53:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-08-28 05:34:43 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_USAGE_USERS )
2021-08-20 21:57:46 +12:00
-> param ( 'range' , '30d' , new WhiteList ([ '24h' , '7d' , '30d' , '90d' ], true ), 'Date range.' , true )
2022-08-25 20:38:43 +12:00
-> param ( 'provider' , '' , new WhiteList ( \array_merge ([ 'email' , 'anonymous' ], \array_map ( fn ( $value ) => " oauth- " . $value , \array_keys ( Config :: getParam ( 'providers' , [])))), true ), 'Provider Name.' , true )
2021-08-20 21:57:46 +12:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-08-20 21:57:46 +12:00
-> inject ( 'register' )
2022-05-26 01:36:25 +12:00
-> action ( function ( string $range , string $provider , Response $response , Database $dbForProject ) {
2021-08-20 21:57:46 +12:00
2021-08-27 06:53:55 +12:00
$usage = [];
2021-08-20 21:57:46 +12:00
if ( App :: getEnv ( '_APP_USAGE_STATS' , 'enabled' ) == 'enabled' ) {
2021-10-28 11:17:15 +13:00
$periods = [
2021-08-20 21:57:46 +12:00
'24h' => [
2022-10-21 18:45:25 +13:00
'period' => '1h' ,
'limit' => 24 ,
2021-08-20 21:57:46 +12:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-26 10:10:52 +12:00
'users.$all.count.total' ,
2022-08-11 14:11:31 +12:00
'users.$all.requests.create' ,
'users.$all.requests.read' ,
'users.$all.requests.update' ,
'users.$all.requests.delete' ,
'sessions.$all.requests.create' ,
'sessions.$all.requests.delete' ,
" sessions. $provider .requests.create " ,
2021-08-20 21:57:46 +12:00
];
2021-08-27 06:53:55 +12:00
$stats = [];
2021-08-29 04:25:48 +12:00
2022-05-24 02:54:50 +12:00
Authorization :: skip ( function () use ( $dbForProject , $periods , $range , $metrics , & $stats ) {
2021-08-29 04:25:48 +12:00
foreach ( $metrics as $metric ) {
2021-10-28 11:17:15 +13:00
$limit = $periods [ $range ][ 'limit' ];
$period = $periods [ $range ][ 'period' ];
2021-10-28 08:57:20 +13:00
2021-12-28 01:45:23 +13:00
$requestDocs = $dbForProject -> find ( 'stats' , [
2022-08-12 11:53:52 +12:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-05-24 02:54:50 +12:00
2021-08-29 04:25:48 +12:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2021-10-28 08:57:20 +13:00
// backfill metrics with empty values for graphs
$backfill = $limit - \count ( $requestDocs );
while ( $backfill > 0 ) {
$last = $limit - $backfill - 1 ; // array index of last added metric
2022-05-24 02:54:50 +12:00
$diff = match ( $period ) { // convert period to seconds for unix timestamp math
2022-10-21 18:45:25 +13:00
'1h' => 3600 ,
2021-10-28 08:57:20 +13:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-16 11:48:09 +12:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2021-10-28 08:57:20 +13:00
];
$backfill -- ;
}
2021-08-29 04:25:48 +12:00
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-05-24 02:54:50 +12:00
}
2021-08-29 04:25:48 +12:00
});
2021-08-20 21:57:46 +12:00
2021-08-27 06:53:55 +12:00
$usage = new Document ([
2021-08-20 21:57:46 +12:00
'range' => $range ,
2022-08-26 10:10:52 +12:00
'usersCount' => $stats [ 'users.$all.count.total' ] ? ? [],
2022-08-20 23:20:31 +12:00
'usersCreate' => $stats [ 'users.$all.requests.create' ] ? ? [],
'usersRead' => $stats [ 'users.$all.requests.read' ] ? ? [],
'usersUpdate' => $stats [ 'users.$all.requests.update' ] ? ? [],
'usersDelete' => $stats [ 'users.$all.requests.delete' ] ? ? [],
'sessionsCreate' => $stats [ 'sessions.$all.requests.create' ] ? ? [],
'sessionsProviderCreate' => $stats [ " sessions. $provider .requests.create " ] ? ? [],
'sessionsDelete' => $stats [ 'sessions.$all.requests.delete' ? ? []]
2021-08-20 21:57:46 +12:00
]);
}
2021-08-27 06:53:55 +12:00
2021-08-28 05:34:43 +12:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_USERS );
2022-05-24 02:54:50 +12:00
});