diff --git a/app/config/collections.old.php b/app/config/collections.old.php deleted file mode 100644 index 4b869d1160..0000000000 --- a/app/config/collections.old.php +++ /dev/null @@ -1,1616 +0,0 @@ - [ - '$id' => 'console', - '$collection' => 'projects', - '$permissions' => ['read' => ['role:all']], - 'name' => 'Appwrite', - 'description' => 'Appwrite core engine', - 'logo' => '', - 'teamId' => -1, - 'webhooks' => [], - 'keys' => [], - 'platforms' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_PLATFORMS, - 'name' => 'Localhost', - 'type' => 'web', - 'hostname' => 'localhost', - ], // Current host is added on app init - ], - 'legalName' => '', - 'legalCountry' => '', - 'legalState' => '', - 'legalCity' => '', - 'legalAddress' => '', - 'legalTaxId' => '', - 'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [], - 'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [], - 'usersAuthLimit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user - ], - Database::SYSTEM_COLLECTION_COLLECTIONS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Collections', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Updated', - 'key' => 'dateUpdated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Structure', - 'key' => 'structure', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => false, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Rules', - 'key' => 'rules', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => true, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_RULES], - ], - ], - ], - Database::SYSTEM_COLLECTION_RULES => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_RULES, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Collections Rule', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Label', - 'key' => 'label', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Key', - 'key' => 'key', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Type', - 'key' => 'type', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Default', - 'key' => 'default', - 'type' => Database::SYSTEM_VAR_TYPE_WILDCARD, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Required', - 'key' => 'required', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => true, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Array', - 'key' => 'array', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => true, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'list', - 'key' => 'list', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - //'default' => '', - 'required' => false, - 'array' => true, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Filter', - 'key' => 'filter', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'required' => false, - 'array' => true, - ], - ], - ], - Database::SYSTEM_COLLECTION_USERS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_USERS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'User', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Email', - 'key' => 'email', - 'type' => Database::SYSTEM_VAR_TYPE_EMAIL, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Status', - 'key' => 'status', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Password', - 'key' => 'password', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Password Update Date', - 'key' => 'passwordUpdate', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Prefs', - 'key' => 'prefs', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - 'filter' => ['json'] - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Registration Date', - 'key' => 'registration', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Email Verification Status', - 'key' => 'emailVerification', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Reset', - 'key' => 'reset', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Sessions', - 'key' => 'sessions', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_SESSIONS], - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Tokens', - 'key' => 'tokens', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_TOKENS], - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Memberships', - 'key' => 'memberships', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_MEMBERSHIPS], - ], - ], - ], - Database::SYSTEM_COLLECTION_SESSIONS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_SESSIONS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Session', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'User ID', - 'key' => 'userId', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Provider', - 'key' => 'provider', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Provider User Identifier', - 'key' => 'providerUid', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Provider Token', - 'key' => 'providerToken', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Secret', - 'key' => 'secret', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Expire', - 'key' => 'expire', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'User Agent', - 'key' => 'userAgent', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'IP', - 'key' => 'ip', - 'type' => Database::SYSTEM_VAR_TYPE_IP, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OS Code', - 'key' => 'osCode', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OS Name', - 'key' => 'osName', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OS Version', - 'key' => 'osVersion', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Client Type', - 'key' => 'clientType', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Client Code', - 'key' => 'clientCode', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Client Name', - 'key' => 'clientName', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Client Version', - 'key' => 'clientVersion', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Client Engine', - 'key' => 'clientEngine', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Client Engine Version', - 'key' => 'clientEngineVersion', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Device Name', - 'key' => 'deviceName', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Device Brand', - 'key' => 'deviceBrand', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Device Model', - 'key' => 'deviceModel', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Country Code', - 'key' => 'countryCode', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_TOKENS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_TOKENS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Token', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'User ID', - 'key' => 'userId', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Type', - 'key' => 'type', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Secret', - 'key' => 'secret', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Expire', - 'key' => 'expire', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'User Agent', - 'key' => 'userAgent', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'IP', - 'key' => 'ip', - 'type' => Database::SYSTEM_VAR_TYPE_IP, - 'default' => '', - 'required' => true, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_MEMBERSHIPS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_MEMBERSHIPS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Membership', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Team ID', - 'key' => 'teamId', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'User ID', - 'key' => 'userId', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Roles', - 'key' => 'roles', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => true, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Invited', - 'key' => 'invited', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, //FIXME SHOULD BE REQUIRED - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Joined', - 'key' => 'joined', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Confirm', - 'key' => 'confirm', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Secret', - 'key' => 'secret', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_TEAMS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_TEAMS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Team', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Sum', - 'key' => 'sum', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_PROJECTS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_PROJECTS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Project', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Description', - 'key' => 'description', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Logo', - 'key' => 'logo', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'URL', - 'key' => 'url', - 'type' => Database::SYSTEM_VAR_TYPE_URL, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Team ID', - 'key' => 'teamId', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => 0, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Legal Name', - 'key' => 'legalName', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Legal Country', - 'key' => 'legalCountry', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Legal State', - 'key' => 'legalState', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Legal City', - 'key' => 'legalCity', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Legal Address', - 'key' => 'legalAddress', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Legal Tax ID', - 'key' => 'legalTaxId', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Max users allowed', - 'key' => 'usersAuthLimit', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Version', - 'key' => 'version', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Webhooks', - 'key' => 'webhooks', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_WEBHOOKS], - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'API Keys', - 'key' => 'keys', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_KEYS], - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Platforms', - 'key' => 'platforms', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_PLATFORMS], - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Domains', - 'key' => 'domains', - 'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT, - 'default' => [], - 'required' => false, - 'array' => true, - 'list' => [Database::SYSTEM_COLLECTION_DOMAINS], - ], - ], - ], - Database::SYSTEM_COLLECTION_WEBHOOKS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_WEBHOOKS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Webhook', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Events', - 'key' => 'events', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => false, - 'array' => true, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'URL', - 'key' => 'url', - 'type' => Database::SYSTEM_VAR_TYPE_URL, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Security', - 'key' => 'security', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'HTTP User', - 'key' => 'httpUser', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'HTTP Password', - 'key' => 'httpPass', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - 'filter' => ['encrypt'], - ], - ], - ], - Database::SYSTEM_COLLECTION_KEYS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_KEYS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Key', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Scopes', - 'key' => 'scopes', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => false, - 'array' => true, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Secret', - 'key' => 'secret', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'filter' => ['encrypt'], - ], - ], - ], - Database::SYSTEM_COLLECTION_PLATFORMS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_PLATFORMS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Platform', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Type', - 'key' => 'type', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Updated', - 'key' => 'dateUpdated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Key', - 'key' => 'key', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Store', - 'key' => 'store', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Hostname', - 'key' => 'hostname', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_DOMAINS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_DOMAINS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Domains', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Domain', - 'key' => 'domain', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Updated', - 'key' => 'updated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Top Level Domain', - 'key' => 'tld', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Registerable Domain', - 'key' => 'registerable', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Verification', - 'key' => 'verification', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => false, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Certificate ID', - 'key' => 'certificateId', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_CERTIFICATES => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_CERTIFICATES, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Certificates', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Domain', - 'key' => 'domain', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Issue Date', - 'key' => 'issueDate', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Renew Date', - 'key' => 'renewDate', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Attempts', - 'key' => 'attempts', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Log', - 'key' => 'log', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Updated Date', - 'key' => 'updated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Certificate ID', - 'key' => 'certificateId', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_FILES => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_FILES, - '$permissions' => ['read' => ['role:all']], - 'name' => 'File', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Folder ID', - 'key' => 'folderId', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Path', - 'key' => 'path', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Signature', - 'key' => 'signature', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Mime Type', - 'key' => 'mimeType', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Original Size', - 'key' => 'sizeOriginal', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Actual Size', - 'key' => 'sizeActual', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Algorithm', - 'key' => 'algorithm', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Token', - 'key' => 'token', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Comment', - 'key' => 'comment', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'File OpenSSL Version', - 'key' => 'fileOpenSSLVersion', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'File OpenSSL Cipher', - 'key' => 'fileOpenSSLCipher', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'File OpenSSL Tag', - 'key' => 'fileOpenSSLTag', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'File OpenSSL IV', - 'key' => 'fileOpenSSLIV', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_FUNCTIONS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_FUNCTIONS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Functions', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Updated', - 'key' => 'dateUpdated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Status', - 'key' => 'status', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Name', - 'key' => 'name', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Runtime', - 'key' => 'runtime', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Tag', - 'key' => 'tag', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Vars', - 'key' => 'vars', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - 'filter' => ['json', 'encrypt'] - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Events', - 'key' => 'events', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => true, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Schedule', - 'key' => 'schedule', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Schedule Previous Run', - 'key' => 'schedulePrevious', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Schedule Next Run', - 'key' => 'scheduleNext', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Timeout', - 'key' => 'timeout', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_TAGS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_TAGS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Tags', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Function ID', - 'key' => 'functionId', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Command', - 'key' => 'command', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Code Path', - 'key' => 'path', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Code Size', - 'key' => 'size', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_EXECUTIONS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_EXECUTIONS, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Executions', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Date Created', - 'key' => 'dateCreated', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => 0, - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Function ID', - 'key' => 'functionId', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Tag ID', - 'key' => 'tagId', - 'type' => Database::SYSTEM_VAR_TYPE_KEY, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Trigger', - 'key' => 'trigger', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Status', - 'key' => 'status', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Exit Code', - 'key' => 'exitCode', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Stdout', - 'key' => 'stdout', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Stderr', - 'key' => 'stderr', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'Time', - 'key' => 'time', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'default' => '', - 'required' => false, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_CONNECTIONS => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_CONNECTIONS, - '$permissions' => ['read' => ['*']], - 'name' => 'Realtime Connections', - 'structure' => true, - 'rules' => [ - [ - '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, - 'label' => 'Container', - 'key' => 'container', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, - 'label' => 'Timestamp', - 'key' => 'timestamp', - 'type' => Database::SYSTEM_VAR_TYPE_NUMERIC, - 'required' => true, - 'array' => false, - ], - [ - '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, - 'label' => 'Value', - 'key' => 'value', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'required' => true, - 'array' => false, - ], - ], - ], - Database::SYSTEM_COLLECTION_RESERVED => [ - '$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS, - '$id' => Database::SYSTEM_COLLECTION_RESERVED, - '$permissions' => ['read' => ['role:all']], - 'name' => 'Reserved', - 'structure' => true, - ], -]; - -/* - * Add enabled OAuth2 providers to default data rules - */ -foreach ($providers as $index => $provider) { - if (!$provider['enabled']) { - continue; - } - - $collections[Database::SYSTEM_COLLECTION_PROJECTS]['rules'][] = [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OAuth2 '.\ucfirst($index).' ID', - 'key' => 'usersOauth2'.\ucfirst($index).'Appid', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - ]; - - $collections[Database::SYSTEM_COLLECTION_PROJECTS]['rules'][] = [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => 'OAuth2 '.\ucfirst($index).' Secret', - 'key' => 'usersOauth2'.\ucfirst($index).'Secret', - 'type' => Database::SYSTEM_VAR_TYPE_TEXT, - 'default' => '', - 'required' => false, - 'array' => false, - 'filter' => ['encrypt'], - ]; -} - -foreach ($auth as $index => $method) { - $collections[Database::SYSTEM_COLLECTION_PROJECTS]['rules'][] = [ - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'label' => $method['name'] ?? '', - 'key' => $method['key'] ?? '', - 'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN, - 'default' => true, - 'required' => false, - ]; -} - -return $collections; \ No newline at end of file diff --git a/app/config/collections.php b/app/config/collections.php index c8dffa8418..4f222c71d2 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -2317,7 +2317,7 @@ $collections = [ ], ], ], - + 'realtime' => [ '$collection' => Database::METADATA, '$id' => 'realtime', @@ -2369,4 +2369,4 @@ $collections = [ ], ]; -return $collections; \ No newline at end of file +return $collections; diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 11a1d1513b..6e8f0fc0a1 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -3,7 +3,6 @@ use Ahc\Jwt\JWT; use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; -use Appwrite\Database\Validator\CustomId; use Appwrite\Detector\Detector; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Host; @@ -12,6 +11,7 @@ use Appwrite\OpenSSL\OpenSSL; use Appwrite\Template\Template; use Appwrite\URL\URL as URLParser; use Appwrite\Utopia\Response; +use Appwrite\Utopia\Database\Validator\CustomId; use Utopia\App; use Utopia\Audit\Audit; use Utopia\Config\Config; diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 46b9897201..0ed47d4b5f 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -27,10 +27,10 @@ use Utopia\Database\Exception\Duplicate as DuplicateException; use Utopia\Database\Exception\Limit as LimitException; use Utopia\Database\Exception\Structure as StructureException; use Appwrite\Auth\Auth; -use Appwrite\Database\Validator\CustomId; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; use Appwrite\Network\Validator\URL; +use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Response; use Appwrite\Detector\Detector; use Appwrite\Event\Event; diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 8488b341f0..3377e8a050 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -2,7 +2,7 @@ use Ahc\Jwt\JWT; use Appwrite\Auth\Auth; -use Appwrite\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\CustomId; use Utopia\Database\Validator\UID; use Utopia\Storage\Storage; use Utopia\Storage\Validator\File; diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index b65eb5db7b..3104f51d73 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -2,10 +2,10 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; -use Appwrite\Database\Validator\CustomId; use Appwrite\Network\Validator\CNAME; use Appwrite\Network\Validator\Domain as DomainValidator; use Appwrite\Network\Validator\URL; +use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Response; use Utopia\Abuse\Adapters\TimeLimit; use Utopia\App; @@ -537,7 +537,7 @@ App::delete('/v1/projects/:projectId') ->inject('deletes') ->action(function ($projectId, $password, $response, $user, $dbForConsole, $deletes) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ /** @var Utopia\Database\Database $dbForConsole */ /** @var Appwrite\Event\Event $deletes */ diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 1dba0c722a..b8f92bdae9 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1,31 +1,31 @@ desc('Create File') diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 0a5133d6b9..de3b2c4cba 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1,19 +1,14 @@ desc('Create Team') diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index e21b2d01fd..0bd8b1fc00 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -2,25 +2,25 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; +use Appwrite\Detector\Detector; +use Appwrite\Network\Validator\Email; +use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Response; use Utopia\App; -use Utopia\Exception; -use Utopia\Validator\Assoc; -use Utopia\Validator\WhiteList; -use Appwrite\Network\Validator\Email; -use Utopia\Validator\Text; -use Utopia\Validator\Range; -use Utopia\Validator\Boolean; use Utopia\Audit\Audit; +use Utopia\Config\Config; +use Utopia\Exception; use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Validator\UID; -use Appwrite\Detector\Detector; -use Appwrite\Database\Validator\CustomId; -use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; +use Utopia\Validator\Assoc; +use Utopia\Validator\WhiteList; +use Utopia\Validator\Text; +use Utopia\Validator\Range; +use Utopia\Validator\Boolean; App::post('/v1/users') ->desc('Create User') diff --git a/app/controllers/general.php b/app/controllers/general.php index 7f82c36a30..f0654a97e4 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -13,9 +13,6 @@ use Utopia\Config\Config; use Utopia\Domains\Domain; use Appwrite\Auth\Auth; use Appwrite\Network\Validator\Origin; -use Appwrite\Utopia\Response\Filters\V06; -use Appwrite\Utopia\Response\Filters\V07; -use Appwrite\Utopia\Response\Filters\V08; use Appwrite\Utopia\Response\Filters\V11; use Utopia\CLI\Console; use Utopia\Database\Document; @@ -159,15 +156,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons $responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); if ($responseFormat) { switch($responseFormat) { - case version_compare ($responseFormat , '0.6.2', '<=') : - Response::setFilter(new V06()); - break; - case version_compare ($responseFormat , '0.7.2', '<=') : - Response::setFilter(new V07()); - break; - case version_compare ($responseFormat , '0.8.0', '<=') : - Response::setFilter(new V08()); - break; case version_compare ($responseFormat , '0.11.0', '<=') : Response::setFilter(new V11()); break; @@ -337,8 +325,8 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project, $l if($logger) { if($error->getCode() >= 500 || $error->getCode() === 0) { try { + /** @var Utopia\Database\Document $user */ $user = $utopia->getResource('user'); - /** @var Appwrite\Database\Document $user */ } catch(\Throwable $th) { // All good, user is optional information for logger } diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 47b1b9a4d0..5fbab338c2 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -1,13 +1,13 @@ on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $logger = $app->getResource("logger"); if($logger) { try { + /** @var Utopia\Database\Document $user */ $user = $app->getResource('user'); - /** @var Appwrite\Database\Document $user */ } catch(\Throwable $_th) { // All good, user is optional information for logger } diff --git a/app/init.php b/app/init.php index a45ac69aea..64ae3091f2 100644 --- a/app/init.php +++ b/app/init.php @@ -21,7 +21,6 @@ use Appwrite\Extend\PDO; use Ahc\Jwt\JWT; use Ahc\Jwt\JWTException; use Appwrite\Auth\Auth; -use Appwrite\Database\Database as DatabaseOld; use Appwrite\Event\Event; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; @@ -62,7 +61,7 @@ const APP_PAGING_LIMIT = 12; const APP_LIMIT_COUNT = 5000; const APP_LIMIT_USERS = 10000; const APP_CACHE_BUSTER = 201; -const APP_VERSION_STABLE = '0.12.1'; +const APP_VERSION_STABLE = '0.13.0'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; @@ -158,43 +157,6 @@ if(!empty($user) || !empty($pass)) { Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', '')); } -/** - * Old DB Filters - */ -DatabaseOld::addFilter('json', - function($value) { - if(!is_array($value)) { - return $value; - } - return json_encode($value); - }, - function($value) { - return json_decode($value, true); - } -); - -DatabaseOld::addFilter('encrypt', - function($value) { - $key = App::getEnv('_APP_OPENSSL_KEY_V1'); - $iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM)); - $tag = null; - - return json_encode([ - 'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag), - 'method' => OpenSSL::CIPHER_AES_128_GCM, - 'iv' => bin2hex($iv), - 'tag' => bin2hex($tag), - 'version' => '1', - ]); - }, - function($value) { - $value = json_decode($value, true); - $key = App::getEnv('_APP_OPENSSL_KEY_V'.$value['version']); - - return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag'])); - } -); - /** * New DB Filters */ diff --git a/app/tasks/migrate.php b/app/tasks/migrate.php index b06a518cba..416f936d4c 100644 --- a/app/tasks/migrate.php +++ b/app/tasks/migrate.php @@ -1,18 +1,17 @@ task('migrate') ->param('version', APP_VERSION_STABLE, new Text(8), 'Version to migrate to.', true) @@ -23,86 +22,36 @@ $cli Console::exit(1); return; } - $options = []; - if (str_starts_with($version, '0.12.')) { - Console::error('--------------------'); - Console::error('WARNING'); - Console::error('--------------------'); - Console::warning('Migrating to Version 0.12.x introduces a major breaking change within the Database Service!'); - Console::warning('Before migrating, please read about the breaking changes here:'); - Console::info('https://dev.to/appwrite/appwrite-012-migration-post-3cha'); - $confirm = Console::confirm("If you want to proceed, type 'yes':"); - if ($confirm != 'yes') { - Console::exit(1); - return; - } - Console::log(''); - Console::log('Collections'); - Console::log('--------------------'); - Console::warning('Be aware that following actions will happen during the migration:'); - Console::warning('- Nested Document rules will be migrated to String attributes'); - Console::warning('- Numeric rules will be migrated to float attributes'); - Console::warning('- Wildcard and Markdown rules will be converted to string attributes'); - Console::info("Do you want to migrate your Database Collections?"); - $options['migrateCollections'] = Console::confirm("Type 'yes' or 'no':"); - - if ($options['migrateCollections'] === 'yes') { - Console::log(''); - Console::log('Documents'); - Console::log('------------------'); - Console::warning('Be aware that following actions will happen during the migration:'); - Console::warning('- Nested Documents will be stored as JSON values'); - Console::warning('- All Numeric values will be converted to float'); - Console::warning('- All Wildcard and Markdown values will be converted to string'); - Console::info("Do you want to migrate your Database Documents?"); - $options['migrateDocuments'] = Console::confirm("Type 'yes' or 'no':"); - } else { - $options['migrateDocuments'] = 'no'; - } - - - if ( - !in_array($options['migrateDocuments'], ['yes', 'no']) - || !in_array($options['migrateCollections'], ['yes', 'no']) - ) { - Console::error("You must reply with 'yes' or 'no'!"); - Console::exit(1); - return; - } - } - - Config::load('collectionsold', __DIR__ . '/../config/collections.old.php'); + $app = new App('UTC'); Console::success('Starting Data Migration to version ' . $version); $db = $register->get('db', true); $cache = $register->get('cache', true); - $cache->flushAll(); - $consoleDB = new Database(); - $consoleDB - ->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache)) - ->setNamespace('app_console') // Main DB - ->setMocks(Config::getParam('collectionsold', [])); + $cache = new Cache(new RedisCache($cache)); - $projectDB = new Database(); - $projectDB - ->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache)) - ->setMocks(Config::getParam('collectionsold', [])); + $projectDB = new Database(new MariaDB($db), $cache); + $projectDB->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $console = $consoleDB->getDocument('console'); + $consoleDB = new Database(new MariaDB($db), $cache); + $consoleDB->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $consoleDB->setNamespace('_project_console'); + + $console = $app->getResource('console'); $limit = 30; $sum = 30; $offset = 0; $projects = [$console]; $count = 0; + $totalProjects = $consoleDB->count('projects') + 1; $class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version]; - $migration = new $class($register->get('db'), $register->get('cache'), $options); + $migration = new $class(); - while ($sum > 0) { + while (!empty($projects)) { foreach ($projects as $project) { try { $migration @@ -114,23 +63,14 @@ $cli } } - $projects = $consoleDB->getCollection([ - 'limit' => $limit, - 'offset' => $offset, - 'filters' => [ - '$collection=' . Database::SYSTEM_COLLECTION_PROJECTS, - ], - ]); - $sum = \count($projects); + $projects = $consoleDB->find('projects', limit: $limit, offset: $offset); + $offset = $offset + $limit; $count = $count + $sum; - if ($sum > 0) { - Console::log('Fetched ' . $count . '/' . $consoleDB->getSum() . ' projects...'); - } + Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...'); } - $cache->flushAll(); Swoole\Event::wait(); // Wait for Coroutines to finish Console::success('Data Migration Completed'); diff --git a/src/Appwrite/Database/Adapter.php b/src/Appwrite/Database/Adapter.php deleted file mode 100644 index d8a1d0ecfc..0000000000 --- a/src/Appwrite/Database/Adapter.php +++ /dev/null @@ -1,161 +0,0 @@ -namespace = $namespace; - - return true; - } - - /** - * Get Namespace. - * - * Get namespace of current set scope - * - * @throws Exception - * - * @return string - */ - public function getNamespace() - { - if (empty($this->namespace)) { - throw new Exception('Missing namespace'); - } - - return $this->namespace; - } - - /** - * Get Document. - * - * @param string $id - * - * @return array - */ - abstract public function getDocument($id); - - /** - * Create Document - **. - * - * @param array $data - * - * @return array - */ - abstract public function createDocument(array $data = [], array $unique = []); - - /** - * Update Document. - * - * @param array $data - * - * @return array - */ - abstract public function updateDocument(array $data = []); - - /** - * Delete Node. - * - * @param string $id - * - * @return array - */ - abstract public function deleteDocument(string $id); - - /** - * Delete Unique Key. - * - * @param string $key - * - * @return array - */ - abstract public function deleteUniqueKey($key); - - /** - * Add Unique Key. - * - * @param string $key - * - * @return array - */ - abstract public function addUniqueKey($key); - - /** - * Create Namespace. - * - * @param string $namespace - * - * @return bool - */ - abstract public function createNamespace($namespace); - - /** - * Delete Namespace. - * - * @param string $namespace - * - * @return bool - */ - abstract public function deleteNamespace($namespace); - - /** - * Filter. - * - * Filter data sets using chosen queries - * - * @param array $options - * @param array $filterTypes - * - * @return array - */ - abstract public function getCollection(array $options, array $filterTypes = []); - - /** - * @param array $options - * - * @return int - */ - abstract public function getCount(array $options); - - /** - * Last Modified. - * - * Return Unix timestamp of last time a node queried in corrent session has been changed - * - * @return int - */ - abstract public function lastModified(); - - /** - * Get Debug Data. - * - * @return array - */ - abstract public function getDebug(); -} diff --git a/src/Appwrite/Database/Adapter/MySQL.php b/src/Appwrite/Database/Adapter/MySQL.php deleted file mode 100644 index 1cb940dadb..0000000000 --- a/src/Appwrite/Database/Adapter/MySQL.php +++ /dev/null @@ -1,986 +0,0 @@ -pdo = $pdo; - $this->redis = $redis; - } - - /** - * Get Document. - * - * @param string $id - * - * @return array - * - * @throws Exception - */ - public function getDocument($id) - { - // Get fields abstraction - $st = $this->getPDO()->prepare('SELECT * FROM `'.$this->getNamespace().'.database.documents` a - WHERE a.uid = :uid AND a.status = 0 - ORDER BY a.updatedAt DESC LIMIT 10; - '); - - $st->bindValue(':uid', $id, PDO::PARAM_STR); - - $st->execute(); - - $document = $st->fetch(); - - if (empty($document)) { // Not Found - return []; - } - - // Get fields abstraction - $st = $this->getPDO()->prepare('SELECT * FROM `'.$this->getNamespace().'.database.properties` a - WHERE a.documentUid = :documentUid AND a.documentRevision = :documentRevision - ORDER BY `order` - '); - - $st->bindParam(':documentUid', $document['uid'], PDO::PARAM_STR, 32); - $st->bindParam(':documentRevision', $document['revision'], PDO::PARAM_STR, 32); - - $st->execute(); - - $properties = $st->fetchAll(); - - $output = [ - '$id' => null, - '$collection' => null, - '$permissions' => (!empty($document['permissions'])) ? \json_decode($document['permissions'], true) : [], - ]; - - foreach ($properties as &$property) { - \settype($property['value'], $property['primitive']); - - if ($property['array']) { - $output[$property['key']][] = $property['value']; - } else { - $output[$property['key']] = $property['value']; - } - } - - // Get fields abstraction - $st = $this->getPDO()->prepare('SELECT * FROM `'.$this->getNamespace().'.database.relationships` a - WHERE a.start = :start AND revision = :revision - ORDER BY `order` - '); - - $st->bindParam(':start', $document['uid'], PDO::PARAM_STR, 32); - $st->bindParam(':revision', $document['revision'], PDO::PARAM_STR, 32); - - $st->execute(); - - $output['temp-relations'] = $st->fetchAll(); - - return $output; - } - - /** - * Create Document. - * - * @param array $data - * - * @throws \Exception - * - * @return array - */ - public function createDocument(array $data = [], array $unique = []) - { - $order = 0; - $data = \array_merge(['$id' => null, '$permissions' => []], $data); // Merge data with default params - $signature = \md5(\json_encode($data)); - $revision = \uniqid('', true); - $data['$id'] = (empty($data['$id'])) ? null : $data['$id']; - - /* - * When updating node, check if there are any changes to update - * by comparing data md5 signatures - */ - if (null !== $data['$id']) { - $st = $this->getPDO()->prepare('SELECT signature FROM `'.$this->getNamespace().'.database.documents` a - WHERE a.uid = :uid AND a.status = 0 - ORDER BY a.updatedAt DESC LIMIT 1; - '); - - $st->bindValue(':uid', $data['$id'], PDO::PARAM_STR); - - $st->execute(); - - $result = $st->fetch(); - - if ($result && isset($result['signature'])) { - $oldSignature = $result['signature']; - - if ($signature === $oldSignature) { - return $data; - } - } - } - - /** - * Check Unique Keys - */ - foreach ($unique as $key => $value) { - $st = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.unique` - SET `key` = :key; - '); - - $st->bindValue(':key', \md5($data['$collection'].':'.$key.'='.$value), PDO::PARAM_STR); - - if (!$st->execute()) { - throw new Duplicate('Duplicated Property: '.$key.'='.$value); - } - } - - // Add or update fields abstraction level - $st1 = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.documents` - SET uid = :uid, createdAt = :createdAt, updatedAt = :updatedAt, signature = :signature, revision = :revision, permissions = :permissions, status = 0 - ON DUPLICATE KEY UPDATE uid = :uid, updatedAt = :updatedAt, signature = :signature, revision = :revision, permissions = :permissions; - '); - - // Adding fields properties - if (null === $data['$id'] || !isset($data['$id'])) { // Get new fields UID - $data['$id'] = $this->getId(); - } - - $st1->bindValue(':uid', $data['$id'], PDO::PARAM_STR); - $st1->bindValue(':revision', $revision, PDO::PARAM_STR); - $st1->bindValue(':signature', $signature, PDO::PARAM_STR); - $st1->bindValue(':createdAt', \date('Y-m-d H:i:s', \time()), PDO::PARAM_STR); - $st1->bindValue(':updatedAt', \date('Y-m-d H:i:s', \time()), PDO::PARAM_STR); - $st1->bindValue(':permissions', \json_encode($data['$permissions']), PDO::PARAM_STR); - - $st1->execute(); - - // Delete old properties - $rms1 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.properties` WHERE documentUid = :documentUid AND documentRevision != :documentRevision'); - $rms1->bindValue(':documentUid', $data['$id'], PDO::PARAM_STR); - $rms1->bindValue(':documentRevision', $revision, PDO::PARAM_STR); - $rms1->execute(); - - // Delete old relationships - $rms2 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.relationships` WHERE start = :start AND revision != :revision'); - $rms2->bindValue(':start', $data['$id'], PDO::PARAM_STR); - $rms2->bindValue(':revision', $revision, PDO::PARAM_STR); - $rms2->execute(); - - // Create new properties - $st2 = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.properties` - (`documentUid`, `documentRevision`, `key`, `value`, `primitive`, `array`, `order`) - VALUES (:documentUid, :documentRevision, :key, :value, :primitive, :array, :order)'); - - $props = []; - - foreach ($data as $key => $value) { // Prepare properties data - - if (\in_array($key, ['$permissions'])) { - continue; - } - - $type = $this->getDataType($value); - - // Handle array of relations - if (self::DATA_TYPE_ARRAY === $type) { - if (!is_array($value)) { // Property should be of type array, if not = skip - continue; - } - - foreach ($value as $i => $child) { - if (self::DATA_TYPE_DICTIONARY !== $this->getDataType($child)) { // not dictionary - - $props[] = [ - 'type' => $this->getDataType($child), - 'key' => $key, - 'value' => $child, - 'array' => true, - 'order' => $order++, - ]; - - continue; - } - - $data[$key][$i] = $this->createDocument($child); - - $this->createRelationship($revision, $data['$id'], $data[$key][$i]['$id'], $key, true, $i); - } - - continue; - } - - // Handle relation - if (self::DATA_TYPE_DICTIONARY === $type) { - $value = $this->createDocument($value); - $this->createRelationship($revision, $data['$id'], $value['$id'], $key); //xxx - continue; - } - - // Handle empty values - if (self::DATA_TYPE_NULL === $type) { - continue; - } - - $props[] = [ - 'type' => $type, - 'key' => $key, - 'value' => $value, - 'array' => false, - 'order' => $order++, - ]; - } - - foreach ($props as $prop) { - if (\is_array($prop['value'])) { - throw new Exception('Value can\'t be an array: '.\json_encode($prop['value'])); - } - if (\is_bool($prop['value'])) { - $prop['value'] = (int) $prop['value']; - } - $st2->bindValue(':documentUid', $data['$id'], PDO::PARAM_STR); - $st2->bindValue(':documentRevision', $revision, PDO::PARAM_STR); - - $st2->bindValue(':key', $prop['key'], PDO::PARAM_STR); - $st2->bindValue(':value', $prop['value'], PDO::PARAM_STR); - $st2->bindValue(':primitive', $prop['type'], PDO::PARAM_STR); - $st2->bindValue(':array', $prop['array'], PDO::PARAM_BOOL); - $st2->bindValue(':order', $prop['order'], PDO::PARAM_STR); - - $st2->execute(); - } - - // TODO remove this dependency (check if related to nested documents) - $this->getRedis()->expire($this->getNamespace().':document-'.$data['$id'], 0); - $this->getRedis()->expire($this->getNamespace().':document-'.$data['$id'], 0); - - return $data; - } - - /** - * Update Document. - * - * @param array $data - * - * @return array - * - * @throws Exception - */ - public function updateDocument(array $data = []) - { - return $this->createDocument($data); - } - - /** - * Delete Document. - * - * @param string $id - * - * @return array - * - * @throws Exception - */ - public function deleteDocument(string $id) - { - $st1 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.documents` - WHERE uid = :id - '); - - $st1->bindValue(':id', $id, PDO::PARAM_STR); - - $st1->execute(); - - $st2 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.properties` - WHERE documentUid = :id - '); - - $st2->bindValue(':id', $id, PDO::PARAM_STR); - - $st2->execute(); - - $st3 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.relationships` - WHERE start = :id OR end = :id - '); - - $st3->bindValue(':id', $id, PDO::PARAM_STR); - - $st3->execute(); - - return []; - } - - /** - * Delete Unique Key. - * - * @param string $key - * - * @return array - * - * @throws Exception - */ - public function deleteUniqueKey($key) - { - $st1 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.unique` WHERE `key` = :key'); - - $st1->bindValue(':key', $key, PDO::PARAM_STR); - - $st1->execute(); - - return []; - } - - /** - * Add Unique Key. - * - * @param string $key - * - * @return array - * - * @throws Exception - */ - public function addUniqueKey($key) - { - $st = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.unique` - SET `key` = :key; - '); - - $st->bindValue(':key', $key, PDO::PARAM_STR); - - if (!$st->execute()) { - throw new Duplicate('Duplicated Property: '.$key); - } - - return []; - } - - /** - * Create Relation. - * - * Adds a new relationship between different nodes - * - * @param string $revision - * @param int $start - * @param int $end - * @param string $key - * @param bool $isArray - * @param int $order - * - * @return array - * - * @throws Exception - */ - protected function createRelationship($revision, $start, $end, $key, $isArray = false, $order = 0) - { - $st2 = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.relationships` - (`revision`, `start`, `end`, `key`, `array`, `order`) - VALUES (:revision, :start, :end, :key, :array, :order)'); - - $st2->bindValue(':revision', $revision, PDO::PARAM_STR); - $st2->bindValue(':start', $start, PDO::PARAM_STR); - $st2->bindValue(':end', $end, PDO::PARAM_STR); - $st2->bindValue(':key', $key, PDO::PARAM_STR); - $st2->bindValue(':array', $isArray, PDO::PARAM_INT); - $st2->bindValue(':order', $order, PDO::PARAM_INT); - - $st2->execute(); - - return []; - } - - /** - * Create Namespace. - * - * @param $namespace - * - * @throws Exception - * - * @return bool - */ - public function createNamespace($namespace) - { - if (empty($namespace)) { - throw new Exception('Empty namespace'); - } - - $documents = 'app_'.$namespace.'.database.documents'; - $properties = 'app_'.$namespace.'.database.properties'; - $relationships = 'app_'.$namespace.'.database.relationships'; - $unique = 'app_'.$namespace.'.database.unique'; - $audit = 'app_'.$namespace.'.audit.audit'; - $abuse = 'app_'.$namespace.'.abuse.abuse'; - - try { - $this->getPDO()->prepare('CREATE TABLE `'.$documents.'` LIKE `template.database.documents`;')->execute(); - $this->getPDO()->prepare('CREATE TABLE `'.$properties.'` LIKE `template.database.properties`;')->execute(); - $this->getPDO()->prepare('CREATE TABLE `'.$relationships.'` LIKE `template.database.relationships`;')->execute(); - $this->getPDO()->prepare('CREATE TABLE `'.$unique.'` LIKE `template.database.unique`;')->execute(); - $this->getPDO()->prepare('CREATE TABLE `'.$audit.'` LIKE `template.audit.audit`;')->execute(); - $this->getPDO()->prepare('CREATE TABLE `'.$abuse.'` LIKE `template.abuse.abuse`;')->execute(); - } catch (Exception $e) { - throw $e; - } - - return true; - } - - /** - * Delete Namespace. - * - * @param $namespace - * - * @throws Exception - * - * @return bool - */ - public function deleteNamespace($namespace) - { - if (empty($namespace)) { - throw new Exception('Empty namespace'); - } - - $unique = 'app_'.$namespace.'.database.unique'; - $documents = 'app_'.$namespace.'.database.documents'; - $properties = 'app_'.$namespace.'.database.properties'; - $relationships = 'app_'.$namespace.'.database.relationships'; - $audit = 'app_'.$namespace.'.audit.audit'; - $abuse = 'app_'.$namespace.'.abuse.abuse'; - - try { - $this->getPDO()->prepare('DROP TABLE `'.$unique.'`;')->execute(); - $this->getPDO()->prepare('DROP TABLE `'.$documents.'`;')->execute(); - $this->getPDO()->prepare('DROP TABLE `'.$properties.'`;')->execute(); - $this->getPDO()->prepare('DROP TABLE `'.$relationships.'`;')->execute(); - $this->getPDO()->prepare('DROP TABLE `'.$audit.'`;')->execute(); - $this->getPDO()->prepare('DROP TABLE `'.$abuse.'`;')->execute(); - } catch (Exception $e) { - throw $e; - } - - return true; - } - - /** - * Get Collection. - * - * @param array $options - * @param array $filterTypes - * - * @throws Exception - * - * @return array - */ - public function getCollection(array $options, array $filterTypes = []) - { - $start = \microtime(true); - $orderCastMap = [ - 'int' => 'UNSIGNED', - 'string' => 'CHAR', - 'date' => 'DATE', - 'time' => 'TIME', - 'datetime' => 'DATETIME', - ]; - $orderTypeMap = ['DESC', 'ASC']; - - $options['orderField'] = (empty($options['orderField'])) ? '' : $options['orderField']; // Set default order field - $options['orderCast'] = (empty($options['orderCast'])) ? 'string' : $options['orderCast']; // Set default order field - - if (!\array_key_exists($options['orderCast'], $orderCastMap)) { - throw new Exception('Invalid order cast'); - } - - if (!\in_array($options['orderType'], $orderTypeMap)) { - throw new Exception('Invalid order type'); - } - - $where = []; - $join = []; - $sorts = []; - $search = ''; - - // Filters - foreach ($options['filters'] as $i => $filter) { - $filter = $this->parseFilter($filter); - $key = $filter['key']; - $value = $filter['value']; - $operator = $filter['operator']; - - $path = \explode('.', $key); - $original = $path; - - if (1 < \count($path)) { - $key = \array_pop($path); - } else { - $path = []; - } - - //$path = implode('.', $path); - - if (array_key_exists($key, $filterTypes) && $filterTypes[$key] === 'numeric') { - $value = (float) $value; - } else { - $value = $this->getPDO()->quote($value, PDO::PARAM_STR); - } - - $key = $this->getPDO()->quote($key, PDO::PARAM_STR); - - //$path = $this->getPDO()->quote($path, PDO::PARAM_STR); - $options['offset'] = (int) $options['offset']; - $options['limit'] = (int) $options['limit']; - - if (empty($path)) { - //if($path == "''") { // Handle direct attributes queries - $where[] = 'JOIN `'.$this->getNamespace().".database.properties` b{$i} ON a.uid IS NOT NULL AND b{$i}.documentUid = a.uid AND (b{$i}.key = {$key} AND b{$i}.value {$operator} {$value})"; - } else { // Handle direct child attributes queries - $len = \count($original); - $prev = 'c'.$i; - - foreach ($original as $y => $part) { - $part = $this->getPDO()->quote($part, PDO::PARAM_STR); - - if (0 === $y) { // First key - $join[$i] = 'JOIN `'.$this->getNamespace().".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$part}"; - } elseif ($y == $len - 1) { // Last key - $join[$i] .= 'JOIN `'.$this->getNamespace().".database.properties` e{$i} ON e{$i}.documentUid = {$prev}.end AND e{$i}.key = {$part} AND e{$i}.value {$operator} {$value}"; - } else { - $join[$i] .= 'JOIN `'.$this->getNamespace().".database.relationships` d{$i}{$y} ON d{$i}{$y}.start = {$prev}.end AND d{$i}{$y}.key = {$part}"; - $prev = 'd'.$i.$y; - } - } - - //$join[] = "JOIN `" . $this->getNamespace() . ".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$path} - // JOIN `" . $this->getNamespace() . ".database.properties` d{$i} ON d{$i}.documentUid = c{$i}.end AND d{$i}.key = {$key} AND d{$i}.value {$operator} {$value}"; - } - } - - // Sorting - if (!empty($options['orderField'])) { - $orderPath = \explode('.', $options['orderField']); - $len = \count($orderPath); - $orderKey = 'order_b'; - $part = $this->getPDO()->quote(\implode('', $orderPath), PDO::PARAM_STR); - $orderSelect = "CASE WHEN {$orderKey}.key = {$part} THEN CAST({$orderKey}.value AS {$orderCastMap[$options['orderCast']]}) END AS sort_ff"; - - if (1 === $len) { - //if($path == "''") { // Handle direct attributes queries - $sorts[] = 'LEFT JOIN `'.$this->getNamespace().".database.properties` order_b ON a.uid IS NOT NULL AND order_b.documentUid = a.uid AND (order_b.key = {$part})"; - } else { // Handle direct child attributes queries - $prev = 'c'; - $orderKey = 'order_e'; - - foreach ($orderPath as $y => $part) { - $part = $this->getPDO()->quote($part, PDO::PARAM_STR); - $x = $y - 1; - - if (0 === $y) { // First key - $sorts[] = 'JOIN `'.$this->getNamespace().".database.relationships` order_c{$y} ON a.uid IS NOT NULL AND order_c{$y}.start = a.uid AND order_c{$y}.key = {$part}"; - } elseif ($y == $len - 1) { // Last key - $sorts[] .= 'JOIN `'.$this->getNamespace().".database.properties` order_e ON order_e.documentUid = order_{$prev}{$x}.end AND order_e.key = {$part}"; - } else { - $sorts[] .= 'JOIN `'.$this->getNamespace().".database.relationships` order_d{$y} ON order_d{$y}.start = order_{$prev}{$x}.end AND order_d{$y}.key = {$part}"; - $prev = 'd'; - } - } - } - } else { - $orderSelect = 'a.uid AS sort_ff'; - } - - /* - * Workaround for a MySQL bug as reported here: - * https://bugs.mysql.com/bug.php?id=78485 - */ - $options['search'] = ($options['search'] === '*') ? '' : $options['search']; - - // Search - if (!empty($options['search'])) { // Handle free search - $where[] = 'LEFT JOIN `'.$this->getNamespace().".database.properties` b_search ON a.uid IS NOT NULL AND b_search.documentUid = a.uid AND b_search.primitive = 'string' - LEFT JOIN - `".$this->getNamespace().'.database.relationships` c_search ON c_search.start = b_search.documentUid - LEFT JOIN - `'.$this->getNamespace().".database.properties` d_search ON d_search.documentUid = c_search.end AND d_search.primitive = 'string' - \n"; - - $search = "AND (MATCH (b_search.value) AGAINST ({$this->getPDO()->quote($options['search'], PDO::PARAM_STR)} IN BOOLEAN MODE) - OR MATCH (d_search.value) AGAINST ({$this->getPDO()->quote($options['search'], PDO::PARAM_STR)} IN BOOLEAN MODE) - )"; - } - - $select = 'DISTINCT a.uid'; - $where = \implode("\n", $where); - $join = \implode("\n", $join); - $sorts = \implode("\n", $sorts); - $range = "LIMIT {$options['offset']}, {$options['limit']}"; - $roles = []; - - foreach (Authorization::getRoles() as $role) { - $roles[] = 'JSON_CONTAINS(REPLACE(a.permissions, \'{self}\', a.uid), \'"'.$role.'"\', \'$.read\')'; - } - - if (false === Authorization::$status) { // FIXME temporary solution (hopefully) - $roles = ['1=1']; - } - - $query = "SELECT %s, {$orderSelect} - FROM `".$this->getNamespace().".database.documents` a {$where}{$join}{$sorts} - WHERE status = 0 - {$search} - AND (".\implode('||', $roles).") - ORDER BY sort_ff {$options['orderType']} %s"; - - $st = $this->getPDO()->prepare(\sprintf($query, $select, $range)); - - $st->execute(); - - $results = ['data' => []]; - - // Get entire fields data for each id - foreach ($st->fetchAll() as $node) { - $results['data'][] = $node['uid']; - } - - $count = $this->getPDO()->prepare(\sprintf($query, 'count(DISTINCT a.uid) as sum', '')); - - $count->execute(); - - $count = $count->fetch(); - - $this->resetDebug(); - - $this - ->setDebug('query', \preg_replace('/\s+/', ' ', \sprintf($query, $select, $range))) - ->setDebug('time', \microtime(true) - $start) - ->setDebug('filters', \count($options['filters'])) - ->setDebug('joins', \substr_count($query, 'JOIN')) - ->setDebug('count', \count($results['data'])) - ->setDebug('sum', (int) $count['sum']) - ; - - return $results['data']; - } - - /** - * Get Collection. - * - * @param array $options - * - * @throws Exception - * - * @return int - */ - public function getCount(array $options) - { - $start = \microtime(true); - $where = []; - $join = []; - - $options = array_merge([ - 'attribute' => '', - 'filters' => [], - ], $options); - - // Filters - foreach ($options['filters'] as $i => $filter) { - $filter = $this->parseFilter($filter); - $key = $filter['key']; - $value = $filter['value']; - $operator = $filter['operator']; - $path = \explode('.', $key); - $original = $path; - - if (1 < \count($path)) { - $key = \array_pop($path); - } else { - $path = []; - } - - $key = $this->getPDO()->quote($key, PDO::PARAM_STR); - $value = $this->getPDO()->quote($value, PDO::PARAM_STR); - - if (empty($path)) { - //if($path == "''") { // Handle direct attributes queries - $where[] = 'JOIN `'.$this->getNamespace().".database.properties` b{$i} ON a.uid IS NOT NULL AND b{$i}.documentUid = a.uid AND (b{$i}.key = {$key} AND b{$i}.value {$operator} {$value})"; - } else { // Handle direct child attributes queries - $len = \count($original); - $prev = 'c'.$i; - - foreach ($original as $y => $part) { - $part = $this->getPDO()->quote($part, PDO::PARAM_STR); - - if (0 === $y) { // First key - $join[$i] = 'JOIN `'.$this->getNamespace().".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$part}"; - } elseif ($y == $len - 1) { // Last key - $join[$i] .= 'JOIN `'.$this->getNamespace().".database.properties` e{$i} ON e{$i}.documentUid = {$prev}.end AND e{$i}.key = {$part} AND e{$i}.value {$operator} {$value}"; - } else { - $join[$i] .= 'JOIN `'.$this->getNamespace().".database.relationships` d{$i}{$y} ON d{$i}{$y}.start = {$prev}.end AND d{$i}{$y}.key = {$part}"; - $prev = 'd'.$i.$y; - } - } - } - } - - $where = \implode("\n", $where); - $join = \implode("\n", $join); - $attribute = $this->getPDO()->quote($options['attribute'], PDO::PARAM_STR); - $func = 'JOIN `'.$this->getNamespace().".database.properties` b_func ON a.uid IS NOT NULL - AND a.uid = b_func.documentUid - AND (b_func.key = {$attribute})"; - $roles = []; - - foreach (Authorization::getRoles() as $role) { - $roles[] = 'JSON_CONTAINS(REPLACE(a.permissions, \'{self}\', a.uid), \'"'.$role.'"\', \'$.read\')'; - } - - if (false === Authorization::$status) { // FIXME temporary solution (hopefully) - $roles = ['1=1']; - } - - $query = "SELECT SUM(b_func.value) as result - FROM `".$this->getNamespace().".database.documents` a {$where}{$join}{$func} - WHERE status = 0 - AND (".\implode('||', $roles).')'; - - $st = $this->getPDO()->prepare(\sprintf($query)); - - $st->execute(); - - $result = $st->fetch(); - - $this->resetDebug(); - - $this - ->setDebug('query', \preg_replace('/\s+/', ' ', \sprintf($query))) - ->setDebug('time', \microtime(true) - $start) - ->setDebug('filters', \count($options['filters'])) - ->setDebug('joins', \substr_count($query, 'JOIN')) - ; - - return (isset($result['result'])) ? (int)$result['result'] : 0; - } - - /** - * Get Unique Document ID. - * - * @return string - */ - public function getId(): string - { - $unique = \uniqid(); - $attempts = 5; - - for ($i = 1; $i <= $attempts; ++$i) { - $document = $this->getDocument($unique); - - if (empty($document) || $document['$id'] !== $unique) { - return $unique; - } - } - - throw new Exception('Failed to create a unique ID ('.$attempts.' attempts)'); - } - - /** - * Last Modified. - * - * Return Unix timestamp of last time a node queried in corrent session has been changed - * - * @return int - */ - public function lastModified() - { - return $this->lastModified; - } - - /** - * Parse Filter. - * - * @param string $filter - * - * @return array - * - * @throws Exception - */ - protected function parseFilter($filter) - { - $operatorsMap = ['!=', '>=', '<=', '=', '>', '<']; // Do not edit order of this array - - //FIXME bug with >= <= operators - - $operator = null; - - foreach ($operatorsMap as $node) { - if (\strpos($filter, $node) !== false) { - $operator = $node; - break; - } - } - - if (empty($operator)) { - throw new Exception('Invalid operator'); - } - - $filter = \explode($operator, $filter); - - if (\count($filter) != 2) { - throw new Exception('Invalid filter expression'); - } - - return [ - 'key' => $filter[0], - 'value' => $filter[1], - 'operator' => $operator, - ]; - } - - /** - * Get Data Type. - * - * Check value data type. return value can be on of the following: - * string, integer, float, boolean, object, list or null - * - * @param $value - * - * @return string - * - * @throws \Exception - */ - protected function getDataType($value) - { - switch (\gettype($value)) { - - case 'string': - return self::DATA_TYPE_STRING; - break; - - case 'integer': - return self::DATA_TYPE_INTEGER; - break; - - case 'double': - return self::DATA_TYPE_FLOAT; - break; - - case 'boolean': - return self::DATA_TYPE_BOOLEAN; - break; - - case 'array': - if ((bool) \count(\array_filter(\array_keys($value), 'is_string'))) { - return self::DATA_TYPE_DICTIONARY; - } - - return self::DATA_TYPE_ARRAY; - break; - - case 'NULL': - return self::DATA_TYPE_NULL; - break; - } - - throw new Exception('Unknown data type: '.$value.' ('.\gettype($value).')'); - } - - /** - * @param string $key - * @param mixed $value - * - * @return $this - */ - public function setDebug(string $key, $value): self - { - $this->debug[$key] = $value; - - return $this; - } - - /** - * @return array - */ - public function getDebug(): array - { - return $this->debug; - } - - /** - * return $this;. - * - * @return void - */ - public function resetDebug(): void - { - $this->debug = []; - } - - /** - * @return PDO - * - * @throws Exception - */ - protected function getPDO() - { - return $this->pdo; - } - - /** - * @throws Exception - * - * @return Redis - */ - protected function getRedis(): Redis - { - return $this->redis; - } -} diff --git a/src/Appwrite/Database/Adapter/Redis.php b/src/Appwrite/Database/Adapter/Redis.php deleted file mode 100644 index eb2c185281..0000000000 --- a/src/Appwrite/Database/Adapter/Redis.php +++ /dev/null @@ -1,300 +0,0 @@ -redis = $redis; - $this->adapter = $adapter; - } - - /** - * Get Document. - * - * @param string $id - * - * @return array - * - * @throws Exception - */ - public function getDocument($id) - { - $output = \json_decode($this->getRedis()->get($this->getNamespace().':document-'.$id), true); - - if (!$output) { - $output = $this->adapter->getDocument($id); - $this->getRedis()->set($this->getNamespace().':document-'.$id, \json_encode($output, JSON_UNESCAPED_UNICODE)); - } - - $output = $this->parseRelations($output); - - return $output; - } - - /** - * @param $output - * - * @return mixed - * - * @throws Exception - */ - protected function parseRelations($output) - { - $keys = []; - - if (empty($output) || !isset($output['temp-relations'])) { - return $output; - } - - foreach ($output['temp-relations'] as $relationship) { - $keys[] = $this->getNamespace().':document-'.$relationship['end']; - } - - $nodes = (!empty($keys)) ? $this->getRedis()->mget($keys) : []; - - foreach ($output['temp-relations'] as $i => $relationship) { - $node = $relationship['end']; - - $node = (!empty($nodes[$i])) ? $this->parseRelations(\json_decode($nodes[$i], true)) : $this->getDocument($node); - - if (empty($node)) { - continue; - } - - if ($relationship['array']) { - $output[$relationship['key']][] = $node; - } else { - $output[$relationship['key']] = $node; - } - } - - unset($output['temp-relations']); - - return $output; - } - - /** - * Create Document. - * - * @param array $data - * - * @return array - * - * @throws Exception - */ - public function createDocument(array $data = [], array $unique = []) - { - $data = $this->adapter->createDocument($data, $unique); - - $this->getRedis()->expire($this->getNamespace().':document-'.$data['$id'], 0); - $this->getRedis()->expire($this->getNamespace().':document-'.$data['$id'], 0); - - return $data; - } - - /** - * Update Document. - * - * @param array $data - * - * @return array - * - * @throws Exception - */ - public function updateDocument(array $data = []) - { - $data = $this->adapter->updateDocument($data); - - $this->getRedis()->expire($this->getNamespace().':document-'.$data['$id'], 0); - $this->getRedis()->expire($this->getNamespace().':document-'.$data['$id'], 0); - - return $data; - } - - /** - * Delete Document. - * - * @param string $id - * - * @return array - * - * @throws Exception - */ - public function deleteDocument(string $id) - { - $data = $this->adapter->deleteDocument($id); - - $this->getRedis()->expire($this->getNamespace().':document-'.$id, 0); - $this->getRedis()->expire($this->getNamespace().':document-'.$id, 0); - - return $data; - } - - /** - * Delete Unique Key. - * - * @param $key - * - * @return array - * - * @throws Exception - */ - public function deleteUniqueKey($key) - { - $data = $this->adapter->deleteUniqueKey($key); - - return $data; - } - - /** - * Add Unique Key. - * - * @param $key - * - * @return array - * - * @throws Exception - */ - public function addUniqueKey($key) - { - $data = $this->adapter->addUniqueKey($key); - - return $data; - } - - /** - * Create Namespace. - * - * @param string $namespace - * - * @return bool - */ - public function createNamespace($namespace) - { - return $this->adapter->createNamespace($namespace); - } - - /** - * Delete Namespace. - * - * @param string $namespace - * - * @return bool - */ - public function deleteNamespace($namespace) - { - return $this->adapter->deleteNamespace($namespace); - } - - /** - * @param array $options - * @param array $filterTypes - * - * @return array - * - * @throws Exception - */ - public function getCollection(array $options, array $filterTypes = []) - { - $data = $this->adapter->getCollection($options, $filterTypes); - $keys = []; - - foreach ($data as $node) { - $keys[] = $this->getNamespace().':document-'.$node; - } - - $nodes = (!empty($keys)) ? $this->getRedis()->mget($keys) : []; - - foreach ($data as $i => &$node) { - $temp = (!empty($nodes[$i])) ? $this->parseRelations(\json_decode($nodes[$i], true)) : $this->getDocument($node); - - if (!empty($temp)) { - $node = $temp; - } - } - - return $data; - } - - /** - * @param array $options - * - * @return int - * - * @throws Exception - */ - public function getCount(array $options) - { - return $this->adapter->getCount($options); - } - - /** - * Last Modified. - * - * Return Unix timestamp of last time a node queried in current session has been changed - * - * @return int - */ - public function lastModified() - { - return 0; - } - - /** - * @return array - */ - public function getDebug() - { - return $this->adapter->getDebug(); - } - - /** - * @throws Exception - * - * @return Client - */ - protected function getRedis(): Client - { - return $this->redis; - } - - /** - * Set Namespace. - * - * Set namespace to divide different scope of data sets - * - * @param $namespace - * - * @return bool - * - * @throws Exception - */ - public function setNamespace($namespace) - { - $this->adapter->setNamespace($namespace); - - return parent::setNamespace($namespace); - } -} diff --git a/src/Appwrite/Database/Database.php b/src/Appwrite/Database/Database.php deleted file mode 100644 index 00225dcacc..0000000000 --- a/src/Appwrite/Database/Database.php +++ /dev/null @@ -1,628 +0,0 @@ -adapter = $adapter; - - return $this; - } - - /** - * Set Namespace. - * - * Set namespace to divide different scope of data sets - * - * @param $namespace - * - * @return $this - * - * @throws Exception - */ - public function setNamespace($namespace) - { - $this->adapter->setNamespace($namespace); - - return $this; - } - - /** - * Get Namespace. - * - * Get namespace of current set scope - * - * @return string - * - * @throws Exception - */ - public function getNamespace() - { - return $this->adapter->getNamespace(); - } - - /** - * Create Namespace. - * - * @param string $namespace - * - * @return bool - */ - public function createNamespace($namespace) - { - return $this->adapter->createNamespace($namespace); - } - - /** - * Delete Namespace. - * - * @param string $namespace - * - * @return bool - */ - public function deleteNamespace($namespace) - { - return $this->adapter->deleteNamespace($namespace); - } - - /** - * @param array $options - * @param array $filterTypes - * - * @return Document[] - */ - public function getCollection(array $options, array $filterTypes = []) - { - $options = \array_merge([ - 'offset' => 0, - 'limit' => 15, - 'search' => '', - 'relations' => true, - 'orderField' => '', - 'orderType' => 'ASC', - 'orderCast' => 'int', - 'filters' => [], - ], $options); - - $results = $this->adapter->getCollection($options, $filterTypes); - - foreach ($results as &$node) { - $node = $this->decode(new Document($node)); - } - - return $results; - } - - /** - * @param array $options - * - * @return Document - */ - public function getCollectionFirst(array $options) - { - $results = $this->getCollection($options); - return \reset($results); - } - - /** - * @param array $options - * - * @return Document - */ - public function getCollectionLast(array $options) - { - $results = $this->getCollection($options); - return \end($results); - } - - /** - * @param string $id - * @param bool $mock is mocked data allowed? - * @param bool $decode enable decoding? - * - * @return Document - */ - public function getDocument($id, bool $mock = true, bool $decode = true) - { - if (\is_null($id)) { - return new Document(); - } - - $document = new Document((isset($this->mocks[$id]) && $mock) ? $this->mocks[$id] : $this->adapter->getDocument($id)); - $validator = new Authorization($document, 'read'); - - if (!$validator->isValid($document->getPermissions())) { // Check if user has read access to this document - return new Document(); - } - - $document = ($decode) ? $this->decode($document) : $document; - - return $document; - } - - /** - * @param array $data - * - * @return Document - * - * @throws AuthorizationException - * @throws StructureException - */ - public function createDocument(array $data, array $unique = []) - { - $document = new Document($data); - - $validator = new Authorization($document, 'write'); - - if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document - throw new AuthorizationException($validator->getDescription()); - } - - $validator = new Structure($this); - - $document = $this->encode($document); - - if (!$validator->isValid($document)) { - throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $document = new Document($this->adapter->createDocument($document->getArrayCopy(), $unique)); - - $document = $this->decode($document); - - return $document; - } - - /** - * @param array $data - * - * @return Document|false - * - * @throws Exception - */ - public function updateDocument(array $data) - { - if (!isset($data['$id'])) { - throw new Exception('Must define $id attribute'); - } - - $document = $this->getDocument($data['$id']); // TODO make sure user don\'t need read permission for write operations - - // Make sure reserved keys stay constant - $data['$id'] = $document->getId(); - $data['$collection'] = $document->getCollection(); - - $validator = new Authorization($document, 'write'); - - if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document - throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $new = new Document($data); - - if (!$validator->isValid($new->getPermissions())) { // Check if user has write access to this document - throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $new = $this->encode($new); - - $validator = new Structure($this); - - if (!$validator->isValid($new)) { // Make sure updated structure still apply collection rules (if any) - throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $new = new Document($this->adapter->updateDocument($new->getArrayCopy())); - - $new = $this->decode($new); - - return $new; - } - - /** - * @param array $data - * - * @return Document|false - * - * @throws Exception - */ - public function overwriteDocument(array $data) - { - if (!isset($data['$id'])) { - throw new Exception('Must define $id attribute'); - } - - $document = $this->getDocument($data['$id']); // TODO make sure user don\'t need read permission for write operations - - $validator = new Authorization($document, 'write'); - - if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document - throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $new = new Document($data); - - if (!$validator->isValid($new->getPermissions())) { // Check if user has write access to this document - throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $new = $this->encode($new); - - $validator = new Structure($this); - - if (!$validator->isValid($new)) { // Make sure updated structure still apply collection rules (if any) - throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false; - } - - $new = new Document($this->adapter->updateDocument($new->getArrayCopy())); - - $new = $this->decode($new); - - return $new; - } - - /** - * @param string $id - * - * @return Document|false - * - * @throws AuthorizationException - */ - public function deleteDocument(string $id) - { - $document = $this->getDocument($id); - - $validator = new Authorization($document, 'write'); - - if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document - throw new AuthorizationException($validator->getDescription()); - } - - return new Document($this->adapter->deleteDocument($id)); - } - - /** - * @param int $key - * - * @return Document|false - * - * @throws AuthorizationException - */ - public function deleteUniqueKey($key) - { - return new Document($this->adapter->deleteUniqueKey($key)); - } - - /** - * @param int $key - * - * @return Document|false - * - * @throws AuthorizationException - */ - public function addUniqueKey($key) - { - return new Document($this->adapter->addUniqueKey($key)); - } - - /** - * @return array - */ - public function getDebug() - { - return $this->adapter->getDebug(); - } - - /** - * @return int - */ - public function getSum() - { - $debug = $this->getDebug(); - - return (isset($debug['sum'])) ? $debug['sum'] : 0; - } - - /** - * @param array $options - * - * @return int - */ - public function getCount(array $options) - { - $options = \array_merge([ - 'filters' => [], - ], $options); - - $results = $this->adapter->getCount($options); - - return $results; - } - - /** - * @param string $key - * @param string $value - * - * @return self - */ - public function setMock($key, $value): self - { - $this->mocks[$key] = $value; - - return $this; - } - - /** - * @param array $mocks - * - * @return self - */ - public function setMocks(array $mocks): self - { - $this->mocks = $mocks; - - return $this; - } - - /** - * @return array - */ - public function getMocks() - { - return $this->mocks; - } - - /** - * Add Attribute Filter - * - * @param string $name - * @param callable $encode - * @param callable $decode - * - * @return void - */ - public static function addFilter(string $name, callable $encode, callable $decode): void - { - self::$filters[$name] = [ - 'encode' => $encode, - 'decode' => $decode, - ]; - } - - /** - * Disable Attribute decoding - * - * @return void - */ - public static function disableFilters(): void - { - self::$statusFilters = false; - } - - /** - * Enable Attribute decoding - * - * @return void - */ - public static function enableFilters(): void - { - self::$statusFilters = true; - } - - public function encode(Document $document):Document - { - if (!self::$statusFilters) { - return $document; - } - - $collection = $this->getDocument($document->getCollection(), true, false); - $rules = $collection->getAttribute('rules', []); - - foreach ($rules as $key => $rule) { - $key = $rule->getAttribute('key', null); - $type = $rule->getAttribute('type', null); - $array = $rule->getAttribute('array', false); - $filters = $rule->getAttribute('filter', []); - $value = $document->getAttribute($key, null); - - if (($value !== null)) { - if ($type === self::SYSTEM_VAR_TYPE_DOCUMENT) { - if ($array) { - $list = []; - foreach ($value as $child) { - $list[] = $this->encode($child); - } - - $document->setAttribute($key, $list); - } else { - $document->setAttribute($key, $this->encode($value)); - } - } else { - foreach ($filters as $filter) { - $value = $this->encodeAttribute($filter, $value); - $document->setAttribute($key, $value); - } - } - } - } - - return $document; - } - - public function decode(Document $document):Document - { - if (!self::$statusFilters) { - return $document; - } - - $collection = $this->getDocument($document->getCollection(), true, false); - $rules = $collection->getAttribute('rules', []); - - foreach ($rules as $key => $rule) { - $key = $rule->getAttribute('key', null); - $type = $rule->getAttribute('type', null); - $array = $rule->getAttribute('array', false); - $filters = $rule->getAttribute('filter', []); - $value = $document->getAttribute($key, null); - - if (($value !== null)) { - if ($type === self::SYSTEM_VAR_TYPE_DOCUMENT) { - if ($array) { - $list = []; - foreach ($value as $child) { - $list[] = $this->decode($child); - } - - $document->setAttribute($key, $list); - } else { - $document->setAttribute($key, $this->decode($value)); - } - } else { - foreach (array_reverse($filters) as $filter) { - $value = $this->decodeAttribute($filter, $value); - $document->setAttribute($key, $value); - } - } - } - } - - return $document; - } - - /** - * Encode Attribute - * - * @param string $name - * @param mixed $value - */ - protected static function encodeAttribute(string $name, $value) - { - if (!isset(self::$filters[$name])) { - return $value; - throw new Exception("Filter '{$name}' not found"); - } - - try { - $value = self::$filters[$name]['encode']($value); - } catch (\Throwable $th) { - $value = null; - } - - return $value; - } - - /** - * Decode Attribute - * - * @param string $name - * @param mixed $value - */ - protected static function decodeAttribute(string $name, $value) - { - if (!isset(self::$filters[$name])) { - return $value; - throw new Exception("Filter '{$name}' not found"); - } - - try { - $value = self::$filters[$name]['decode']($value); - } catch (\Throwable $th) { - $value = null; - } - - return $value; - } - - /** - * Get Last Modified. - * - * Return Unix timestamp of last time a node queried in current session has been changed - * - * @return int - */ - public function lastModified() - { - return $this->adapter->lastModified(); - } -} diff --git a/src/Appwrite/Database/Document.php b/src/Appwrite/Database/Document.php deleted file mode 100644 index 94c38b7b30..0000000000 --- a/src/Appwrite/Database/Document.php +++ /dev/null @@ -1,274 +0,0 @@ - &$value) { - if (\is_array($value)) { - if ((isset($value['$id']) || isset($value['$collection'])) && (!$value instanceof self)) { - $input[$key] = new self($value); - } else { - foreach ($value as $childKey => $child) { - if ((isset($child['$id']) || isset($child['$collection'])) && (!$child instanceof self)) { - $value[$childKey] = new self($child); - } - } - } - } - } - - parent::__construct($input, $flags, $iterator_class); - } - - /** - * @return string|null - */ - public function getId() - { - return $this->getAttribute('$id', null); - } - - /** - * @return string - */ - public function getCollection() - { - return $this->getAttribute('$collection', null); - } - - /** - * @return array - */ - public function getPermissions() - { - return $this->getAttribute('$permissions', []); - } - - /** - * Get Attribute. - * - * Method for getting a specific fields attribute. If $name is not found $default value will be returned. - * - * @param string $name - * @param mixed $default - * - * @return mixed - */ - public function getAttribute($name, $default = null) - { - $name = \explode('.', $name); - - $temp = &$this; - - foreach ($name as $key) { - if (!isset($temp[$key])) { - return $default; - } - - $temp = &$temp[$key]; - } - - return $temp; - } - - /** - * Get Document Attributes - * - * @return array - */ - public function getAttributes(): array - { - $attributes = []; - - foreach ($this as $attribute => $value) { - if(array_key_exists($attribute, ['$id' => true, '$permissions' => true, '$collection' => true, '$execute' => []])) { - continue; - } - - $attributes[$attribute] = $value; - } - - return $attributes; - } - - /** - * Set Attribute. - * - * Method for setting a specific field attribute - * - * @param string $key - * @param mixed $value - * @param string $type - * - * @return mixed - */ - public function setAttribute($key, $value, $type = self::SET_TYPE_ASSIGN) - { - switch ($type) { - case self::SET_TYPE_ASSIGN: - $this[$key] = $value; - break; - case self::SET_TYPE_APPEND: - $this[$key] = (!isset($this[$key]) || !\is_array($this[$key])) ? [] : $this[$key]; - \array_push($this[$key], $value); - break; - case self::SET_TYPE_PREPEND: - $this[$key] = (!isset($this[$key]) || !\is_array($this[$key])) ? [] : $this[$key]; - \array_unshift($this[$key], $value); - break; - } - - return $this; - } - - /** - * Remove Attribute. - * - * Method for removing a specific field attribute - * - * @param string $key - * @param mixed $value - * @param string $type - * - * @return mixed - */ - public function removeAttribute($key) - { - if (isset($this[$key])) { - unset($this[$key]); - } - - return $this; - } - - /** - * Search. - * - * Get array child by key and value match - * - * @param $key - * @param $value - * @param array|null $scope - * - * @return Document|Document[]|mixed|null|array - */ - public function search($key, $value, $scope = null) - { - $array = (!\is_null($scope)) ? $scope : $this; - - if (\is_array($array) || $array instanceof self) { - if (isset($array[$key]) && $array[$key] == $value) { - return $array; - } - - foreach ($array as $k => $v) { - if ((\is_array($v) || $v instanceof self) && (!empty($v))) { - $result = $this->search($key, $value, $v); - - if (!empty($result)) { - return $result; - } - } else { - if ($k === $key && $v === $value) { - return $array; - } - } - } - } - - if ($array === $value) { - return $array; - } - - return; - } - - /** - * Checks if document has data. - * - * @return bool - */ - public function isEmpty() - { - return empty($this->getId()); - } - - /** - * Checks if a document key is set. - * - * @param string $key - * - * @return bool - */ - public function isSet($key) - { - return isset($this[$key]); - } - - /** - * Get Array Copy. - * - * Outputs entity as a PHP array - * - * @param array $whitelist - * @param array $blacklist - * - * @return array - */ - public function getArrayCopy(array $whitelist = [], array $blacklist = []): array - { - $array = parent::getArrayCopy(); - - $output = []; - - foreach ($array as $key => &$value) { - if (!empty($whitelist) && !\in_array($key, $whitelist)) { // Export only whitelisted fields - continue; - } - - if (!empty($blacklist) && \in_array($key, $blacklist)) { // Don't export blacklisted fields - continue; - } - - if ($value instanceof self) { - $output[$key] = $value->getArrayCopy($whitelist, $blacklist); - } elseif (\is_array($value)) { - foreach ($value as $childKey => &$child) { - if ($child instanceof self) { - $output[$key][$childKey] = $child->getArrayCopy($whitelist, $blacklist); - } else { - $output[$key][$childKey] = $child; - } - } - - if (empty($value)) { - $output[$key] = $value; - } - } else { - $output[$key] = $value; - } - } - - return $output; - } -} diff --git a/src/Appwrite/Database/Exception/Authorization.php b/src/Appwrite/Database/Exception/Authorization.php deleted file mode 100644 index e87e797079..0000000000 --- a/src/Appwrite/Database/Exception/Authorization.php +++ /dev/null @@ -1,7 +0,0 @@ - true]; - - /** - * @var Document - */ - protected $document; - - /** - * @var string - */ - protected $action = ''; - - /** - * @var string - */ - protected $message = 'Authorization Error'; - - /** - * Structure constructor. - * - * @param Document $document - * @param string $action - */ - public function __construct(Document $document, $action) - { - $this->document = $document; - $this->action = $action; - } - - /** - * Get Description. - * - * Returns validator description - * - * @return string - */ - public function getDescription(): string - { - return $this->message; - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param mixed $permissions - * - * @return bool - */ - public function isValid($permissions): bool - { - if (!self::$status) { - return true; - } - - if (!isset($permissions[$this->action])) { - $this->message = 'Missing action key: "'.$this->action.'"'; - - return false; - } - - $permission = null; - - foreach ($permissions[$this->action] as $permission) { - $permission = \str_replace(':{self}', ':'.$this->document->getId(), $permission); - - if (\array_key_exists($permission, self::$roles)) { - return true; - } - } - - $this->message = 'Missing "'.$this->action.'" permission for role "'.$permission.'". Only this scopes "'.\json_encode(self::getRoles()).'" are given and only this are allowed "'.\json_encode($permissions[$this->action]).'".'; - - return false; - } - - /** - * @param string $role - * - * @return void - */ - public static function setRole(string $role): void - { - self::$roles[$role] = true; - } - - /** - * @param string $role - * - * @return void - */ - public static function unsetRole(string $role): void - { - unset(self::$roles[$role]); - } - - /** - * @return array - */ - public static function getRoles(): array - { - return \array_keys(self::$roles); - } - - /** - * @return void - */ - public static function cleanRoles(): void - { - self::$roles = []; - } - - /** - * @param string $role - * - * @return bool - */ - public static function isRole(string $role): bool - { - return (\array_key_exists($role, self::$roles)); - } - - /** - * @var bool - */ - public static $status = true; - - /** - * Default value in case we need - * to reset Authorization status - * - * @var bool - */ - public static $statusDefault = true; - - /** - * Change default status. - * This will be used for the - * value set on the self::reset() method - * - * @return void - */ - public static function setDefaultStatus($status): void - { - self::$statusDefault = $status; - self::$status = $status; - } - - /** - * Enable Authorization checks - * - * @return void - */ - public static function enable(): void - { - self::$status = true; - } - - /** - * Disable Authorization checks - * - * @return void - */ - public static function disable(): void - { - self::$status = false; - } - - /** - * Disable Authorization checks - * - * @return void - */ - public static function reset(): void - { - self::$status = self::$statusDefault; - } - - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_ARRAY; - } -} diff --git a/src/Appwrite/Database/Validator/Collection.php b/src/Appwrite/Database/Validator/Collection.php deleted file mode 100644 index 139ff20cd0..0000000000 --- a/src/Appwrite/Database/Validator/Collection.php +++ /dev/null @@ -1,62 +0,0 @@ -collections = $collections; - $this->merge = $merge; - - return parent::__construct($database); - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param mixed $document - * - * @return bool - */ - public function isValid($document): bool - { - $document = new Document( - \array_merge($this->merge, ($document instanceof Document) ? $document->getArrayCopy() : $document) - ); - - if (\is_null($document->getCollection())) { - $this->message = 'Missing collection attribute $collection'; - - return false; - } - - if (!\in_array($document->getCollection(), $this->collections)) { - $this->message = 'Collection is not allowed'; - - return false; - } - - return parent::isValid($document); - } -} diff --git a/src/Appwrite/Database/Validator/DocumentId.php b/src/Appwrite/Database/Validator/DocumentId.php deleted file mode 100644 index 988497cfe6..0000000000 --- a/src/Appwrite/Database/Validator/DocumentId.php +++ /dev/null @@ -1,105 +0,0 @@ -database = $database; - $this->collection = $collection; - } - - /** - * Get Description. - * - * Returns validator description - * - * @return string - */ - public function getDescription(): string - { - return $this->message; - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param $value - * - * @return bool - */ - public function isValid($id): bool - { - $document = $this->database->getDocument($id); - - if (!$document) { - return false; - } - - if (!$document instanceof Document) { - return false; - } - - if (!$document->getId()) { - return false; - } - - if ($document->getCollection() !== $this->collection) { - return false; - } - - return true; - } - - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_STRING; - } -} diff --git a/src/Appwrite/Database/Validator/Key.php b/src/Appwrite/Database/Validator/Key.php deleted file mode 100644 index 328f06fec6..0000000000 --- a/src/Appwrite/Database/Validator/Key.php +++ /dev/null @@ -1,74 +0,0 @@ -message; - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param $value - * - * @return bool - */ - public function isValid($value): bool - { - if (!\is_string($value)) { - return false; - } - - if (\preg_match('/[^A-Za-z0-9\-\_]/', $value)) { - return false; - } - - if (\mb_strlen($value) > 32) { - return false; - } - - return true; - } - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_STRING; - } -} diff --git a/src/Appwrite/Database/Validator/Permissions.php b/src/Appwrite/Database/Validator/Permissions.php deleted file mode 100644 index 1419c3e7c7..0000000000 --- a/src/Appwrite/Database/Validator/Permissions.php +++ /dev/null @@ -1,100 +0,0 @@ -document = $document; - } - - /** - * Get Description. - * - * Returns validator description - * - * @return string - */ - public function getDescription(): string - { - return $this->message; - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param mixed $value - * - * @return bool - */ - public function isValid($value): bool - { - if (!\is_array($value) && !empty($value)) { - $this->message = 'Invalid permissions data structure'; - - return false; - } - - foreach ($value as $action => $roles) { - if (!\in_array($action, ['read', 'write', 'execute'])) { - $this->message = 'Unknown action ("'.$action.'")'; - - return false; - } - - foreach ($roles as $role) { - if (!\is_string($role)) { - $this->message = 'Permissions role must be of type string.'; - - return false; - } - } - } - - return true; - } - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_ARRAY; - } -} diff --git a/src/Appwrite/Database/Validator/Structure.php b/src/Appwrite/Database/Validator/Structure.php deleted file mode 100644 index 6cd143a8f7..0000000000 --- a/src/Appwrite/Database/Validator/Structure.php +++ /dev/null @@ -1,313 +0,0 @@ - '$id', - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'key' => '$id', - 'type' => 'id', - 'default' => null, - 'required' => false, - 'array' => false, - ], - [ - 'label' => '$collection', - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'key' => '$collection', - 'type' => 'id', - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - 'label' => '$permissions', - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'key' => '$permissions', - 'type' => 'permissions', - 'default' => null, - 'required' => true, - 'array' => false, - ], - [ - 'label' => '$createdAt', - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'key' => '$createdAt', - 'type' => 'numeric', - 'default' => null, - 'required' => false, - 'array' => false, - ], - [ - 'label' => '$updatedAt', - '$collection' => Database::SYSTEM_COLLECTION_RULES, - 'key' => '$updatedAt', - 'type' => 'numeric', - 'default' => null, - 'required' => false, - 'array' => false, - ], - ]; - - /** - * @var string - */ - protected $message = 'General Error'; - - /** - * Structure constructor. - * - * @param Database $database - */ - public function __construct(Database $database) - { - $this->database = $database; - } - - /** - * Get Description. - * - * Returns validator description - * - * @return string - */ - public function getDescription(): string - { - return 'Invalid document structure: '.$this->message; - } - - /** - * Is valid. - * - * Returns true if valid or false if not. - * - * @param mixed $document - * - * @return bool - */ - public function isValid($document): bool - { - $document = (\is_array($document)) ? new Document($document) : $document; - - $this->id = $document->getId(); - - if (\is_null($document->getCollection())) { - $this->message = 'Missing collection attribute $collection'; - - return false; - } - - $collection = $this->getCollection($document->getCollection()); - - if (\is_null($collection->getId()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) { - $this->message = 'Collection not found'; - - return false; - } - - $array = $document->getArrayCopy(); - $rules = \array_merge($this->rules, $collection->getAttribute('rules', [])); - - foreach ($rules as $rule) { // Check all required keys are set - if (isset($rule['key']) && !isset($array[$rule['key']]) - && isset($rule['required']) && true == $rule['required']) { - $this->message = 'Missing required key "'.$rule['key'].'"'; - - return false; - } - } - - foreach ($array as $key => $value) { - $rule = $collection->search('key', $key, $rules); - - if (!$rule) { - continue; - } - - $ruleType = $rule['type'] ?? ''; - $ruleRequired = $rule['required'] ?? true; - $ruleArray = $rule['array'] ?? false; - $validator = null; - - switch ($ruleType) { - case self::RULE_TYPE_ID: - $validator = new UID(); - break; - case self::RULE_TYPE_PERMISSIONS: - $validator = new Permissions($document); //$validator = ($this->forcePermissions) ? new Authorization($original, 'write') : new Validator\Mock(); - break; - case self::RULE_TYPE_KEY: - $validator = new Key(); - break; - case self::RULE_TYPE_TEXT: - case self::RULE_TYPE_MARKDOWN: - $validator = new Validator\Text(0); - break; - case self::RULE_TYPE_NUMERIC: - $validator = new Validator\Numeric(); - break; - case self::RULE_TYPE_BOOLEAN: - $validator = new Validator\Boolean(); - break; - case self::RULE_TYPE_EMAIL: - $validator = new NetworkValidator\Email(); - break; - case self::RULE_TYPE_URL: - $validator = new NetworkValidator\URL(); - break; - case self::RULE_TYPE_IP: - $validator = new NetworkValidator\IP(); - break; - case self::RULE_TYPE_WILDCARD: - $validator = new Validator\Wildcard(); - break; - case self::RULE_TYPE_DOCUMENT: - $validator = new Collection($this->database, (isset($rule['list'])) ? $rule['list'] : []); - $value = $document->getAttribute($key); - break; - case self::RULE_TYPE_DOCUMENTID: - $validator = new DocumentId($this->database, (isset($rule['list']) && isset($rule['list'][0])) ? $rule['list'][0] : ''); - $value = $document->getAttribute($key); - break; - case self::RULE_TYPE_FILEID: - $validator = new DocumentId($this->database, Database::SYSTEM_COLLECTION_FILES); - $value = $document->getAttribute($key); - break; - } - - if (empty($validator)) { // Error creating validator for property - $this->message = 'Unknown rule type "'.$ruleType.'" for property "'.\htmlspecialchars($key, ENT_QUOTES, 'UTF-8').'"'; - - if (empty($ruleType)) { - $this->message = 'Unknown property "'.$key.'" type'. - '. Make sure to follow '.\strtolower($collection->getAttribute('name', 'unknown')).' collection structure'; - } - - return false; - } - - if ($ruleRequired && ('' === $value || null === $value)) { - $this->message = 'Required property "'.$key.'" has no value'; - - return false; - } - - if (!$ruleRequired && empty($value)) { - unset($array[$key]); - unset($rule); - - continue; - } - - if ($ruleArray) { // Array of values validation - if (!\is_array($value)) { - $this->message = 'Property "'.$key.'" must be an array'; - - return false; - } - - // TODO add is required check here - - foreach ($value as $node) { - if (!$validator->isValid($node)) { // Check if property is valid, if not required can also be empty - $this->message = 'Property "'.$key.'" has invalid input. '.$validator->getDescription(); - - return false; - } - } - } else { // Single value validation - if ((!$validator->isValid($value)) && !('' === $value && !$ruleRequired)) { // Error when value is not valid, and is not optional and empty - $this->message = 'Property "'.$key.'" has invalid input. '.$validator->getDescription(); - - return false; - } - } - - unset($array[$key]); - unset($rule); - } - - if (!empty($array)) { // No fields should be left unvalidated - $this->message = 'Unknown properties are not allowed ('.\implode(', ', \array_keys($array)).') for this collection'. - '. Make sure to follow '.\strtolower($collection->getAttribute('name', 'unknown')).' collection structure'; - - return false; - } - - return true; - } - - /** - * Get Collection - * - * Get Collection by unique ID - * - * @return Document - */ - protected function getCollection($id): Document - { - return $this->database->getDocument($id); - } - - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_OBJECT; - } -} diff --git a/src/Appwrite/Database/Validator/UID.php b/src/Appwrite/Database/Validator/UID.php deleted file mode 100644 index ebab6b4628..0000000000 --- a/src/Appwrite/Database/Validator/UID.php +++ /dev/null @@ -1,70 +0,0 @@ - 32) { - return false; - } - - return true; - } - - /** - * Is array - * - * Function will return true if object is array. - * - * @return bool - */ - public function isArray(): bool - { - return false; - } - - /** - * Get Type - * - * Returns validator type. - * - * @return string - */ - public function getType(): string - { - return self::TYPE_STRING; - } -} diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 777d389279..d00318f212 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -2,107 +2,58 @@ namespace Appwrite\Migration; -use Appwrite\Database\Document as OldDocument; -use Appwrite\Database\Database as OldDatabase; -use PDO; -use Redis; use Swoole\Runtime; +use Utopia\Database\Document; +use Utopia\Database\Database; use Utopia\CLI\Console; +use Utopia\Config\Config; use Utopia\Exception; abstract class Migration { - /** - * @var array - */ - protected array $options; - - /** - * @var PDO - */ - protected PDO $db; - - /** - * @var Redis - */ - protected Redis $cache; - /** * @var int */ - protected int $limit = 500; + protected int $limit = 100; /** - * @var OldDocument + * @var Document */ - protected OldDocument $project; + protected Document $project; /** - * @var OldDatabase + * @var Database */ - protected OldDatabase $oldProjectDB; + protected Database $projectDB; /** - * @var OldDatabase + * @var Database */ - protected OldDatabase $oldConsoleDB; + protected Database $consoleDB; /** * @var array */ public static array $versions = [ - '0.6.0' => 'V05', - '0.7.0' => 'V06', - '0.8.0' => 'V07', - '0.9.0' => 'V08', - '0.9.1' => 'V08', - '0.9.2' => 'V08', - '0.9.3' => 'V08', - '0.9.4' => 'V08', - '0.10.0' => 'V09', - '0.10.1' => 'V09', - '0.10.2' => 'V09', - '0.10.3' => 'V09', - '0.10.4' => 'V09', - '0.11.0' => 'V10', - '0.12.0' => 'V11', - '0.12.1' => 'V11', + '0.13.0' => 'V12', ]; - /** - * Migration constructor. - * - * @param PDO $db - * @param Redis|null $cache - * @param array $options - * @return void - */ - public function __construct(PDO $db, Redis $cache = null, array $options = []) - { - $this->options = $options; - $this->db = $db; - if (!is_null($cache)) { - $this->cache = $cache; - } - } - /** * Set project for migration. * - * @param OldDocument $project - * @param OldDatabase $projectDB - * @param OldDatabase $oldConsoleDB + * @param Document $project + * @param Database $projectDB + * @param Database $oldConsoleDB * * @return self */ - public function setProject(OldDocument $project, OldDatabase $projectDB, OldDatabase $oldConsoleDB): self + public function setProject(Document $project, Database $projectDB, Database $consoleDB): self { $this->project = $project; + $this->projectDB = $projectDB; + $this->projectDB->setNamespace('_project_' . $this->project->getId()); - $this->oldProjectDB = $projectDB; - $this->oldProjectDB->setNamespace('app_' . $project->getId()); - - $this->oldConsoleDB = $oldConsoleDB; + $this->consoleDB = $consoleDB; return $this; } @@ -114,52 +65,72 @@ abstract class Migration */ public function forEachDocument(callable $callback): void { - $sum = $this->limit; - $offset = 0; + Runtime::enableCoroutine(SWOOLE_HOOK_ALL); - while ($sum >= $this->limit) { - $all = $this->projectDB->getCollection([ - 'limit' => $this->limit, - 'offset' => $offset, - 'orderType' => 'DESC', - ]); + /** @var array $collections */ + $collections = Config::getParam('collections', []); - $sum = \count($all); - Runtime::enableCoroutine(SWOOLE_HOOK_ALL); + foreach ($collections as $collection) { + $sum = 0; + $nextDocument = null; + $collectionCount = $this->projectDB->count($collection['$id']); + Console::log('Migrating Collection ' . $collection['$id'] . ':'); - Console::log('Migrating: ' . $offset . ' / ' . $this->projectDB->getSum()); - \Co\run(function () use ($all, $callback) { - foreach ($all as $document) { - go(function () use ($document, $callback) { - if (empty($document->getId()) || empty($document->getCollection())) { - if ($document->getCollection() !== 0) { - Console::warning('Skipped Document due to missing ID or Collection.'); + do { + $documents = $this->projectDB->find($collection['$id'], limit: $this->limit, cursor: $nextDocument); + $count = count($documents); + $sum += $count; + + Console::log($sum . ' / ' . $collectionCount); + + \Co\run(function (array $documents, callable $callback) { + foreach ($documents as $document) { + go(function (Document $document, callable $callback) { + if (empty($document->getId()) || empty($document->getCollection())) { + return; } - return; - } - $old = $document->getArrayCopy(); - $new = call_user_func($callback, $document); + $old = $document->getArrayCopy(); + $new = call_user_func($callback, $document); - if (!$this->check_diff_multi($new->getArrayCopy(), $old)) { - return; - } + foreach ($document as &$attr) { + if ($attr instanceof Document) { + $attr = call_user_func($callback, $attr); + } - try { - $new = $this->projectDB->overwriteDocument($new->getArrayCopy()); - } catch (\Throwable $th) { - Console::error('Failed to update document: ' . $th->getMessage()); - return; - - if ($document && $new->getId() !== $document->getId()) { - throw new Exception('Duplication Error'); + if (\is_array($attr)) { + foreach ($attr as &$child) { + if ($child instanceof Document) { + $child = call_user_func($callback, $child); + } + } + } } - } - }); + + if (!$this->check_diff_multi($new->getArrayCopy(), $old)) { + return; + } + + try { + $new = $this->projectDB->updateDocument($document->getCollection(), $document->getId(), $document); + } catch (\Throwable $th) { + Console::error('Failed to update document: ' . $th->getMessage()); + return; + + if ($document && $new->getId() !== $document->getId()) { + throw new Exception('Duplication Error'); + } + } + }, $document, $callback); + } + }, $documents, $callback); + + if ($count !== $this->limit) { + $nextDocument = null; + } else { + $nextDocument = end($documents); } - }); - - $offset += $this->limit; + } while (!is_null($nextDocument)); } } diff --git a/src/Appwrite/Migration/Version/V05.php b/src/Appwrite/Migration/Version/V05.php deleted file mode 100644 index bcabe6e0a1..0000000000 --- a/src/Appwrite/Migration/Version/V05.php +++ /dev/null @@ -1,126 +0,0 @@ -db; - $project = $this->project; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - - // Update all documents $uid -> $id - - $this->forEachDocument([$this, 'fixDocument']); - - $schema = $_SERVER['_APP_DB_SCHEMA'] ?? ''; - - try { - $statement = $db->prepare(" - - CREATE TABLE IF NOT EXISTS `template.database.unique` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `key` varchar(128) DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `index1` (`key`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - - CREATE TABLE IF NOT EXISTS `{$schema}`.`app_{$project->getId()}.database.unique` LIKE `template.database.unique`; - ALTER TABLE `{$schema}`.`app_{$project->getId()}.audit.audit` DROP COLUMN IF EXISTS `userType`; - ALTER TABLE `{$schema}`.`app_{$project->getId()}.audit.audit` DROP INDEX IF EXISTS `index_1`; - ALTER TABLE `{$schema}`.`app_{$project->getId()}.audit.audit` ADD INDEX IF NOT EXISTS `index_1` (`userId` ASC); - "); - - $statement->closeCursor(); - - $statement->execute(); - } catch (\Exception $e) { - Console::error('Failed to alter table for project: ' . $project->getId() . ' with message: ' . $e->getMessage() . '/'); - } - } - - protected function fixDocument(Document $document) - { - $providers = Config::getParam('providers'); - - switch ($document->getAttribute('$collection')) { - case Database::SYSTEM_COLLECTION_PROJECTS: - foreach ($providers as $key => $provider) { - if (!empty($document->getAttribute('usersOauth' . \ucfirst($key) . 'Appid'))) { - $document - ->setAttribute('usersOauth2' . \ucfirst($key) . 'Appid', $document->getAttribute('usersOauth' . \ucfirst($key) . 'Appid', '')) - ->removeAttribute('usersOauth' . \ucfirst($key) . 'Appid'); - } - - if (!empty($document->getAttribute('usersOauth' . \ucfirst($key) . 'Secret'))) { - $document - ->setAttribute('usersOauth2' . \ucfirst($key) . 'Secret', $document->getAttribute('usersOauth' . \ucfirst($key) . 'Secret', '')) - ->removeAttribute('usersOauth' . \ucfirst($key) . 'Secret'); - } - } - $document->setAttribute('security', $document->getAttribute('security') ? true : false); - break; - - case Database::SYSTEM_COLLECTION_TASKS: - $document->setAttribute('security', $document->getAttribute('security') ? true : false); - break; - - case Database::SYSTEM_COLLECTION_USERS: - foreach ($providers as $key => $provider) { - if (!empty($document->getAttribute('oauth' . \ucfirst($key)))) { - $document - ->setAttribute('oauth2' . \ucfirst($key), $document->getAttribute('oauth' . \ucfirst($key), '')) - ->removeAttribute('oauth' . \ucfirst($key)); - } - - if (!empty($document->getAttribute('oauth' . \ucfirst($key) . 'AccessToken'))) { - $document - ->setAttribute('oauth2' . \ucfirst($key) . 'AccessToken', $document->getAttribute('oauth' . \ucfirst($key) . 'AccessToken', '')) - ->removeAttribute('oauth' . \ucfirst($key) . 'AccessToken'); - } - } - - if ($document->getAttribute('confirm', null) !== null) { - $document - ->setAttribute('emailVerification', $document->getAttribute('confirm', $document->getAttribute('emailVerification', false))) - ->removeAttribute('confirm'); - } - break; - - case Database::SYSTEM_COLLECTION_PLATFORMS: - if ($document->getAttribute('url', null) !== null) { - $document - ->setAttribute('hostname', \parse_url($document->getAttribute('url', $document->getAttribute('hostname', '')), PHP_URL_HOST)) - ->removeAttribute('url'); - } - break; - } - - $document - ->setAttribute('$id', $document->getAttribute('$uid', $document->getAttribute('$id'))) - ->removeAttribute('$uid'); - - foreach ($document as &$attr) { // Handle child documents - if ($attr instanceof Document) { - $attr = $this->fixDocument($attr); - } - - if (\is_array($attr)) { - foreach ($attr as &$child) { - if ($child instanceof Document) { - $child = $this->fixDocument($child); - } - } - } - } - - return $document; - } -} diff --git a/src/Appwrite/Migration/Version/V06.php b/src/Appwrite/Migration/Version/V06.php deleted file mode 100644 index 45bd284f2e..0000000000 --- a/src/Appwrite/Migration/Version/V06.php +++ /dev/null @@ -1,58 +0,0 @@ -project; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - - $this->projectDB->disableFilters(); - $this->forEachDocument([$this, 'fixDocument']); - $this->projectDB->enableFilters(); - } - - protected function fixDocument(Document $document) - { - switch ($document->getAttribute('$collection')) { - case Database::SYSTEM_COLLECTION_USERS: - if ($document->isSet('password-update')) { - $document - ->setAttribute('passwordUpdate', $document->getAttribute('password-update', $document->getAttribute('passwordUpdate', ''))) - ->removeAttribute('password-update'); - } - break; - case Database::SYSTEM_COLLECTION_KEYS: - if ($document->getAttribute('secret', null)) { - $json = \json_decode($document->getAttribute('secret'), true); - if (is_array($json)) { - Console::log('Secret already encrypted. Skipped: ' . $document->getId()); - break; - } - - $key = App::getEnv('_APP_OPENSSL_KEY_V1'); - $iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM)); - $tag = null; - - $document->setAttribute('secret', json_encode([ - 'data' => OpenSSL::encrypt($document->getAttribute('secret'), OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag), - 'method' => OpenSSL::CIPHER_AES_128_GCM, - 'iv' => \bin2hex($iv), - 'tag' => \bin2hex($tag ?? ''), - 'version' => '1', - ])); - } - break; - } - return $document; - } -} diff --git a/src/Appwrite/Migration/Version/V07.php b/src/Appwrite/Migration/Version/V07.php deleted file mode 100644 index 3efd7d15cc..0000000000 --- a/src/Appwrite/Migration/Version/V07.php +++ /dev/null @@ -1,68 +0,0 @@ -project; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - - $this->forEachDocument([$this, 'fixDocument']); - } - - protected function fixDocument(Document $document) - { - $providers = Config::getParam('providers'); - - switch ($document->getAttribute('$collection')) { - case Database::SYSTEM_COLLECTION_USERS: - /** - * Remove deprecated OAuth2 properties in the Users Documents. - */ - foreach ($providers as $key => $provider) { - if (!empty($document->getAttribute('oauth2' . \ucfirst($key)))) { - $document->removeAttribute('oauth2' . \ucfirst($key)); - } - - if (!empty($document->getAttribute('oauth2' . \ucfirst($key) . 'AccessToken'))) { - $document->removeAttribute('oauth2' . \ucfirst($key) . 'AccessToken'); - } - } - /** - * Invalidate all Login Tokens, since they can't be migrated to the new structure. - * Reason for it is the missing distinction between E-Mail and OAuth2 tokens. - */ - $tokens = array_filter($document->getAttribute('tokens', []), function ($token) { - return ($token->getAttribute('type') != Auth::TOKEN_TYPE_LOGIN); - }); - $document->setAttribute('tokens', array_values($tokens)); - - break; - } - - foreach ($document as &$attr) { // Handle child documents - if ($attr instanceof Document) { - $attr = $this->fixDocument($attr); - } - - if (\is_array($attr)) { - foreach ($attr as &$child) { - if ($child instanceof Document) { - $child = $this->fixDocument($child); - } - } - } - } - - return $document; - } -} diff --git a/src/Appwrite/Migration/Version/V08.php b/src/Appwrite/Migration/Version/V08.php deleted file mode 100644 index fbc31c4df1..0000000000 --- a/src/Appwrite/Migration/Version/V08.php +++ /dev/null @@ -1,60 +0,0 @@ -project; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - - $this->forEachDocument([$this, 'fixDocument']); - } - - protected function fixDocument(Document $document) - { - switch ($document->getAttribute('$collection')) { - /** - * Rename env attribute to runtime. - */ - case Database::SYSTEM_COLLECTION_FUNCTIONS: - if ($document->isSet('env')) { - $document - ->setAttribute('runtime', $document->getAttribute('env', $document->getAttribute('env', ''))) - ->removeAttribute('env'); - } - - break; - /** - * Add version reference to database. - */ - case Database::SYSTEM_COLLECTION_PROJECTS: - $document->setAttribute('version', '0.9.0'); - - break; - } - - foreach ($document as &$attr) { - if ($attr instanceof Document) { - $attr = $this->fixDocument($attr); - } - - if (\is_array($attr)) { - foreach ($attr as &$child) { - if ($child instanceof Document) { - $child = $this->fixDocument($child); - } - } - } - } - - return $document; - } -} diff --git a/src/Appwrite/Migration/Version/V09.php b/src/Appwrite/Migration/Version/V09.php deleted file mode 100644 index 2d1411c4c3..0000000000 --- a/src/Appwrite/Migration/Version/V09.php +++ /dev/null @@ -1,48 +0,0 @@ -project; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - - $this->forEachDocument([$this, 'fixDocument']); - } - - protected function fixDocument(Document $document) - { - switch ($document->getAttribute('$collection')) { - /** - * Add version reference to database. - */ - case Database::SYSTEM_COLLECTION_PROJECTS: - $document->setAttribute('version', '0.10.0'); - - break; - } - - foreach ($document as &$attr) { - if ($attr instanceof Document) { - $attr = $this->fixDocument($attr); - } - - if (\is_array($attr)) { - foreach ($attr as &$child) { - if ($child instanceof Document) { - $child = $this->fixDocument($child); - } - } - } - } - - return $document; - } -} diff --git a/src/Appwrite/Migration/Version/V10.php b/src/Appwrite/Migration/Version/V10.php deleted file mode 100644 index 0760e3ff9d..0000000000 --- a/src/Appwrite/Migration/Version/V10.php +++ /dev/null @@ -1,48 +0,0 @@ -project; - Console::log('Migrating project: ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - - $this->forEachDocument([$this, 'fixDocument']); - } - - protected function fixDocument(Document $document) - { - switch ($document->getAttribute('$collection')) { - /** - * Add version reference to database. - */ - case Database::SYSTEM_COLLECTION_PROJECTS: - $document->setAttribute('version', '0.11.0'); - - break; - } - - foreach ($document as &$attr) { - if ($attr instanceof Document) { - $attr = $this->fixDocument($attr); - } - - if (\is_array($attr)) { - foreach ($attr as &$child) { - if ($child instanceof Document) { - $child = $this->fixDocument($child); - } - } - } - } - - return $document; - } -} diff --git a/src/Appwrite/Migration/Version/V11.php b/src/Appwrite/Migration/Version/V11.php deleted file mode 100644 index 896dce8f32..0000000000 --- a/src/Appwrite/Migration/Version/V11.php +++ /dev/null @@ -1,821 +0,0 @@ -options = array_map(fn ($option) => $option === 'yes' ? true : false, $this->options); - - if (!is_null($cache)) { - $this->cache->flushAll(); - $cacheAdapter = new Cache(new RedisCache($this->cache)); - $this->dbProject = new Database(new MariaDB($this->db), $cacheAdapter); // namespace is set on execution - $this->dbConsole = new Database(new MariaDB($this->db), $cacheAdapter); - - $this->dbProject->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $this->dbConsole->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $this->dbConsole->setNamespace('_project_console'); - } - - $this->newCollections = Config::getParam('collections', []); - $this->oldCollections = Config::getParam('collectionsold', []); - } - - public function execute(): void - { - Authorization::disable(); - Runtime::enableCoroutine(SWOOLE_HOOK_ALL); - - $oldProject = $this->project; - - $this->dbProject->setNamespace('_project_' . $oldProject->getId()); - $this->dbConsole->setNamespace('_project_console'); - - Console::info(''); - Console::info('------------------------------------'); - Console::info('Migrating project ' . $oldProject->getAttribute('name')); - Console::info('------------------------------------'); - - /** - * Create internal/external structure for projects and skip the console project. - */ - if ($oldProject->getId() !== 'console') { - try { - $project = $this->dbConsole->getDocument(collection: 'projects', id: $oldProject->getId()); - } catch (\Throwable $th) { - Console::error($th->getTraceAsString()); - } - - /** - * Migrate Project Document. - */ - if ($project->isEmpty()) { - $newProject = $this->fixDocument($oldProject); - $newProject->setAttribute('version', '0.12.0'); - $project = $this->dbConsole->createDocument('projects', $newProject); - Console::log('Created project document: ' . $oldProject->getAttribute('name') . ' (' . $oldProject->getId() . ')'); - } - - /** - * Create internal tables - */ - try { - Console::log('Created internal tables for : ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - $this->dbProject->createMetadata(); - } catch (\Throwable $th) { - } - - /** - * Create Audit tables - */ - if ($this->dbProject->getCollection(Audit::COLLECTION)->isEmpty()) { - $audit = new Audit($this->dbProject); - $audit->setup(); - Console::log('Created audit tables for : ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - } - - /** - * Create Abuse tables - */ - if ($this->dbProject->getCollection(TimeLimit::COLLECTION)->isEmpty()) { - $adapter = new TimeLimit("", 0, 1, $this->dbProject); - $adapter->setup(); - Console::log('Created abuse tables for : ' . $project->getAttribute('name') . ' (' . $project->getId() . ')'); - } - - /** - * Create internal collections for Project - */ - foreach ($this->newCollections as $key => $collection) { - if (!$this->dbProject->getCollection($key)->isEmpty()) continue; // Skip if project collection already exists - - $attributes = []; - $indexes = []; - - foreach ($collection['attributes'] as $attribute) { - $attributes[] = new Document([ - '$id' => $attribute['$id'], - 'type' => $attribute['type'], - 'size' => $attribute['size'], - 'required' => $attribute['required'], - 'signed' => $attribute['signed'], - 'array' => $attribute['array'], - 'filters' => $attribute['filters'], - ]); - } - - foreach ($collection['indexes'] as $index) { - $indexes[] = new Document([ - '$id' => $index['$id'], - 'type' => $index['type'], - 'attributes' => $index['attributes'], - 'lengths' => $index['lengths'], - 'orders' => $index['orders'], - ]); - } - - $this->dbProject->createCollection($key, $attributes, $indexes); - } - if ($this->options['migrateCollections']) { - $this->migrateExternalCollections(); - } - } else { - Console::log('Skipped console project migration.'); - } - - $sum = $this->limit; - $offset = 0; - $total = 0; - - /** - * Migrate internal documents - */ - while ($sum >= $this->limit) { - $all = $this->oldProjectDB->getCollection([ - 'limit' => $this->limit, - 'offset' => $offset, - 'orderType' => 'DESC', - 'filters' => [ - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_COLLECTIONS, - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_RULES, - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_TASKS, - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_PROJECTS, - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_CONNECTIONS, - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_RESERVED, - '$collection!=' . OldDatabase::SYSTEM_COLLECTION_TOKENS, - ] - ]); - - $sum = \count($all); - - Console::log('Migrating Internal Documents: ' . $offset . ' / ' . $this->oldProjectDB->getSum()); - - foreach ($all as $document) { - if ( - !array_key_exists($document->getCollection(), $this->oldCollections) - ) { - continue; - } - - $new = $this->fixDocument($document); - - if (is_null($new) || empty($new->getId())) { - Console::warning('Skipped Document due to missing ID.'); - continue; - } - - try { - if ($this->dbProject->getDocument($new->getCollection(), $new->getId())->isEmpty()) { - $this->dbProject->createDocument($new->getCollection(), $new); - } - } catch (\Throwable $th) { - Console::error("Failed to migrate document ({$new->getId()}) from collection ({$new->getCollection()}): " . $th->getMessage()); - continue; - } - } - - $offset += $this->limit; - $total += $sum; - } - Console::log('Migrated ' . $total . ' Internal Documents.'); - } - - /** - * Migrate external collections for Project - * - * @return void - * @throws Exception - * @throws Throwable - * @throws Limit - * @throws ExceptionAuthorization - * @throws Structure - */ - protected function migrateExternalCollections(): void - { - $sum = $this->limit; - $offset = 0; - - while ($sum >= $this->limit) { - $databaseCollections = $this->oldProjectDB->getCollection([ - 'limit' => $this->limit, - 'offset' => $offset, - 'orderType' => 'DESC', - 'filters' => [ - '$collection=' . OldDatabase::SYSTEM_COLLECTION_COLLECTIONS, - ] - ]); - - $sum = \count($databaseCollections); - Console::log('Migrating Collections: ' . $offset . ' / ' . $this->oldProjectDB->getSum()); - - foreach ($databaseCollections as $oldCollection) { - $id = $oldCollection->getId(); - $permissions = $oldCollection->getPermissions(); - $name = $oldCollection->getAttribute('name'); - $newCollection = $this->dbProject->getCollection('collection_' . $id); - - if ($newCollection->isEmpty()) { - $this->dbProject->createCollection('collection_' . $id); - /** - * Migrate permissions - */ - $read = $this->migrateWildcardPermissions($permissions['read'] ?? []); - $write = $this->migrateWildcardPermissions($permissions['write'] ?? []); - - /** - * Suffix collection name with a subsequent number to make it unique if possible. - */ - $suffix = 1; - while ($this->dbProject->findOne('collections', [ - new Query('name', Query::TYPE_EQUAL, [$name]) - ])) { - $name .= ' - ' . $suffix++; - } - - $this->dbProject->createDocument('collections', new Document([ - '$id' => $id, - '$read' => [], - '$write' => [], - 'permission' => 'document', - 'dateCreated' => time(), - 'dateUpdated' => time(), - 'name' => substr($name, 0, 256), - 'enabled' => true, - 'search' => implode(' ', [$id, $name]), - ])); - } else { - Console::warning('Skipped Collection ' . $newCollection->getId() . ' from ' . $newCollection->getCollection()); - } - - /** - * Migrate collection rules to attributes - */ - $attributes = $this->getCollectionAttributes($oldCollection); - - foreach ($attributes as $attribute) { - try { - $this->dbProject->createAttribute( - collection: 'collection_' . $attribute['$collection'], - id: $attribute['$id'], - type: $attribute['type'], - size: $attribute['size'], - required: $attribute['required'], - default: $attribute['default'], - signed: $attribute['signed'], - array: $attribute['array'], - format: $attribute['format'] ?? null, - formatOptions: $attribute['formatOptions'] ?? [], - filters: $attribute['filters'] - ); - $this->dbProject->createDocument('attributes', new Document([ - '$id' => $attribute['$collection'] . '_' . $attribute['$id'], - 'key' => $attribute['$id'], - 'collectionId' => $attribute['$collection'], - 'type' => $attribute['type'], - 'status' => 'available', - 'size' => $attribute['size'], - 'required' => $attribute['required'], - 'signed' => $attribute['signed'], - 'default' => $attribute['default'], - 'array' => $attribute['array'], - 'format' => $attribute['format'] ?? null, - 'formatOptions' => $attribute['formatOptions'] ?? null, - 'filters' => $attribute['filters'] - ])); - - Console::log('Created "' . $attribute['$id'] . '" attribute in collection: ' . $name); - } catch (\Throwable $th) { - Console::log($th->getMessage() . ' - ("' . $attribute['$id'] . '" attribute in collection ' . $name . ')'); - } - } - if ($this->options['migrateDocuments']) { - $this->migrateExternalDocuments(collection: $id); - } - } - $offset += $this->limit; - } - } - /** - * Migrate all external documents - * - * @return void - * @throws Exception - * @throws Throwable - * @throws ExceptionAuthorization - * @throws Structure - */ - protected function migrateExternalDocuments(string $collection): void - { - $sum = $this->limit; - $offset = 0; - - while ($sum >= $this->limit) { - $allDocs = $this->oldProjectDB->getCollection([ - 'limit' => $this->limit, - 'offset' => $offset, - 'orderType' => 'DESC', - 'filters' => [ - '$collection=' . $collection - ] - ]); - - $sum = \count($allDocs); - - Console::log('Migrating External Documents for Collection ' . $collection . ': ' . $offset . ' / ' . $this->oldProjectDB->getSum()); - - foreach ($allDocs as $document) { - if (!$this->dbProject->getDocument('collection_' . $collection, $document->getId())->isEmpty()) { - continue; - } - go(function ($document) { - foreach ($document as $key => $attr) { - /** - * Convert nested Document to JSON strings. - */ - if ($document->getAttribute($key) instanceof OldDocument) { - $document[$key] = json_encode($this->fixDocument($attr)->getArrayCopy()); - } - /** - * Convert numeric Attributes to float. - */ - if (!is_string($attr) && is_numeric($attr)) { - $document[$key] = floatval($attr); - } - - if (\is_array($attr)) { - foreach ($attr as $index => $child) { - /** - * Convert array of nested Document to array JSON strings. - */ - if ($document->getAttribute($key)[$index] instanceof OldDocument) { - $document[$key][$index] = json_encode($this->fixDocument($child)->getArrayCopy()); - } - /** - * Convert array of numeric Attributes to array float. - */ - if (!is_string($child) && is_numeric($child)) { - $document[$key][$index] = floatval($child); // Convert any numeric to float - } - } - } - } - }, $document); - $document = new Document($document->getArrayCopy()); - $document = $this->migratePermissions($document); - - try { - $this->dbProject->createDocument('collection_' . $collection, $document); - } catch (\Throwable $th) { - Console::error("Failed to migrate document ({$document->getId()}): " . $th->getMessage()); - continue; - } - } - $offset += $this->limit; - } - } - - /** - * Migrates single docuemnt. - * - * @param OldDocument $oldDocument - * @return Document|null - * @throws Exception - */ - protected function fixDocument(OldDocument $oldDocument): Document|null - { - $document = new Document($oldDocument->getArrayCopy()); - $document = $this->migratePermissions($document); - - /** - * Check attributes and set their default values. - */ - if (array_key_exists($document->getCollection(), $this->oldCollections)) { - foreach ($this->newCollections[$document->getCollection()]['attributes'] ?? [] as $attr) { - if ( - (!$attr['array'] || - ($attr['array'] && array_key_exists('filter', $attr) - && in_array('json', $attr['filter']))) - && empty($document->getAttribute($attr['$id'], null)) - ) { - $document->setAttribute($attr['$id'], $attr['default'] ?? null); - } - } - } - - switch ($document->getAttribute('$collection')) { - case OldDatabase::SYSTEM_COLLECTION_PROJECTS: - $newProviders = []; - $newAuths = []; - $providers = Config::getParam('providers', []); - $auths = Config::getParam('auth', []); - - /** - * Remove Tasks - */ - $document->removeAttribute('tasks'); - - /* - * Add enabled OAuth2 providers to default data rules - */ - foreach ($providers as $index => $provider) { - $appId = $document->getAttribute('usersOauth2' . \ucfirst($index) . 'Appid'); - $appSecret = $document->getAttribute('usersOauth2' . \ucfirst($index) . 'Secret'); - - if (!is_null($appId) || !is_null($appId)) { - $newProviders[$appId] = $appSecret; - } - - $document - ->removeAttribute('usersOauth2' . \ucfirst($index) . 'Appid') - ->removeAttribute('usersOauth2' . \ucfirst($index) . 'Secret'); - } - - $document->setAttribute('providers', $newProviders); - - /* - * Migrate User providers settings - */ - $oldAuths = [ - 'email-password' => 'usersAuthEmailPassword', - 'magic-url' => 'usersAuthMagicURL', - 'anonymous' => 'usersAuthAnonymous', - 'invites' => 'usersAuthInvites', - 'jwt' => 'usersAuthJWT', - 'phone' => 'usersAuthPhone' - ]; - - foreach ($oldAuths as $index => $auth) { - $enabled = $document->getAttribute($auth, true); - $newAuths['auth' . \ucfirst($auths[$index]['key'])] = $enabled; - $document->removeAttribute($auth); - } - - if (!empty($document->getAttribute('usersAuthLimit'))) { - $newAuths['limit'] = $document->getAttribute('usersAuthLimit'); - } - - $document->removeAttribute('usersAuthLimit'); - - $document->setAttribute('auths', $newProviders); - - break; - case OldDatabase::SYSTEM_COLLECTION_PLATFORMS: - $projectId = $this->getProjectIdFromReadPermissions($document); - - if (is_null($projectId)) { - return null; - } - - /** - * Set Project ID - */ - if ($document->getAttribute('projectId') === null) { - $document->setAttribute('projectId', $projectId); - } - - /** - * Set empty key and store if null - */ - if ($document->getAttribute('key') === null) { - $document->setAttribute('key', ''); - } - if ($document->getAttribute('store') === null) { - $document->setAttribute('store', ''); - } - - /** - * Reset Permissions - */ - $document->setAttribute('$read', ['role:all']); - $document->setAttribute('$write', ['role:all']); - - break; - case OldDatabase::SYSTEM_COLLECTION_CERTIFICATES: - /** - * Replace certificateId attribute. - */ - if ($document->getAttribute('certificateId') !== null) { - $document->setAttribute('$id', $document->getAttribute('certificateId')); - $document->removeAttribute('certificateId'); - } - - break; - case OldDatabase::SYSTEM_COLLECTION_DOMAINS: - $projectId = $this->getProjectIdFromReadPermissions($document); - - if (is_null($projectId)) { - return null; - } - - /** - * Set Project ID - */ - if ($document->getAttribute('projectId') === null) { - $document->setAttribute('projectId', $projectId); - } - - /** - * Set empty verification if null - */ - if ($document->getAttribute('verification') === null) { - $document->setAttribute('verification', false); - } - - /** - * Reset Permissions - */ - $document->setAttribute('$read', ['role:all']); - $document->setAttribute('$write', ['role:all']); - - break; - case OldDatabase::SYSTEM_COLLECTION_KEYS: - $projectId = $this->getProjectIdFromReadPermissions($document); - - if (is_null($projectId)) { - return null; - } - - /** - * Set Project ID - */ - if ($document->getAttribute('projectId') === null) { - $document->setAttribute('projectId', $projectId); - } - - /** - * Set scopes if empty - */ - if (empty($document->getAttribute('scopes', []))) { - $document->setAttribute('scopes', []); - } - - /** - * Reset Permissions - */ - $document->setAttribute('$read', ['role:all']); - $document->setAttribute('$write', ['role:all']); - - break; - case OldDatabase::SYSTEM_COLLECTION_FUNCTIONS: - $document->setAttribute('events', $document->getAttribute('events', [])); - - break; - case OldDatabase::SYSTEM_COLLECTION_WEBHOOKS: - $projectId = $this->getProjectIdFromReadPermissions($document); - - if (is_null($projectId)) { - return null; - } - - /** - * Set Project ID - */ - if ($document->getAttribute('projectId') === null) { - $document->setAttribute('projectId', $projectId); - } - - $document->setAttribute('events', $document->getAttribute('events', [])); - - /** - * Reset Permissions - */ - $document->setAttribute('$read', ['role:all']); - $document->setAttribute('$write', ['role:all']); - - break; - case OldDatabase::SYSTEM_COLLECTION_USERS: - /** - * Set deleted attribute to false - */ - if ($document->getAttribute('deleted') === null) { - $document->setAttribute('deleted', false); - } - /** - * Remove deprecated user status 0 and replace with boolean. - */ - if ($document->getAttribute('status') === 2) { - $document->setAttribute('status', false); - } else { - $document->setAttribute('status', true); - } - - /** - * Set default values for arrays if not set. - */ - if (empty($document->getAttribute('prefs', []))) { - $document->setAttribute('prefs', new \stdClass()); - } - if (empty($document->getAttribute('sessions', []))) { - $document->setAttribute('sessions', []); - } - if (empty($document->getAttribute('tokens', []))) { - $document->setAttribute('tokens', []); - } - if (empty($document->getAttribute('memberships', []))) { - $document->setAttribute('memberships', []); - } - - /** - * Replace user:{self} with user:USER_ID - */ - $write = $document->getWrite(); - $document->setAttribute('$write', str_replace('user:{self}', "user:{$document->getId()}", $write)); - - break; - case OldDatabase::SYSTEM_COLLECTION_TEAMS: - - /** - * Replace team:{self} with team:TEAM_ID - */ - $read = $document->getWrite(); - $write = $document->getWrite(); - - $document->setAttribute('$read', str_replace('team:{self}', "team:{$document->getId()}", $read)); - $document->setAttribute('$write', str_replace('team:{self}', "team:{$document->getId()}", $write)); - - break; - case OldDatabase::SYSTEM_COLLECTION_FILES: - /** - * Migrating breakind changes on Files. - */ - if (!empty($document->getAttribute('fileOpenSSLVersion', null))) { - $document - ->setAttribute('openSSLVersion', $document->getAttribute('fileOpenSSLVersion')) - ->removeAttribute('fileOpenSSLVersion'); - } - if (!empty($document->getAttribute('fileOpenSSLCipher', null))) { - $document - ->setAttribute('openSSLCipher', $document->getAttribute('fileOpenSSLCipher')) - ->removeAttribute('fileOpenSSLCipher'); - } - if (!empty($document->getAttribute('fileOpenSSLTag', null))) { - $document - ->setAttribute('openSSLTag', $document->getAttribute('fileOpenSSLTag')) - ->removeAttribute('fileOpenSSLTag'); - } - if (!empty($document->getAttribute('fileOpenSSLIV', null))) { - $document - ->setAttribute('openSSLIV', $document->getAttribute('fileOpenSSLIV')) - ->removeAttribute('fileOpenSSLIV'); - } - - /** - * Remove deprecated attributes. - */ - $document->removeAttribute('folderId'); - $document->removeAttribute('token'); - break; - } - - return $document; - } - - /** - * Migrates $permissions to independent $read and $write. - * @param Document $document - * @return Document - */ - protected function migratePermissions(Document $document): Document - { - if ($document->isSet('$permissions')) { - $permissions = $document->getAttribute('$permissions', []); - $read = $this->migrateWildcardPermissions($permissions['read'] ?? []); - $write = $this->migrateWildcardPermissions($permissions['write'] ?? []); - $document->setAttribute('$read', $read); - $document->setAttribute('$write', $write); - $document->removeAttribute('$permissions'); - } - - return $document; - } - - /** - * Takes a permissions array and replaces wildcard * with role:all. - * @param array $permissions - * @return array - */ - protected function migrateWildcardPermissions(array $permissions): array - { - return array_map(function ($permission) { - if ($permission === '*') return 'role:all'; - return $permission; - }, $permissions); - } - - /** - * Get new collection attributes from old collection rules. - * @param OldDocument $collection - * @return array - */ - protected function getCollectionAttributes(OldDocument $collection): array - { - $attributes = []; - foreach ($collection->getAttribute('rules', []) as $key => $value) { - $collectionId = $collection->getId(); - $id = $value['key']; - $array = $value['array'] ?? false; - $required = $value['required'] ?? false; - $default = $value['default'] ?? null; - $default = match ($value['type']) { - OldDatabase::SYSTEM_VAR_TYPE_NUMERIC => floatval($default), - default => $default - }; - $type = match ($value['type']) { - OldDatabase::SYSTEM_VAR_TYPE_TEXT => Database::VAR_STRING, - OldDatabase::SYSTEM_VAR_TYPE_EMAIL => Database::VAR_STRING, - OldDatabase::SYSTEM_VAR_TYPE_DOCUMENT => Database::VAR_STRING, - OldDatabase::SYSTEM_VAR_TYPE_IP => Database::VAR_STRING, - OldDatabase::SYSTEM_VAR_TYPE_URL => Database::VAR_STRING, - OldDatabase::SYSTEM_VAR_TYPE_WILDCARD => Database::VAR_STRING, - OldDatabase::SYSTEM_VAR_TYPE_NUMERIC => Database::VAR_FLOAT, - OldDatabase::SYSTEM_VAR_TYPE_BOOLEAN => Database::VAR_BOOLEAN, - default => Database::VAR_STRING - }; - - $size = $type === Database::VAR_STRING ? 65_535 : 0; // Max size of text in MariaDB - - if ($required) { - $default = null; - } - - $attributes[$key] = [ - '$collection' => $collectionId, - '$id' => $id, - 'type' => $type, - 'size' => $size, - 'required' => $required, - 'default' => $default, - 'array' => $array, - 'signed' => true, - 'filters' => [] - ]; - - if ($type === Database::VAR_FLOAT) { - $attributes[$key]['format'] = APP_DATABASE_ATTRIBUTE_FLOAT_RANGE; - $attributes[$key]['formatOptions'] = []; - $attributes[$key]['formatOptions']['min'] = -PHP_FLOAT_MAX; - $attributes[$key]['formatOptions']['max'] = PHP_FLOAT_MAX; - } - } - - return $attributes; - } - - /** - * @param Document $document - * @return string|null - * @throws Exception - */ - protected function getProjectIdFromReadPermissions(Document $document): string|null - { - $readPermissions = $document->getRead(); - $teamId = str_replace('team:', '', reset($readPermissions)); - $project = $this->oldConsoleDB->getCollectionFirst([ - 'filters' => [ - '$collection=' . OldDatabase::SYSTEM_COLLECTION_PROJECTS, - 'teamId=' . $teamId - ] - ]); - - if (!$project) { - return null; - } - - return $project->getId(); - } -} diff --git a/src/Appwrite/Migration/Version/V12.php b/src/Appwrite/Migration/Version/V12.php new file mode 100644 index 0000000000..9b9376abac --- /dev/null +++ b/src/Appwrite/Migration/Version/V12.php @@ -0,0 +1,113 @@ +project->getAttribute('name') . ' (' . $this->project->getId() . ')'); + + $this->forEachDocument([$this, 'fixDocument']); + } + + protected function fixDocument(Document $document) + { + switch ($document->getCollection()) { + case 'projects': + /** + * Bump Project version number. + */ + $document->setAttribute('version', '0.13.0'); + + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'name'], $document)); + } + + break; + + case 'users': + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'email', 'name'], $document)); + } + + break; + + case 'teams': + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'name'], $document)); + } + + break; + + case 'files': + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'name'], $document)); + } + + break; + + case 'functions': + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'name', 'runtime'], $document)); + } + + break; + + case 'tags': + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'command'], $document)); + } + + break; + + case 'executions': + /** + * Populate search string from Migration to 0.12. + */ + if (empty($document->getAttribute('search'))) { + $document->setAttribute('search', $this->buildSearchAttribute(['$id', 'functionId'], $document)); + } + + break; + } + + return $document; + } + + /** + * Builds a search string for a fulltext index. + * + * @param array $values + * @param Document $document + * @return string + */ + private function buildSearchAttribute(array $values, Document $document): string + { + $values = array_filter(array_map(fn (string $value) => $document->getAttribute($value) ?? '', $values)); + + return implode(' ', $values); + } +} diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index f26eed1244..4aeadd90b2 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -275,7 +275,7 @@ class OpenAPI3 extends Format $node['schema']['x-example'] = false; break; case 'Utopia\Database\Validator\UID': - case 'Appwrite\Database\Validator\CustomId': + case 'Appwrite\Utopia\Database\Validator\CustomId': $node['schema']['type'] = $validator->getType(); $node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index ee02950e16..21ea7ee2b6 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -263,7 +263,7 @@ class Swagger2 extends Format $node['x-example'] = false; break; case 'Utopia\Database\Validator\UID': - case 'Appwrite\Database\Validator\CustomId': + case 'Appwrite\Utopia\Database\Validator\CustomId': $node['type'] = $validator->getType(); $node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']'; break; diff --git a/src/Appwrite/Database/Validator/CustomId.php b/src/Appwrite/Utopia/Database/Validator/CustomId.php similarity index 87% rename from src/Appwrite/Database/Validator/CustomId.php rename to src/Appwrite/Utopia/Database/Validator/CustomId.php index 39a8500f81..96891bf68a 100644 --- a/src/Appwrite/Database/Validator/CustomId.php +++ b/src/Appwrite/Utopia/Database/Validator/CustomId.php @@ -1,5 +1,5 @@ parseCollection($content); - break; - - case Response::MODEL_COLLECTION_LIST: - $parsedResponse = $this->parseCollectionList($content); - break; - - case Response::MODEL_FILE: - $parsedResponse = $this->parseFile($content); - break; - - case Response::MODEL_FILE_LIST: - $parsedResponse = $content; - break; - - case Response::MODEL_USER: - $parsedResponse = $this->parseUser($content); - break; - - case Response::MODEL_USER_LIST: - $parsedResponse = $this->parseUserList($content); - break; - - case Response::MODEL_TEAM: - $parsedResponse = $this->parseTeam($content); - break; - - case Response::MODEL_TEAM_LIST: - $parsedResponse = $this->parseTeamList($content); - break; - - case Response::MODEL_MEMBERSHIP: - $parsedResponse = $content; - break; - - case Response::MODEL_MEMBERSHIP_LIST: - $parsedResponse = $content['memberships']; - break; - - case Response::MODEL_SESSION: - $parsedResponse = $this->parseSession($content); - break; - - case Response::MODEL_SESSION_LIST: - $parsedResponse = $this->parseSessionList($content); - break; - - case Response::MODEL_LOG_LIST: - $parsedResponse = $this->parseLogList($content); - break; - - case Response::MODEL_TOKEN: - $parsedResponse = $this->parseToken($content); - break; - - case Response::MODEL_LOCALE: - $parsedResponse = $this->parseLocale($content); - break; - - case Response::MODEL_COUNTRY_LIST: - $parsedResponse = $this->parseCountryList($content); - break; - - case Response::MODEL_PHONE_LIST: - $parsedResponse = $this->parsePhoneList($content); - break; - - case Response::MODEL_CONTINENT_LIST: - $parsedResponse = $this->parseContinentList($content); - break; - - case Response::MODEL_CURRENCY_LIST: - $parsedResponse = $this->parseCurrencyList($content); - break; - - case Response::MODEL_LANGUAGE_LIST: - $parsedResponse = $content; - break; - - case Response::MODEL_ANY: - case Response::MODEL_DOCUMENT: - case Response::MODEL_PREFERENCES: - $parsedResponse = $content; - break; - - default: - throw new Exception('Received invalid model : ' . $model); - } - - return $parsedResponse; - } - - private function parseCollectionList(array $content) - { - foreach ($content['collections'] as $key => $collection) { - $content['collections'][$key] = $this->parseCollection($collection); - } - return $content; - } - - private function parseCollection(array $content) - { - $content['$collection'] = Database::SYSTEM_COLLECTION_COLLECTIONS; - $content['structure'] = true; - return $content; - } - - private function parseFile(array $content) - { - $content['$collection'] = Database::SYSTEM_COLLECTION_FILES; - $content['algorithm'] = 'gzip'; - $content['comment'] = ''; - $content['fileOpenSSLCipher'] = OpenSSL::CIPHER_AES_128_GCM; - $content['fileOpenSSLIV'] = ''; - $content['fileOpenSSLTag'] = ''; - $content['fileOpenSSLVersion'] = ''; - $content['folderId'] = ''; - $content['path'] = ''; - $content['sizeActual'] = $content['sizeOriginal']; - $content['token'] = ''; - return $content; - } - - private function parseCurrencyList(array $content) - { - $content['locations'] = []; - $currencies = $content['currencies']; - $parsedResponse = []; - foreach ($currencies as $currency) { - $currency['locations'] = []; - $parsedResponse[] = $currency; - } - $content['currencies'] = $parsedResponse; - return $content; - } - - private function parseContinentList(array $content) - { - $continents = $content['continents']; - $parsedResponse = []; - foreach ($continents as $continent) { - $parsedResponse[$continent['code']] = $continent['name']; - } - $content['continents'] = $parsedResponse; - return $content; - } - - private function parsePhoneList(array $content) - { - $phones = $content['phones']; - $parsedResponse = []; - foreach ($phones as $phone) { - $parsedResponse[$phone['countryCode']] = $phone['code']; - } - $content['phones'] = $parsedResponse; - return $content; - } - - private function parseCountryList(array $content) - { - $countries = $content['countries']; - $parsedResponse = []; - foreach ($countries as $country) { - $parsedResponse[$country['code']] = $country['name']; - } - $content['countries'] = $parsedResponse; - return $content; - } - - private function parseLocale(array $content) - { - $content['ip'] = $content['ip'] ?? ''; - $content['countryCode'] = $content['countryCode'] ?? '--'; - $content['country'] = $content['country'] ?? Locale::getText('locale.country.unknown'); - $content['continent'] = $content['continent'] ?? Locale::getText('locale.country.unknown'); - $content['continentCode'] = $content['continentCode'] ?? '--'; - $content['eu'] = $content['eu'] ?? false; - $content['currency'] = $content['currency'] ?? null; - return $content; - } - - private function parseToken(array $content) - { - $content['type'] = Auth::TOKEN_TYPE_RECOVERY; - return $content; - } - - private function parseTeam(array $content) - { - $content['$collection'] = Database::SYSTEM_COLLECTION_TEAMS; - $content['$permissions'] = []; - return $content; - } - - private function parseTeamList(array $content) - { - $teams = $content['teams']; - $parsedResponse = []; - foreach ($teams as $team) { - $parsedResponse[] = $this->parseTeam($team); - } - $content['teams'] = $parsedResponse; - return $content; - } - - private function parseLogList(array $content) - { - $logs = $content['logs']; - $parsedResponse = []; - foreach ($logs as $log) { - $parsedResponse[] = [ - 'brand' => $log['deviceBrand'], - 'device' => $log['deviceName'], - 'event' => $log['event'], - 'ip' => $log['ip'], - 'model' => $log['deviceModel'], - 'time' => $log['time'], - 'geo' => [ - 'isoCode' => empty($log['countryCode']) ? '---' : $log['countryCode'], - 'country' => empty($log['countryName']) ? Locale::getText('locale.country.unknown') : $log['countryName'] - ], - 'OS' => [ - 'name' => $log['osName'], - 'platform' => '', - 'short_name' => $log['osCode'], - 'version' => $log['osVersion'] - ], - 'client' => [ - 'engine' => $log['clientEngine'], - 'name' => $log['clientName'], - 'short_name' => $log['clientCode'], - 'type' => $log['clientType'], - 'version' => $log['clientVersion'] - ] - ]; - } - $content['logs'] = $parsedResponse; - return $content; - } - - private function parseSessionList(array $content) - { - $sessions = $content['sessions']; - $parsedResponse = []; - foreach ($sessions as $session) { - $parsedResponse[] = [ - '$id' => $session['$id'], - 'brand' => $session['deviceBrand'], - 'current' => $session['current'], - 'device' => $session['deviceName'], - 'ip' => $session['ip'], - 'model' => $session['deviceModel'], - 'geo' => [ - 'isoCode' => empty($session['countryCode']) ? '---' : $session['countryCode'], - 'country' => empty($session['countryName']) ? Locale::getText('locale.country.unknown') : $session['countryName'] - ], - 'OS' => [ - 'name' => $session['osName'], - 'platform' => '', - 'short_name' => $session['osCode'], - 'version' => $session['osVersion'] - ], - 'client' => [ - 'engine' => $session['clientEngine'], - 'name' => $session['clientName'], - 'short_name' => $session['clientCode'], - 'type' => $session['clientType'], - 'version' => $session['clientVersion'] - ] - ]; - } - $content['sessions'] = $parsedResponse; - return $content; - } - - private function parseSession(array $content) - { - $content['type'] = Auth::TOKEN_TYPE_LOGIN; - return $content; - } - - private function parseUserList(array $content) - { - $users = $content['users']; - $parsedResponse = []; - foreach ($users as $user) { - $parsedResponse[] = $this->parseUser($user); - } - $content['users'] = $parsedResponse; - return $content; - } - - private function parseUser(array $content) - { - foreach (Config::getParam('providers', []) as $key => $provider) { - if (!$provider['enabled']) { - continue; - } - $content['oauth2' . ucfirst($key)] = ''; - $content['oauth2' . ucfirst($key) . 'AccessToken'] = ''; - } - $content['status'] = $content['status'] ? 0 : 2; - $content['roles'] = Authorization::getRoles() ?? []; - return $content; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V07.php b/src/Appwrite/Utopia/Response/Filters/V07.php deleted file mode 100644 index 7ab0838578..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V07.php +++ /dev/null @@ -1,110 +0,0 @@ -parseFunctionList($content); - break; - case Response::MODEL_FUNCTION: - $parsedResponse = $this->parseFunctionList($content); /** Function property env was renamed to runtime in 0.9.x */ - break; - default: - throw new Exception('Received invalid model : '.$model); - } - - return $parsedResponse; - } - - protected function parseFunction(array $content) - { - $content['env'] = $content['runtime']; - unset($content['runtime']); - return $content; - } - - protected function parseFunctionList(array $content) - { - $functions = $content['functions']; - $parsedResponse = []; - foreach ($functions as $function) { - $parsedResponse[] = $this->parseFunction($function); - } - $content['functions'] = $parsedResponse; - return $content; - } -} diff --git a/src/Appwrite/Utopia/Response/Filters/V08.php b/src/Appwrite/Utopia/Response/Filters/V08.php deleted file mode 100644 index 2527562f8e..0000000000 --- a/src/Appwrite/Utopia/Response/Filters/V08.php +++ /dev/null @@ -1,103 +0,0 @@ -parseFunctionList($content); - break; - case Response::MODEL_FUNCTION: /** Function property env was renamed to runtime in 0.9.x */ - $parsedResponse = $this->parseFunctionList($content); - break; - default: - throw new Exception('Received invalid model : '.$model); - } - - return $parsedResponse; - } - - protected function parseFunction(array $content) - { - $content['env'] = $content['runtime']; - unset($content['runtime']); - return $content; - } - - protected function parseFunctionList(array $content) - { - $functions = $content['functions']; - $parsedResponse = []; - foreach ($functions as $function) { - $parsedResponse[] = $this->parseFunction($function); - } - $content['functions'] = $parsedResponse; - return $content; - } -} diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index a832379282..4b26f2fcd9 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -160,45 +160,7 @@ class HTTPTest extends Scope } } - public function testResponseHeader() { - - /** - * Test without header - */ - $response = $this->client->call(Client::METHOD_GET, '/locale/continents', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => 'console', - ], $this->getHeaders())); - - $body = $response['body']; - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals($body['sum'], 7); - $this->assertEquals($body['continents'][0]['name'], 'Africa'); - $this->assertEquals($body['continents'][0]['code'], 'AF'); - $this->assertEquals($body['continents'][1]['name'], 'Antarctica'); - $this->assertEquals($body['continents'][1]['code'], 'AN'); - $this->assertEquals($body['continents'][2]['name'], 'Asia'); - $this->assertEquals($body['continents'][2]['code'], 'AS'); - - /** - * Test with header - */ - $response = $this->client->call(Client::METHOD_GET, '/locale/continents', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => 'console', - 'x-appwrite-response-format' => '0.6.2' - ], $this->getHeaders())); - - $body = $response['body']; - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals($body['sum'], 7); - $this->assertEquals($body['continents']['AF'], 'Africa'); - $this->assertEquals($body['continents']['AN'], 'Antarctica'); - $this->assertEquals($body['continents']['AS'], 'Asia'); - } - public function testVersions() { - /** * Test without header */ diff --git a/tests/unit/Database/Validator/KeyTest.php b/tests/unit/Database/Validator/KeyTest.php deleted file mode 100644 index 68362c22f4..0000000000 --- a/tests/unit/Database/Validator/KeyTest.php +++ /dev/null @@ -1,36 +0,0 @@ -object = new Key(); - } - - public function tearDown(): void - { - } - - public function testValues() - { - $this->assertEquals($this->object->isValid('dasda asdasd'), false); - $this->assertEquals($this->object->isValid('asdasdasdas'), true); - $this->assertEquals($this->object->isValid('as$$5dasdasdas'), false); - $this->assertEquals($this->object->isValid(false), false); - $this->assertEquals($this->object->isValid(null), false); - $this->assertEquals($this->object->isValid('socialAccountForYoutubeSubscribers'), false); - $this->assertEquals($this->object->isValid('socialAccountForYoutubeSubscriber'), false); - $this->assertEquals($this->object->isValid('socialAccountForYoutubeSubscribe'), true); - $this->assertEquals($this->object->isValid('socialAccountForYoutubeSubscrib'), true); - } -} diff --git a/tests/unit/Database/Validator/UIDTest.php b/tests/unit/Database/Validator/UIDTest.php deleted file mode 100644 index bc70451130..0000000000 --- a/tests/unit/Database/Validator/UIDTest.php +++ /dev/null @@ -1,30 +0,0 @@ -object = new UID(); - } - - public function tearDown(): void - { - } - - public function testValues() - { - $this->assertEquals($this->object->isValid('5f058a8925807'), true); - $this->assertEquals($this->object->isValid('5f058a89258075f058a89258075f058t'), true); - $this->assertEquals($this->object->isValid('5f058a89258075f058a89258075f058tx'), false); - } -} diff --git a/tests/unit/Migration/MigrationTest.php b/tests/unit/Migration/MigrationTest.php index 45ddcca29f..fa2928eb79 100644 --- a/tests/unit/Migration/MigrationTest.php +++ b/tests/unit/Migration/MigrationTest.php @@ -2,18 +2,13 @@ namespace Appwrite\Tests; -use Appwrite\Database\Document; use Appwrite\Migration\Migration; use PHPUnit\Framework\TestCase; use ReflectionMethod; +use Utopia\Database\Document; abstract class MigrationTest extends TestCase { - /** - * @var PDO - */ - protected \PDO $pdo; - /** * @var Migration */ @@ -43,7 +38,7 @@ abstract class MigrationTest extends TestCase { require_once __DIR__.'/../../../app/init.php'; - foreach (Migration::$versions as $version => $class) { + foreach (Migration::$versions as $class) { $this->assertTrue(class_exists('Appwrite\\Migration\\Version\\'.$class)); } // Test if current version exists diff --git a/tests/unit/Migration/MigrationV05Test.php b/tests/unit/Migration/MigrationV05Test.php deleted file mode 100644 index 09e28dd054..0000000000 --- a/tests/unit/Migration/MigrationV05Test.php +++ /dev/null @@ -1,86 +0,0 @@ -pdo = new \PDO('sqlite::memory:'); - $this->migration = new V05($this->pdo); - $reflector = new ReflectionClass('Appwrite\Migration\Version\V05'); - $this->method = $reflector->getMethod('fixDocument'); - $this->method->setAccessible(true); - } - - public function testMigration() - { - $document = $this->fixDocument(new Document([ - '$uid' => 'unique', - '$collection' => Database::SYSTEM_COLLECTION_PROJECTS, - 'usersOauthGithubAppid' => 123, - 'usersOauthGithubSecret' => 456 - ])); - - $this->assertEquals($document->getAttribute('$uid', null), null); - $this->assertEquals($document->getAttribute('$id', null), 'unique'); - - $this->assertEquals($document->getAttribute('usersOauthGithubAppid', null), null); - $this->assertEquals($document->getAttribute('usersOauth2GithubAppid', null), 123); - - $this->assertEquals($document->getAttribute('usersOauthGithubSecret', null), null); - $this->assertEquals($document->getAttribute('usersOauth2GithubSecret', null), 456); - - $this->assertEquals($document->getAttribute('security', true), false); - - $document = $this->fixDocument(new Document([ - '$uid' => 'unique', - '$collection' => Database::SYSTEM_COLLECTION_TASKS - ])); - - $this->assertEquals($document->getAttribute('$uid', null), null); - $this->assertEquals($document->getAttribute('$id', null), 'unique'); - - $this->assertEquals($document->getAttribute('security', true), false); - - $document = $this->fixDocument(new Document([ - '$uid' => 'unique', - '$collection' => Database::SYSTEM_COLLECTION_USERS, - 'oauthGithub' => 'id', - 'oauthGithubAccessToken' => 'token', - 'confirm' => false - ])); - - $this->assertEquals($document->getAttribute('$uid', null), null); - $this->assertEquals($document->getAttribute('$id', null), 'unique'); - - $this->assertEquals($document->getAttribute('confirm', null), null); - $this->assertEquals($document->getAttribute('emailVerification', true), false); - - $this->assertEquals($document->getAttribute('oauthGithub', null), null); - $this->assertEquals($document->getAttribute('oauth2Github', null), 'id'); - - $this->assertEquals($document->getAttribute('oauthGithubAccessToken', null), null); - $this->assertEquals($document->getAttribute('oauth2GithubAccessToken', null), 'token'); - - $document = $this->fixDocument(new Document([ - '$uid' => 'unique', - '$collection' => Database::SYSTEM_COLLECTION_PLATFORMS, - 'url' => 'https://appwrite.io' - ])); - - $this->assertEquals($document->getAttribute('$uid', null), null); - $this->assertEquals($document->getAttribute('$id', null), 'unique'); - - $this->assertEquals($document->getAttribute('url', null), null); - $this->assertEquals($document->getAttribute('hostname', null), 'appwrite.io'); - } -} diff --git a/tests/unit/Migration/MigrationV06Test.php b/tests/unit/Migration/MigrationV06Test.php deleted file mode 100644 index 19e892c435..0000000000 --- a/tests/unit/Migration/MigrationV06Test.php +++ /dev/null @@ -1,48 +0,0 @@ -pdo = new \PDO('sqlite::memory:'); - - $this->migration = new V06($this->pdo); - $reflector = new ReflectionClass('Appwrite\Migration\Version\V06'); - $this->method = $reflector->getMethod('fixDocument'); - $this->method->setAccessible(true); - } - - public function testMigration() - { - $document = $this->fixDocument(new Document([ - '$id' => uniqid(), - '$collection' => Database::SYSTEM_COLLECTION_USERS, - 'password-update' => 123 - ])); - - $this->assertEquals($document->getAttribute('password-update', null), null); - $this->assertEquals($document->getAttribute('passwordUpdate', null), 123); - - $document = $this->fixDocument( - new Document([ - '$id' => uniqid(), - '$collection' => Database::SYSTEM_COLLECTION_KEYS, - 'secret' => 123 - ]) - ); - - $encrypted = json_decode($document->getAttribute('secret', null)); - $this->assertObjectHasAttribute('data', $encrypted); - $this->assertObjectHasAttribute('method', $encrypted); - $this->assertObjectHasAttribute('iv', $encrypted); - $this->assertObjectHasAttribute('tag', $encrypted); - $this->assertObjectHasAttribute('version', $encrypted); - } -} diff --git a/tests/unit/Migration/MigrationV07Test.php b/tests/unit/Migration/MigrationV07Test.php deleted file mode 100644 index ca73c3229d..0000000000 --- a/tests/unit/Migration/MigrationV07Test.php +++ /dev/null @@ -1,69 +0,0 @@ -pdo = new \PDO('sqlite::memory:'); - $this->migration = new V07($this->pdo); - $reflector = new ReflectionClass('Appwrite\Migration\Version\V07'); - $this->method = $reflector->getMethod('fixDocument'); - $this->method->setAccessible(true); - } - - public function testMigration() - { - $document = $this->fixDocument(new Document([ - '$id' => 'unique', - '$collection' => Database::SYSTEM_COLLECTION_USERS, - 'oauth2Github' => 123, - 'oauth2GithubAccessToken' => 456, - 'tokens' => [ - new Document([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, - 'userId' => 'unique', - 'type' => Auth::TOKEN_TYPE_LOGIN, - 'secret' => 'login', - ]), - new Document([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, - 'userId' => 'unique', - 'type' => Auth::TOKEN_TYPE_INVITE, - 'secret' => 'invite', - ]), - new Document([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, - 'userId' => 'unique', - 'type' => Auth::TOKEN_TYPE_RECOVERY, - 'secret' => 'recovery', - ]), - new Document([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, - 'userId' => 'unique', - 'type' => Auth::TOKEN_TYPE_VERIFICATION, - 'secret' => 'verification', - ]), - ] - ])); - - $this->assertEquals($document->getAttribute('oauth2Github', null), null); - $this->assertEquals($document->getAttribute('oauth2GithubAccessToken', null), null); - - $this->assertCount(3, $document->getAttribute('tokens', [])); - $this->assertEquals(Auth::TOKEN_TYPE_INVITE, $document->getAttribute('tokens', [])[0]['type']); - $this->assertEquals(Auth::TOKEN_TYPE_RECOVERY, $document->getAttribute('tokens', [])[1]['type']); - $this->assertEquals(Auth::TOKEN_TYPE_VERIFICATION, $document->getAttribute('tokens', [])[2]['type']); - - } -} diff --git a/tests/unit/Migration/MigrationV08Test.php b/tests/unit/Migration/MigrationV08Test.php deleted file mode 100644 index 06ed5f44ff..0000000000 --- a/tests/unit/Migration/MigrationV08Test.php +++ /dev/null @@ -1,40 +0,0 @@ -pdo = new \PDO('sqlite::memory:'); - $this->migration = new V08($this->pdo); - $reflector = new ReflectionClass('Appwrite\Migration\Version\V08'); - $this->method = $reflector->getMethod('fixDocument'); - $this->method->setAccessible(true); - } - - public function testMigration() - { - $document = $this->fixDocument(new Document([ - '$id' => 'unique', - '$collection' => Database::SYSTEM_COLLECTION_FUNCTIONS, - 'env' => 'node-16' - ])); - - $this->assertEquals($document->getAttribute('env', null), null); - $this->assertEquals($document->getAttribute('runtime', null), 'node-16'); - - $document = $this->fixDocument(new Document([ - '$id' => 'project', - '$collection' => Database::SYSTEM_COLLECTION_PROJECTS - ])); - - $this->assertEquals($document->getAttribute('version', null), '0.9.0'); - } -} diff --git a/tests/unit/Migration/MigrationV09Test.php b/tests/unit/Migration/MigrationV09Test.php deleted file mode 100644 index d5bee3808f..0000000000 --- a/tests/unit/Migration/MigrationV09Test.php +++ /dev/null @@ -1,31 +0,0 @@ -pdo = new \PDO('sqlite::memory:'); - $this->migration = new V09($this->pdo); - $reflector = new ReflectionClass('Appwrite\Migration\Version\V09'); - $this->method = $reflector->getMethod('fixDocument'); - $this->method->setAccessible(true); - } - - public function testMigration() - { - $document = $this->fixDocument(new Document([ - '$id' => 'project', - '$collection' => Database::SYSTEM_COLLECTION_PROJECTS, - 'version' => '0.9.0' - ])); - - $this->assertEquals($document->getAttribute('version', '0.9.0'), '0.10.0'); - } -} diff --git a/tests/unit/Migration/MigrationV10Test.php b/tests/unit/Migration/MigrationV10Test.php deleted file mode 100644 index fe683e0aaf..0000000000 --- a/tests/unit/Migration/MigrationV10Test.php +++ /dev/null @@ -1,31 +0,0 @@ -pdo = new \PDO('sqlite::memory:'); - $this->migration = new V10($this->pdo); - $reflector = new ReflectionClass('Appwrite\Migration\Version\V10'); - $this->method = $reflector->getMethod('fixDocument'); - $this->method->setAccessible(true); - } - - public function testMigration() - { - $document = $this->fixDocument(new Document([ - '$id' => 'project', - '$collection' => Database::SYSTEM_COLLECTION_PROJECTS, - 'version' => '0.10.0' - ])); - - $this->assertEquals($document->getAttribute('version', '0.10.0'), '0.11.0'); - } -} diff --git a/tests/unit/Migration/MigrationV12Test.php b/tests/unit/Migration/MigrationV12Test.php new file mode 100644 index 0000000000..0c268ecfc8 --- /dev/null +++ b/tests/unit/Migration/MigrationV12Test.php @@ -0,0 +1,100 @@ +migration = new V12(); + $reflector = new ReflectionClass('Appwrite\Migration\Version\V12'); + $this->method = $reflector->getMethod('fixDocument'); + $this->method->setAccessible(true); + } + + public function testMigrationProjects() + { + $document = $this->fixDocument(new Document([ + '$id' => 'project', + '$collection' => 'projects', + 'name' => 'Appwrite', + 'version' => '0.12.0', + 'search' => '' + ])); + + $this->assertEquals($document->getAttribute('version'), '0.13.0'); + $this->assertEquals($document->getAttribute('search'), 'project Appwrite'); + } + + public function testMigrationUsers() + { + $document = $this->fixDocument(new Document([ + '$id' => 'user', + '$collection' => 'users', + 'email' => 'test@appwrite.io', + 'name' => 'Torsten Dittmann' + ])); + + $this->assertEquals($document->getAttribute('search'), 'user test@appwrite.io Torsten Dittmann'); + } + + public function testMigrationTeams() + { + $document = $this->fixDocument(new Document([ + '$id' => 'team', + '$collection' => 'teams', + 'name' => 'Appwrite' + ])); + + $this->assertEquals($document->getAttribute('search'), 'team Appwrite'); + } + + public function testMigrationFiles() + { + $document = $this->fixDocument(new Document([ + '$id' => 'file', + '$collection' => 'files', + 'name' => 'Dog.jpeg' + ])); + + $this->assertEquals($document->getAttribute('search'), 'file Dog.jpeg'); + } + + public function testMigrationFunctions() + { + $document = $this->fixDocument(new Document([ + '$id' => 'function', + '$collection' => 'functions', + 'name' => 'My Function', + 'runtime' => 'php-8.0' + ])); + + $this->assertEquals($document->getAttribute('search'), 'function My Function php-8.0'); + } + + public function testMigrationTags() + { + $document = $this->fixDocument(new Document([ + '$id' => 'tag', + '$collection' => 'tags', + 'command' => 'php main.php' + ])); + + $this->assertEquals($document->getAttribute('search'), 'tag php main.php'); + } + + public function testMigrationExecutions() + { + $document = $this->fixDocument(new Document([ + '$id' => 'execution', + '$collection' => 'executions', + 'functionId' => 'function' + ])); + + $this->assertEquals($document->getAttribute('search'), 'execution function'); + } +} diff --git a/tests/unit/Database/Validator/CustomIdTest.php b/tests/unit/Utopia/Database/Validator/CustomIdTest.php similarity index 96% rename from tests/unit/Database/Validator/CustomIdTest.php rename to tests/unit/Utopia/Database/Validator/CustomIdTest.php index 89cf16bfa8..8b0ddf737a 100644 --- a/tests/unit/Database/Validator/CustomIdTest.php +++ b/tests/unit/Utopia/Database/Validator/CustomIdTest.php @@ -2,7 +2,7 @@ namespace Appwrite\Tests; -use Appwrite\Database\Validator\CustomId; +use Appwrite\Utopia\Database\Validator\CustomId; use PHPUnit\Framework\TestCase; class CustomIdTest extends TestCase diff --git a/tests/unit/Utopia/Filters/V06Test.php b/tests/unit/Utopia/Filters/V06Test.php deleted file mode 100644 index 6ee44c70aa..0000000000 --- a/tests/unit/Utopia/Filters/V06Test.php +++ /dev/null @@ -1,518 +0,0 @@ -filter = new V06(); - } - - public function testParseUser() - { - $content = [ - '$id' => '5e5ea5c16897e', - 'name' => 'John Doe', - 'registration' => 1592981250, - 'status' => true, - 'email' => 'john@appwrite.io', - 'emailVerification' => false, - 'prefs' => [ - 'theme' => 'pink', - 'timezone' => 'UTC' - ] - ]; - - Config::load('providers', __DIR__.'/../../../../app/config/providers.php'); - - $model = Response::MODEL_USER; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['name'], 'John Doe'); - $this->assertEquals($parsedResponse['registration'], 1592981250); - $this->assertEquals($parsedResponse['status'], 0); - $this->assertEquals($parsedResponse['email'], 'john@appwrite.io'); - $this->assertEquals($parsedResponse['emailVerification'], false); - $this->assertEquals($parsedResponse['prefs'], ['theme' => 'pink', 'timezone' => 'UTC']); - $this->assertEquals($parsedResponse['roles'], Authorization::getRoles() ?? []); - } - - public function testParseUserList() - { - $content = [ - 'sum' => 1, - 'users' => [ - 0 => [ - '$id' => '5e5ea5c16897e', - 'name' => 'John Doe', - 'registration' => 1592981250, - 'status' => true, - 'email' => 'john@appwrite.io', - 'emailVerification' => false, - 'prefs' => [ - 'theme' => 'pink', - 'timezone' => 'UTC' - ] - ] - ] - ]; - - Config::load('providers', __DIR__.'/../../../../app/config/providers.php'); - - $model = Response::MODEL_USER_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['users'][0]['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['users'][0]['name'], 'John Doe'); - $this->assertEquals($parsedResponse['users'][0]['registration'], 1592981250); - $this->assertEquals($parsedResponse['users'][0]['status'], 0); - $this->assertEquals($parsedResponse['users'][0]['email'], 'john@appwrite.io'); - $this->assertEquals($parsedResponse['users'][0]['emailVerification'], false); - $this->assertEquals($parsedResponse['users'][0]['prefs'], ['theme' => 'pink', 'timezone' => 'UTC']); - $this->assertEquals($parsedResponse['users'][0]['roles'], Authorization::getRoles() ?? []); - } - - public function testParseSession() - { - $content = [ - '$id' => '5e5ea5c16897e', - 'userId' => '5e5bb8c16897e', - 'expire' => 1592981250, - 'ip' => '127.0.0.1', - 'osCode' => 'Mac', - 'osName' => 'Mac', - 'osVersion' => 'Mac', - 'clientType' => 'browser', - 'clientCode' => 'CM', - 'clientName' => 'Chrome Mobile iOS', - 'clientVersion' => '84.0', - 'clientEngine' => 'WebKit', - 'clientEngineVersion' => '605.1.15', - 'deviceName' => 'smartphone', - 'deviceBrand' => 'Google', - 'deviceModel' => 'Nexus 5', - 'countryCode' => 'US', - 'countryName' => 'United States', - 'current' => true - ]; - - $model = Response::MODEL_SESSION; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['userId'], '5e5bb8c16897e'); - $this->assertEquals($parsedResponse['expire'], 1592981250); - $this->assertEquals($parsedResponse['ip'], '127.0.0.1'); - $this->assertEquals($parsedResponse['osCode'], 'Mac'); - $this->assertEquals($parsedResponse['osName'], 'Mac'); - $this->assertEquals($parsedResponse['osVersion'], 'Mac'); - $this->assertEquals($parsedResponse['clientType'], 'browser'); - $this->assertEquals($parsedResponse['clientCode'], 'CM'); - $this->assertEquals($parsedResponse['clientName'], 'Chrome Mobile iOS'); - $this->assertEquals($parsedResponse['clientVersion'], '84.0'); - $this->assertEquals($parsedResponse['clientEngine'], 'WebKit'); - $this->assertEquals($parsedResponse['clientEngineVersion'], '605.1.15'); - $this->assertEquals($parsedResponse['deviceName'], 'smartphone'); - $this->assertEquals($parsedResponse['deviceBrand'], 'Google'); - $this->assertEquals($parsedResponse['deviceModel'], 'Nexus 5'); - $this->assertEquals($parsedResponse['countryCode'], 'US'); - $this->assertEquals($parsedResponse['countryName'], 'United States'); - $this->assertEquals($parsedResponse['current'], true); - $this->assertEquals($parsedResponse['type'], Auth::TOKEN_TYPE_LOGIN); - } - - public function testParseSessionList() - { - $content = [ - 'sum' => 1, - 'sessions' => [ - 0 => [ - '$id' => '5e5ea5c16897e', - 'userId' => '5e5bb8c16897e', - 'expire' => 1592981250, - 'ip' => '127.0.0.1', - 'osCode' => 'Mac', - 'osName' => 'Mac', - 'osVersion' => 'Mac', - 'clientType' => 'browser', - 'clientCode' => 'CM', - 'clientName' => 'Chrome Mobile iOS', - 'clientVersion' => '84.0', - 'clientEngine' => 'WebKit', - 'clientEngineVersion' => '605.1.15', - 'deviceName' => 'smartphone', - 'deviceBrand' => 'Google', - 'deviceModel' => 'Nexus 5', - 'countryCode' => 'US', - 'countryName' => 'United States', - 'current' => true - ] - ] - ]; - - $model = Response::MODEL_SESSION_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['sessions'][0]['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['sessions'][0]['brand'], 'Google'); - $this->assertEquals($parsedResponse['sessions'][0]['current'], true); - $this->assertEquals($parsedResponse['sessions'][0]['device'], 'smartphone'); - $this->assertEquals($parsedResponse['sessions'][0]['ip'], '127.0.0.1'); - $this->assertEquals($parsedResponse['sessions'][0]['model'], 'Nexus 5'); - - $this->assertEquals($parsedResponse['sessions'][0]['OS']['name'], 'Mac'); - $this->assertEquals($parsedResponse['sessions'][0]['OS']['platform'], ''); - $this->assertEquals($parsedResponse['sessions'][0]['OS']['short_name'], 'Mac'); - $this->assertEquals($parsedResponse['sessions'][0]['OS']['version'], 'Mac'); - - $this->assertEquals($parsedResponse['sessions'][0]['client']['engine'], 'WebKit'); - $this->assertEquals($parsedResponse['sessions'][0]['client']['name'], 'Chrome Mobile iOS'); - $this->assertEquals($parsedResponse['sessions'][0]['client']['short_name'], 'CM'); - $this->assertEquals($parsedResponse['sessions'][0]['client']['type'], 'browser'); - $this->assertEquals($parsedResponse['sessions'][0]['client']['version'], '84.0'); - - $this->assertEquals($parsedResponse['sessions'][0]['geo']['isoCode'], 'US'); - $this->assertEquals($parsedResponse['sessions'][0]['geo']['country'], 'United States'); - } - - public function testParseLogList() - { - $content = [ - 'sum' => 1, - 'logs' => [ - 0 => [ - 'event' => 'account.sessions.create', - 'ip' => '127.0.0.1', - 'time' => 1592981250, - 'osCode' => 'Mac', - 'osName' => 'Mac', - 'osVersion' => 'Mac', - 'clientType' => 'browser', - 'clientCode' => 'CM', - 'clientName' => 'Chrome Mobile iOS', - 'clientVersion' => '84.0', - 'clientEngine' => 'WebKit', - 'clientEngineVersion' => '605.1.15', - 'deviceName' => 'smartphone', - 'deviceBrand' => 'Google', - 'deviceModel' => 'Nexus 5', - 'countryCode' => 'US', - 'countryName' => 'United States' - ] - ] - ]; - - $model = Response::MODEL_LOG_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['logs'][0]['brand'], 'Google'); - $this->assertEquals($parsedResponse['logs'][0]['device'], 'smartphone'); - $this->assertEquals($parsedResponse['logs'][0]['event'], 'account.sessions.create'); - $this->assertEquals($parsedResponse['logs'][0]['ip'], '127.0.0.1'); - $this->assertEquals($parsedResponse['logs'][0]['model'], 'Nexus 5'); - $this->assertEquals($parsedResponse['logs'][0]['time'], 1592981250); - - $this->assertEquals($parsedResponse['logs'][0]['OS']['name'], 'Mac'); - $this->assertEquals($parsedResponse['logs'][0]['OS']['platform'], ''); - $this->assertEquals($parsedResponse['logs'][0]['OS']['short_name'], 'Mac'); - $this->assertEquals($parsedResponse['logs'][0]['OS']['version'], 'Mac'); - - $this->assertEquals($parsedResponse['logs'][0]['client']['engine'], 'WebKit'); - $this->assertEquals($parsedResponse['logs'][0]['client']['name'], 'Chrome Mobile iOS'); - $this->assertEquals($parsedResponse['logs'][0]['client']['short_name'], 'CM'); - $this->assertEquals($parsedResponse['logs'][0]['client']['type'], 'browser'); - $this->assertEquals($parsedResponse['logs'][0]['client']['version'], '84.0'); - - $this->assertEquals($parsedResponse['logs'][0]['geo']['isoCode'], 'US'); - $this->assertEquals($parsedResponse['logs'][0]['geo']['country'], 'United States'); - } - - public function testParseTeam() - { - $content = [ - '$id' => '5ff45ef261829', - 'name' => 'test', - 'dateCreated' => 1592981250, - 'sum' => 7 - ]; - - $model = Response::MODEL_TEAM; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['$id'], '5ff45ef261829'); - $this->assertEquals($parsedResponse['name'], 'test'); - $this->assertEquals($parsedResponse['dateCreated'], 1592981250); - $this->assertEquals($parsedResponse['sum'], 7); - $this->assertEquals($parsedResponse['$collection'], 'teams'); - $this->assertEquals($parsedResponse['$permissions'], []); - } - - public function testParseTeamList() - { - $content = [ - 'sum' => 1, - 'teams' => [ - 0 => [ - '$id' => '5ff45ef261829', - 'name' => 'test', - 'dateCreated' => 1592981250, - 'sum' => 7 - ] - ] - ]; - - $model = Response::MODEL_TEAM_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['teams'][0]['$id'], '5ff45ef261829'); - $this->assertEquals($parsedResponse['teams'][0]['name'], 'test'); - $this->assertEquals($parsedResponse['teams'][0]['dateCreated'], 1592981250); - $this->assertEquals($parsedResponse['teams'][0]['sum'], 7); - $this->assertEquals($parsedResponse['teams'][0]['$collection'], 'teams'); - $this->assertEquals($parsedResponse['teams'][0]['$permissions'], []); - - } - - public function testParseToken() - { - $content = [ - '$id' => 'bb8ea5c16897e', - 'userId' => '5e5ea5c168bb8', - 'secret' => '', - 'expire' => 1592981250 - ]; - - $model = Response::MODEL_TOKEN; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['$id'], 'bb8ea5c16897e'); - $this->assertEquals($parsedResponse['userId'], '5e5ea5c168bb8'); - $this->assertEquals($parsedResponse['expire'], 1592981250); - $this->assertEquals($parsedResponse['secret'], ''); - $this->assertEquals($parsedResponse['type'], Auth::TOKEN_TYPE_RECOVERY); - } - - public function testParseLocale() - { - $content = [ - 'ip' => '127.0.0.1', - 'countryCode' => 'US', - 'country' => 'United States', - 'continentCode' => 'NA', - 'continent' => 'North America', - 'eu' => false, - 'currency' => 'USD' - ]; - - $model = Response::MODEL_LOCALE; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['ip'], '127.0.0.1'); - $this->assertEquals($parsedResponse['countryCode'], 'US'); - $this->assertEquals($parsedResponse['country'], 'United States'); - $this->assertEquals($parsedResponse['continentCode'], 'NA'); - $this->assertEquals($parsedResponse['continent'], 'North America'); - $this->assertEquals($parsedResponse['eu'], false); - $this->assertEquals($parsedResponse['currency'], 'USD'); - } - - public function testParseCountryList() - { - $content = [ - 'sum' => 1, - 'countries' => [ - 0 => [ - 'name' => 'United States', - 'code' => 'US' - ] - ] - ]; - - $model = Response::MODEL_COUNTRY_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['countries']['US'], 'United States'); - } - - public function testParsePhoneList() - { - $content = [ - 'sum' => 1, - 'phones' => [ - 0 => [ - 'code' => '+1', - 'countryCode' => 'US', - 'countryName' => 'United States' - ] - ] - ]; - - $model = Response::MODEL_PHONE_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['phones']['US'], '+1'); - } - - public function testParseContinentList() - { - $content = [ - 'sum' => 1, - 'continents' => [ - 0 => [ - 'name' => 'Europe', - 'code' => 'EU', - ] - ] - ]; - - $model = Response::MODEL_CONTINENT_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['continents']['EU'], 'Europe'); - } - - public function testParseCurrencyList() - { - $content = [ - 'sum' => 1, - 'currencies' => [ - 0 => [ - 'symbol' => '$', - 'name' => 'US dollar', - 'symbolNative' => '$', - 'decimalDigits' => 2, - 'rounding' => 0, - 'code' => 'USD', - 'namePlural' => 'US Dollars' - ] - ] - ]; - - $model = Response::MODEL_CURRENCY_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['currencies'][0]['symbol'], '$'); - $this->assertEquals($parsedResponse['currencies'][0]['name'], 'US dollar'); - $this->assertEquals($parsedResponse['currencies'][0]['symbolNative'], '$'); - $this->assertEquals($parsedResponse['currencies'][0]['decimalDigits'], 2); - $this->assertEquals($parsedResponse['currencies'][0]['rounding'], 0); - $this->assertEquals($parsedResponse['currencies'][0]['code'], 'USD'); - $this->assertEquals($parsedResponse['currencies'][0]['namePlural'], 'US Dollars'); - $this->assertEquals($parsedResponse['currencies'][0]['locations'], []); - } - - public function testParseFile() - { - $content = [ - '$id' => '5e5ea5c16897e', - '$permissions' => ['read' => ['role:all'], 'write' => ['role:all']], - 'name' => 'Pink.png', - 'dateCreated' => 1592981250, - 'signature' => '5d529fd02b544198ae075bd57c1762bb', - 'mimeType' => 'image/png', - 'sizeOriginal' => 17890 - ]; - - $model = Response::MODEL_FILE; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['$permissions'], ['read' => ['role:all'], 'write' => ['role:all']]); - $this->assertEquals($parsedResponse['name'], 'Pink.png'); - $this->assertEquals($parsedResponse['dateCreated'], 1592981250); - $this->assertEquals($parsedResponse['signature'], '5d529fd02b544198ae075bd57c1762bb'); - $this->assertEquals($parsedResponse['mimeType'], 'image/png'); - $this->assertEquals($parsedResponse['sizeOriginal'], 17890); - $this->assertEquals($parsedResponse['$collection'], Database::SYSTEM_COLLECTION_FILES); - $this->assertEquals($parsedResponse['algorithm'], 'gzip'); - $this->assertEquals($parsedResponse['comment'], ''); - $this->assertEquals($parsedResponse['fileOpenSSLCipher'], OpenSSL::CIPHER_AES_128_GCM); - $this->assertEquals($parsedResponse['fileOpenSSLIV'], ''); - $this->assertEquals($parsedResponse['fileOpenSSLTag'], ''); - $this->assertEquals($parsedResponse['fileOpenSSLVersion'], ''); - $this->assertEquals($parsedResponse['folderId'], ''); - $this->assertEquals($parsedResponse['path'], ''); - $this->assertEquals($parsedResponse['sizeActual'], $content['sizeOriginal']); - $this->assertEquals($parsedResponse['token'], ''); - } - - public function testParseCollection() - { - $content = [ - '$id' => '5e5ea5c16897e', - '$permissions' => ['read' => ['role:all'], 'write' => ['role:all']], - 'name' => 'Movies', - 'dateCreated' => 1592981250, - 'dateUpdated' => '5d529fd02b544198ae075bd57c1762bb', - 'rules' => [] - ]; - - $model = Response::MODEL_COLLECTION; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['$permissions'], ['read' => ['role:all'], 'write' => ['role:all']]); - $this->assertEquals($parsedResponse['name'], 'Movies'); - $this->assertEquals($parsedResponse['dateCreated'], 1592981250); - $this->assertEquals($parsedResponse['dateUpdated'], '5d529fd02b544198ae075bd57c1762bb'); - $this->assertEquals($parsedResponse['rules'], []); - $this->assertEquals($parsedResponse['$collection'], Database::SYSTEM_COLLECTION_COLLECTIONS); - $this->assertEquals($parsedResponse['structure'], true); - } - - public function testParseCollectionList() - { - - $content = [ - 'sum' => 1, - 'collections' => [ - 0 => [ - '$id' => '5e5ea5c16897e', - '$permissions' => ['read' => ['role:all'], 'write' => ['role:all']], - 'name' => 'Movies', - 'dateCreated' => 1592981250, - 'dateUpdated' => '5d529fd02b544198ae075bd57c1762bb', - 'rules' => [] - ] - ] - ]; - - $model = Response::MODEL_COLLECTION_LIST; - $parsedResponse = $this->filter->parse($content, $model); - - $this->assertEquals($parsedResponse['sum'], 1); - $this->assertEquals($parsedResponse['collections'][0]['$id'], '5e5ea5c16897e'); - $this->assertEquals($parsedResponse['collections'][0]['$permissions'], ['read' => ['role:all'], 'write' => ['role:all']]); - $this->assertEquals($parsedResponse['collections'][0]['name'], 'Movies'); - $this->assertEquals($parsedResponse['collections'][0]['dateCreated'], 1592981250); - $this->assertEquals($parsedResponse['collections'][0]['dateUpdated'], '5d529fd02b544198ae075bd57c1762bb'); - $this->assertEquals($parsedResponse['collections'][0]['rules'], []); - $this->assertEquals($parsedResponse['collections'][0]['$collection'], Database::SYSTEM_COLLECTION_COLLECTIONS); - $this->assertEquals($parsedResponse['collections'][0]['structure'], true); - } -} \ No newline at end of file diff --git a/tests/unit/Utopia/ResponseTest.php b/tests/unit/Utopia/ResponseTest.php index da555fde0d..d59b81eb54 100644 --- a/tests/unit/Utopia/ResponseTest.php +++ b/tests/unit/Utopia/ResponseTest.php @@ -3,7 +3,7 @@ namespace Appwrite\Tests; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Filters\V06; +use Appwrite\Utopia\Response\Filters\V11; use PHPUnit\Framework\TestCase; use Swoole\Http\Response as SwooleResponse; @@ -25,7 +25,7 @@ class ResponseTest extends TestCase $this->assertEquals($this->object->hasFilter(), false); $this->assertEquals($this->object->getFilter(), null); - $filter = new V06(); + $filter = new V11(); $this->object->setFilter($filter); $this->assertEquals($this->object->hasFilter(), true);