Removed the tasks service
This commit is contained in:
parent
5dfa6217d8
commit
95dacecf3a
|
@ -238,7 +238,6 @@ RUN chmod +x /usr/local/bin/doctor && \
|
|||
chmod +x /usr/local/bin/worker-deletes && \
|
||||
chmod +x /usr/local/bin/worker-functions && \
|
||||
chmod +x /usr/local/bin/worker-mails && \
|
||||
chmod +x /usr/local/bin/worker-tasks && \
|
||||
chmod +x /usr/local/bin/worker-usage && \
|
||||
chmod +x /usr/local/bin/worker-webhooks
|
||||
|
||||
|
|
|
@ -807,16 +807,6 @@ $collections = [
|
|||
'array' => true,
|
||||
'list' => [Database::SYSTEM_COLLECTION_KEYS],
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'Tasks',
|
||||
'key' => 'tasks',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT,
|
||||
'default' => [],
|
||||
'required' => false,
|
||||
'array' => true,
|
||||
'list' => [Database::SYSTEM_COLLECTION_TASKS],
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'Platforms',
|
||||
|
@ -939,160 +929,6 @@ $collections = [
|
|||
],
|
||||
],
|
||||
],
|
||||
Database::SYSTEM_COLLECTION_TASKS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_TASKS,
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Task',
|
||||
'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' => 'Status',
|
||||
'key' => 'status',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'Updated',
|
||||
'key' => 'updated',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$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' => 'Previous',
|
||||
'key' => 'previous',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'Next',
|
||||
'key' => 'next',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'Duration',
|
||||
'key' => 'duration',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'Delay',
|
||||
'key' => 'delay',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
|
||||
'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 Method',
|
||||
'key' => 'httpMethod',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'HTTP URL',
|
||||
'key' => 'httpUrl',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'label' => 'HTTP Headers',
|
||||
'key' => 'httpHeaders',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
'array' => true,
|
||||
],
|
||||
[
|
||||
'$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'],
|
||||
],
|
||||
[
|
||||
'$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' => 'Failures',
|
||||
'key' => 'failures',
|
||||
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
Database::SYSTEM_COLLECTION_PLATFORMS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
|
|
|
@ -188,17 +188,6 @@ $collections = [
|
|||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
[
|
||||
'$id' => 'tasks',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
[
|
||||
'$id' => 'domains',
|
||||
'type' => Database::VAR_STRING,
|
||||
|
|
|
@ -152,7 +152,7 @@ return [
|
|||
'name' => 'Console',
|
||||
'enabled' => false,
|
||||
'beta' => false,
|
||||
'languages' => [ // TODO change key to 'sdks'
|
||||
'languages' => [
|
||||
[
|
||||
'key' => 'web',
|
||||
'name' => 'Console',
|
||||
|
@ -179,7 +179,7 @@ return [
|
|||
'description' => 'Libraries for integrating with Appwrite to build server side integrations. Read the [getting started for server](/docs/getting-started-for-server) tutorial to start building your first server integration.',
|
||||
'enabled' => true,
|
||||
'beta' => false,
|
||||
'languages' => [ // TODO change key to 'sdks'
|
||||
'languages' => [
|
||||
[
|
||||
'key' => 'nodejs',
|
||||
'name' => 'Node.js',
|
||||
|
|
|
@ -40,8 +40,6 @@ $admins = [
|
|||
'platforms.write',
|
||||
'keys.read',
|
||||
'keys.write',
|
||||
'tasks.read',
|
||||
'tasks.write',
|
||||
'webhooks.read',
|
||||
'webhooks.write',
|
||||
'locale.read',
|
||||
|
|
|
@ -1156,8 +1156,8 @@ App::delete('/v1/account')
|
|||
$protocol = $request->getProtocol();
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
|
||||
|
||||
//TODO delete all tokens or only current session?
|
||||
//TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
|
||||
// TODO delete all tokens or only current session?
|
||||
// TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
|
||||
/*
|
||||
* Data to delete
|
||||
* * Tokens
|
||||
|
@ -1550,7 +1550,7 @@ App::post('/v1/account/verification')
|
|||
->label('sdk.response.model', Response::MODEL_TOKEN)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
|
|
@ -133,21 +133,6 @@ App::get('/v1/health/queue/webhooks')
|
|||
$response->json(['size' => Resque::size(Event::WEBHOOK_QUEUE_NAME)]);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/tasks')
|
||||
->desc('Get Tasks Queue')
|
||||
->groups(['api', 'health'])
|
||||
->label('scope', 'health.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'health')
|
||||
->label('sdk.method', 'getQueueTasks')
|
||||
->label('sdk.description', '/docs/references/health/get-queue-tasks.md')
|
||||
->inject('response')
|
||||
->action(function ($response) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
|
||||
$response->json(['size' => Resque::size(Event::TASK_QUEUE_NAME)]);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/logs')
|
||||
->desc('Get Logs Queue')
|
||||
->groups(['api', 'health'])
|
||||
|
|
|
@ -80,7 +80,6 @@ App::post('/v1/projects')
|
|||
'platforms' => [],
|
||||
'webhooks' => [],
|
||||
'keys' => [],
|
||||
'tasks' => [],
|
||||
'domains' => [],
|
||||
'usersAuthEmailPassword' => true,
|
||||
'usersAuthAnonymous' => true,
|
||||
|
@ -332,9 +331,6 @@ App::get('/v1/projects/:projectId/usage')
|
|||
$documents[] = ['name' => $collection['name'], 'total' => $projectDB->getSum()];
|
||||
}
|
||||
|
||||
// Tasks
|
||||
$tasksTotal = \count($project->getAttribute('tasks', []));
|
||||
|
||||
$response->json([
|
||||
'range' => $range,
|
||||
'requests' => [
|
||||
|
@ -369,10 +365,6 @@ App::get('/v1/projects/:projectId/usage')
|
|||
'data' => [],
|
||||
'total' => $usersTotal,
|
||||
],
|
||||
'tasks' => [
|
||||
'data' => [],
|
||||
'total' => $tasksTotal,
|
||||
],
|
||||
'storage' => [
|
||||
'total' => $projectDB->getCount(
|
||||
[
|
||||
|
@ -966,238 +958,6 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
|||
$response->noContent();
|
||||
});
|
||||
|
||||
// Tasks
|
||||
|
||||
App::post('/v1/projects/:projectId/tasks')
|
||||
->desc('Create Task')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'createTask')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TASK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Task name. Max length: 128 chars.')
|
||||
->param('status', null, new WhiteList(['play', 'pause'], true), 'Task status.')
|
||||
->param('schedule', null, new Cron(), 'Task schedule CRON syntax.')
|
||||
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
|
||||
->param('httpMethod', '', new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], true), 'Task HTTP method.')
|
||||
->param('httpUrl', '', new URL(), 'Task HTTP URL')
|
||||
->param('httpHeaders', null, new ArrayList(new Text(256)), 'Task HTTP headers list.', true)
|
||||
->param('httpUser', '', new Text(256), 'Task HTTP user. Max length: 256 chars.', true)
|
||||
->param('httpPass', '', new Text(256), 'Task HTTP password. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function ($projectId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass, $response, $dbForConsole) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
$cron = new CronExpression($schedule);
|
||||
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
|
||||
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
|
||||
|
||||
$task = new Document([
|
||||
'$id' => $dbForConsole->getId(),
|
||||
'projectId' => $project->getId(),
|
||||
'name' => $name,
|
||||
'status' => $status,
|
||||
'schedule' => $schedule,
|
||||
'updated' => \time(),
|
||||
'previous' => null,
|
||||
'next' => $next,
|
||||
'security' => $security,
|
||||
'httpMethod' => $httpMethod,
|
||||
'httpUrl' => $httpUrl,
|
||||
'httpHeaders' => $httpHeaders,
|
||||
'httpUser' => $httpUser,
|
||||
'httpPass' => $httpPass,
|
||||
'log' => '{}',
|
||||
'failures' => 0,
|
||||
]);
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('tasks', $task, Document::SET_TYPE_APPEND)
|
||||
);
|
||||
|
||||
if ($next) {
|
||||
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy());
|
||||
}
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($task, Response::MODEL_TASK);
|
||||
});
|
||||
|
||||
App::get('/v1/projects/:projectId/tasks')
|
||||
->desc('List Tasks')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'listTasks')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TASK_LIST)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function ($projectId, $response, $dbForConsole) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
$tasks = $project->getAttribute('tasks', []);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'tasks' => $tasks,
|
||||
'sum' => count($tasks),
|
||||
]), Response::MODEL_TASK_LIST);
|
||||
|
||||
});
|
||||
|
||||
App::get('/v1/projects/:projectId/tasks/:taskId')
|
||||
->desc('Get Task')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'getTask')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TASK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('taskId', null, new UID(), 'Task unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function ($projectId, $taskId, $response, $dbForConsole) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
$task = $project->find('$id', $taskId, 'tasks');
|
||||
|
||||
if (empty($task) || !$task instanceof Document) {
|
||||
throw new Exception('Task not found', 404);
|
||||
}
|
||||
|
||||
$response->dynamic($task, Response::MODEL_TASK);
|
||||
});
|
||||
|
||||
App::put('/v1/projects/:projectId/tasks/:taskId')
|
||||
->desc('Update Task')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'updateTask')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TASK)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('taskId', null, new UID(), 'Task unique ID.')
|
||||
->param('name', null, new Text(128), 'Task name. Max length: 128 chars.')
|
||||
->param('status', null, new WhiteList(['play', 'pause'], true), 'Task status.')
|
||||
->param('schedule', null, new Cron(), 'Task schedule CRON syntax.')
|
||||
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
|
||||
->param('httpMethod', '', new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], true), 'Task HTTP method.')
|
||||
->param('httpUrl', '', new URL(), 'Task HTTP URL.')
|
||||
->param('httpHeaders', null, new ArrayList(new Text(256)), 'Task HTTP headers list.', true)
|
||||
->param('httpUser', '', new Text(256), 'Task HTTP user. Max length: 256 chars.', true)
|
||||
->param('httpPass', '', new Text(256), 'Task HTTP password. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function ($projectId, $taskId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass, $response, $dbForConsole) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
$task = $project->find('$id', $taskId, 'tasks');
|
||||
|
||||
if (empty($task) || !$task instanceof Document) {
|
||||
throw new Exception('Task not found', 404);
|
||||
}
|
||||
|
||||
$cron = new CronExpression($schedule);
|
||||
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
|
||||
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
|
||||
|
||||
$project->findAndReplace('$id', $task->getId(), $task
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('status', $status)
|
||||
->setAttribute('schedule', $schedule)
|
||||
->setAttribute('updated', \time())
|
||||
->setAttribute('next', $next)
|
||||
->setAttribute('security', $security)
|
||||
->setAttribute('httpMethod', $httpMethod)
|
||||
->setAttribute('httpUrl', $httpUrl)
|
||||
->setAttribute('httpHeaders', $httpHeaders)
|
||||
->setAttribute('httpUser', $httpUser)
|
||||
->setAttribute('httpPass', $httpPass)
|
||||
, 'tasks');
|
||||
|
||||
$dbForConsole->updateDocument('projects', $project->getId(), $project);
|
||||
|
||||
if ($next) {
|
||||
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy());
|
||||
}
|
||||
|
||||
$response->dynamic($task, Response::MODEL_TASK);
|
||||
});
|
||||
|
||||
App::delete('/v1/projects/:projectId/tasks/:taskId')
|
||||
->desc('Delete Task')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'deleteTask')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('projectId', null, new UID(), 'Project unique ID.')
|
||||
->param('taskId', null, new UID(), 'Task unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function ($projectId, $taskId, $response, $dbForConsole) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
if (!$project->findAndRemove('$id', $taskId, 'tasks')) {
|
||||
throw new Exception('Task not found', 404);
|
||||
}
|
||||
|
||||
$dbForConsole->updateDocument('projects', $project->getId(), $project);
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
// Platforms
|
||||
|
||||
App::post('/v1/projects/:projectId/platforms')
|
||||
|
|
|
@ -246,7 +246,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
->param('email', '', new Email(), 'New team member email.')
|
||||
->param('name', '', new Text(128), 'New team member name. Max length: 128 chars.', true)
|
||||
->param('roles', [], new ArrayList(new Key()), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.')
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients'])
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('user')
|
||||
|
@ -517,7 +517,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
|||
$membership->setAttribute('roles', $roles);
|
||||
$membership = $dbForInternal->updateDocument('memberships', $membership->getId(), $membership);
|
||||
|
||||
//TODO sync updated membership in the user $profile object using TYPE_REPLACE
|
||||
// TODO sync updated membership in the user $profile object using TYPE_REPLACE
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
|
|
|
@ -447,7 +447,6 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
}
|
||||
}
|
||||
|
||||
// TODO : Response filter implementation
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
@ -538,6 +537,5 @@ App::delete('/v1/users/:userId')
|
|||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
|
||||
// TODO : Response filter implementation
|
||||
$response->noContent();
|
||||
});
|
||||
|
|
|
@ -44,7 +44,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
|||
->setParam('{url}', $request->getHostname().$route->getURL())
|
||||
;
|
||||
|
||||
//TODO make sure we get array here
|
||||
// TODO make sure we get array here
|
||||
|
||||
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
|
||||
if(!empty($value)) {
|
||||
|
@ -217,7 +217,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
|||
$route = $utopia->match($request);
|
||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
||||
&& $project->getId()
|
||||
&& $mode !== APP_MODE_ADMIN //TODO: add check to make sure user is admin
|
||||
&& $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin
|
||||
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode
|
||||
|
||||
$usage
|
||||
|
|
|
@ -189,21 +189,6 @@ App::get('/console/keys')
|
|||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
App::get('/console/tasks')
|
||||
->groups(['web', 'console'])
|
||||
->label('permission', 'public')
|
||||
->label('scope', 'console')
|
||||
->inject('layout')
|
||||
->action(function ($layout) {
|
||||
/** @var Utopia\View $layout */
|
||||
|
||||
$page = new View(__DIR__.'/../../views/console/tasks/index.phtml');
|
||||
|
||||
$layout
|
||||
->setParam('title', APP_NAME.' - Tasks')
|
||||
->setParam('body', $page);
|
||||
});
|
||||
|
||||
App::get('/console/database')
|
||||
->groups(['web', 'console'])
|
||||
->label('permission', 'public')
|
||||
|
|
|
@ -142,16 +142,6 @@
|
|||
<b class="subtitle">MANAGE</b>
|
||||
|
||||
<ul class="links">
|
||||
<li>
|
||||
<a data-ls-attrs="href=/console/tasks?project={{router.params.project}}"
|
||||
data-analytics
|
||||
data-analytics-event="click"
|
||||
data-analytics-category="console/navigation"
|
||||
data-analytics-label="Tasks Link">
|
||||
<i class="icon-clock"></i>
|
||||
Tasks
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-ls-attrs="href=/console/webhooks?project={{router.params.project}}"
|
||||
data-analytics
|
||||
|
|
|
@ -18,7 +18,6 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/settings?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-cog"></i> Settings</a> </li>
|
||||
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/keys?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-key-inv"></i> API Keys</a> </li>
|
||||
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/webhooks?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-link"></i> Webhooks</a> </li>
|
||||
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/tasks?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-clock"></i> Tasks</a> </li>
|
||||
</ul>
|
||||
|
||||
<div class="margin-bottom phones-only"> </div>
|
||||
|
@ -115,25 +114,21 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
|
|||
|
||||
<div class="box dashboard">
|
||||
<div class="row responsive">
|
||||
<div class="col span-3">
|
||||
<div class="col span-4">
|
||||
<div class="value"><span class="sum" data-ls-bind="{{usage.documents.total|statsTotal}}" data-default="0">0</span></div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Documents</b></div>
|
||||
</div>
|
||||
<div class="col span-3">
|
||||
<div class="col span-4">
|
||||
<div class="value">
|
||||
<span class="sum" data-ls-bind="{{usage.storage.total|humanFileSize}}" data-default="0">0</span>
|
||||
<span data-ls-bind="{{usage.storage.total|humanFileUnit}}" class="text-size-small unit"></span>
|
||||
</div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Storage</b></div>
|
||||
</div>
|
||||
<div class="col span-3">
|
||||
<div class="col span-4">
|
||||
<div class="value"><span class="sum" data-ls-bind="{{usage.users.total}}" data-default="0">0</span></div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Users</b></div>
|
||||
</div>
|
||||
<div class="col span-3">
|
||||
<div class="value"><span class="sum" data-ls-bind="{{usage.tasks.total}}" data-default="0">0</span></div>
|
||||
<div class="margin-top-small"><b class="text-size-small unit">Tasks</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,355 +0,0 @@
|
|||
<div class="cover margin-bottom-large">
|
||||
<h1 class="zone xl margin-bottom-large">
|
||||
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
|
||||
<br />
|
||||
|
||||
<span>Tasks</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="zone xl"
|
||||
data-service="projects.listTasks"
|
||||
data-scope="console"
|
||||
data-event="load,projects.createTask,projects.updateTask,projects.deleteTask"
|
||||
data-name="console-tasks"
|
||||
data-param-project-id="{{router.params.project}}"
|
||||
data-success="trigger"
|
||||
data-success-param-trigger-events="projects.listTasks">
|
||||
|
||||
<div data-ls-if="0 === {{console-tasks.sum}} || undefined === {{console-tasks.sum}}" class="box margin-top margin-bottom">
|
||||
<h3 class="margin-bottom-small text-bold">No Tasks Found</h3>
|
||||
|
||||
<p class="margin-bottom-no">You haven't created any tasks for your project yet.</p>
|
||||
</div>
|
||||
|
||||
<div class="box y-scroll margin-bottom" data-ls-if="0 != {{console-tasks.sum}}">
|
||||
<table class="full vertical">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th width="140">Status</th>
|
||||
<th width="180">Schedule</th>
|
||||
<th width="140"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-ls-loop="console-tasks.tasks" data-ls-as="task" class="list">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="margin-bottom-tiny text-one-liner">
|
||||
<span data-ls-attrs="title={{task.name}} ({{task.failures}} errors)" data-ls-bind="{{task.name}}"></span>
|
||||
|
||||
<span data-ls-if="false === {{task.security}}">
|
||||
<span class="text-danger">SSL/TLS Disabled</span>
|
||||
</span>
|
||||
<span data-ls-if="0 !== {{task.failures}}">
|
||||
<span class="text-danger" data-ls-bind="({{task.failures}} errors)"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a data-ls-attrs="href={{task.httpUrl}}" data-ls-bind="{{task.httpUrl}}" target="_blank" class="text-one-liner text-size-small"></a>
|
||||
</td>
|
||||
<td data-title="" style="vertical-align: middle">
|
||||
<span data-ls-if="'play' === {{task.status}}">
|
||||
<span class="tag green"><i class="icon-play"></i> Running </span>
|
||||
</span>
|
||||
<span data-ls-if="'play' !== {{task.status}}">
|
||||
<span class="tag red"><i class="icon-pause"></i> Paused </span>
|
||||
</span>
|
||||
</td>
|
||||
<td data-title="" style="vertical-align: middle" class="text-size-small text-fade">
|
||||
<span data-ls-bind="Next: {{task.next|dateTime}}"></span>
|
||||
|
||||
<br />
|
||||
|
||||
<span data-ls-if="undefined !== {{task.previous}} && {{task.previous}}">
|
||||
<span data-ls-bind="Prev: {{task.previous|dateTime}}"></span>
|
||||
|
||||
<!-- <span data-ls-if="undefined !== {{task.delay}} && 59 < {{task.delay}}" class="text-danger margin-top-tiny">
|
||||
<small data-ls-bind="({{task.delay|ms2hum}} Delay)"></small>
|
||||
</span> -->
|
||||
</span>
|
||||
<small data-ls-if="undefined === {{task.previous}}" class="text-size-small">
|
||||
None.
|
||||
</small>
|
||||
</td>
|
||||
<td data-title="">
|
||||
<div data-ui-modal class="modal box sticky-footer close" data-button-alias="none" data-open-event="task-update-{{task.$id}}">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h1>Update Task</h1>
|
||||
|
||||
<form
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Update Project Task"
|
||||
data-service="projects.updateTask"
|
||||
data-scope="console"
|
||||
data-event="submit"
|
||||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated task successfully"
|
||||
data-success-param-trigger-events="projects.updateTask"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to update task"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
<input type="hidden" name="taskId" data-ls-bind="{{task.$id}}" />
|
||||
|
||||
<label data-ls-attrs="for=name-{{task.$id}}">Name</label>
|
||||
<input type="text" class="full-width" data-ls-attrs="id=name-{{task.$id}}" name="name" required autocomplete="off" data-ls-bind="{{task.name}}" maxlength="128" />
|
||||
|
||||
<label data-ls-attrs="for=status-{{task.$id}}" class="margin-bottom">Status
|
||||
<div class="margin-top-small">
|
||||
<input name="status" type="radio" checked="checked" required data-ls-bind="{{task.status}}" value="play" /> <span>Play</span>
|
||||
<input name="status" type="radio" required data-ls-bind="{{task.status}}" value="pause" /> <span>Pause</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label data-ls-attrs="for=schedule-{{task.$id}}">Schedule (CRON Syntax)</label>
|
||||
<input type="text" class="full-width" data-ls-attrs="id=schedule-{{task.$id}}" name="schedule" required autocomplete="off" data-ls-bind="{{task.schedule}}" placeholder="* * * * *" />
|
||||
|
||||
<div class="row responsive thin">
|
||||
<div class="col span-4">
|
||||
<label data-ls-attrs="for=httpMethod-{{task.$id}}">HTTP Method</label>
|
||||
<select data-ls-attrs="id=httpMethod-{{task.$id}}" name="httpMethod" required data-ls-bind="{{task.httpMethod}}">
|
||||
<option value="POST">POST</option>
|
||||
<option value="GET">GET</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
<option value="CONNECT">CONNECT</option>
|
||||
<option value="HEAD">HEAD</option>
|
||||
<option value="TRACE">TRACE</option>
|
||||
<option value="OPTIONS">OPTIONS</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col span-8">
|
||||
<label data-ls-attrs="for=httpUrl-{{task.$id}}">HTTP URL</label>
|
||||
<input type="url" class="full-width" data-ls-attrs="id=httpUrl-{{task.$id}}" name="httpUrl" required autocomplete="off" placeholder="https://example.com/callback" data-ls-bind="{{task.httpUrl}}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="margin-bottom toggle" data-ls-ui-open data-button-aria="Advanced Options">
|
||||
<i class="icon-plus pull-end margin-top-tiny"></i>
|
||||
<i class="icon-minus pull-end margin-top-tiny"></i>
|
||||
|
||||
<h2 class="margin-bottom">
|
||||
Advanced Options
|
||||
<small class="text-size-small">(optional)</small>
|
||||
</h2>
|
||||
|
||||
<label for="httpHeaders" class="text-bold">HTTP Headers</label>
|
||||
|
||||
<input type="hidden" id="httpHeadersInit" name="httpHeaders" data-cast-to="array-empty">
|
||||
|
||||
<div class="margin-bottom-small">
|
||||
<div data-ls-loop="task.httpHeaders" data-ls-as="header" style="overflow: hidden">
|
||||
<div class="margin-bottom-small">
|
||||
<div data-forms-remove class="row thin">
|
||||
<div class="col span-10">
|
||||
<input type="hidden" name="httpHeaders" data-forms-headers data-ls-bind="{{header}}" data-cast-to="array" />
|
||||
</div>
|
||||
<div class="col span-2">
|
||||
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-forms-clone="" data-label="Add Header" data-first="0">
|
||||
<div class="">
|
||||
<div data-forms-remove class="row thin margin-bottom-small">
|
||||
<div class="col span-10">
|
||||
<input type="hidden" name="httpHeaders" data-forms-headers data-cast-to="array" />
|
||||
</div>
|
||||
<div class="col span-2">
|
||||
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label data-ls-attrs="for=security-{{task.$id}}" class="margin-bottom">
|
||||
<div class="margin-bottom-small text-bold">SSL / TLS (Certificate verification)</div>
|
||||
|
||||
<input name="security" type="radio" required data-ls-bind="{{task.security}}" value="true" data-cast-to="boolean" /> <span>Enabled</span>
|
||||
<input name="security" type="radio" required data-ls-bind="{{task.security}}" value="false" data-cast-to="boolean" /> <span>Disabled</span>
|
||||
</label>
|
||||
|
||||
<p class="margin-bottom text-size-small text-fade"><span class="text-red">Warning</span>: Untrusted or self-signed certificates may not be secure.
|
||||
<a href="https://en.wikipedia.org/wiki/Self-signed_certificate" target="_blank" rel="noopener">Learn more<i class="icon-link-ext"></i></a>
|
||||
</p>
|
||||
|
||||
<label class="text-bold">HTTP Authentication <span class="tooltip" data-tooltip="Use to secure your endpoint from untrusted sources"><i class="icon-question"></i></span> <small>(optional)</small></label>
|
||||
|
||||
<div class="row responsive thin">
|
||||
<div class="col span-6 margin-bottom">
|
||||
<label data-ls-attrs="for=httpUser-{{task.$id}}">User</label>
|
||||
<input type="text" class="full-width margin-bottom-no" data-ls-attrs="id=httpUser-{{task.$id}}" name="httpUser" autocomplete="off" data-ls-bind="{{task.httpUser}}" />
|
||||
</div>
|
||||
<div class="col span-6 margin-bottom">
|
||||
<label data-ls-attrs="for=httpPass-{{task.$id}}">Password</label>
|
||||
<input data-forms-show-secret type="password" class="full-width margin-bottom-no" data-ls-attrs="id=httpPass-{{task.$id}}" name="httpPass" autocomplete="off" data-ls-bind="{{task.httpPass}}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button type="submit">Update</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<form
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Delete Project Task"
|
||||
data-service="projects.deleteTask"
|
||||
data-scope="console"
|
||||
data-event="task-delete-{{task.$id}}"
|
||||
data-confirm="Are you sure you want to delete this task?"
|
||||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Deleted task successfully"
|
||||
data-success-param-trigger-events="projects.deleteTask"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to delete task"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
<input type="hidden" name="taskId" data-ls-bind="{{task.$id}}" />
|
||||
</form>
|
||||
|
||||
<button class="pull-end margin-start round desktops-only" data-ls-ui-trigger="task-update-{{task.$id}}"><i class="icon-cog"></i></button>
|
||||
<button class="pull-end reverse danger round desktops-only" data-ls-ui-trigger="task-delete-{{task.$id}}"><i class="icon-trash"></i></button>
|
||||
|
||||
<button class="link pull-start margin-end-small tablets-only phones-only" data-ls-ui-trigger="task-update-{{task.$id}}">Update</button>
|
||||
<button class="link pull-start margin-end text-danger tablets-only phones-only" data-ls-ui-trigger="task-delete-{{task.$id}}">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<div data-ui-modal class="modal box close sticky-footer" data-button-text="Add Task">
|
||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||
|
||||
<h1>Add Task</h1>
|
||||
|
||||
<form
|
||||
data-analytics
|
||||
data-analytics-activity
|
||||
data-analytics-event="submit"
|
||||
data-analytics-category="console"
|
||||
data-analytics-label="Create Project Task"
|
||||
data-service="projects.createTask"
|
||||
data-scope="console"
|
||||
data-event="submit"
|
||||
data-success="alert,trigger,reset"
|
||||
data-success-param-alert-text="Created task successfully"
|
||||
data-success-param-trigger-events="projects.createTask"
|
||||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create task"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="full-width" id="name" name="name" required autocomplete="off" maxlength="128" />
|
||||
|
||||
<label data-ls-attrs="for=status" class="margin-bottom">Status
|
||||
<div class="margin-top-small">
|
||||
<input name="status" type="radio" value="play" checked="checked" required /> <span>Play</span>
|
||||
<input name="status" type="radio" value="pause" required /> <span>Pause</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label for="schedule">Schedule (CRON Syntax)</label>
|
||||
<input type="text" class="full-width" id="schedule" name="schedule" required autocomplete="off" placeholder="* * * * *" />
|
||||
|
||||
<div class="row responsive thin">
|
||||
<div class="col span-4">
|
||||
<label for="httpMethod">HTTP Method</label>
|
||||
<select id="httpMethod" name="httpMethod" required>
|
||||
<option value="POST">POST</option>
|
||||
<option value="GET">GET</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
<option value="CONNECT">CONNECT</option>
|
||||
<option value="HEAD">HEAD</option>
|
||||
<option value="TRACE">TRACE</option>
|
||||
<option value="OPTIONS">OPTIONS</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col span-8">
|
||||
<label for="httpUrl">HTTP URL</label>
|
||||
<input type="url" class="full-width" id="httpUrl" name="httpUrl" required autocomplete="off" placeholder="https://example.com/callback" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="margin-bottom toggle" data-ls-ui-open data-button-aria="Advanced Options">
|
||||
<i class="icon-plus pull-end margin-top-tiny"></i>
|
||||
<i class="icon-minus pull-end margin-top-tiny"></i>
|
||||
|
||||
<h2 class="margin-bottom">
|
||||
Advanced Options
|
||||
<small class="text-size-small">(optional)</small>
|
||||
</h2>
|
||||
|
||||
<label for="httpHeaders" class="text-bold">HTTP Headers</label>
|
||||
|
||||
<input type="hidden" id="httpHeadersInitAdd" name="httpHeaders" data-cast-to="array-empty">
|
||||
|
||||
<div class="margin-bottom-small">
|
||||
<div data-forms-clone="" data-label="Add Header" data-first="0">
|
||||
<div class="">
|
||||
<div data-forms-remove class="row thin margin-bottom-small">
|
||||
<div class="col span-10">
|
||||
<input type="hidden" name="httpHeaders" data-forms-headers data-cast-to="array" />
|
||||
</div>
|
||||
<div class="col span-2">
|
||||
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="secure" class="margin-bottom-small">
|
||||
<div class="margin-bottom-small text-bold">SSL / TLS (Certificate verification)</div>
|
||||
|
||||
<input name="security" data-ls-attrs="id=secure-yes" type="radio" value="1" checked="checked" required /> <span>Enabled</span>
|
||||
<input name="security" data-ls-attrs="id=secure-no" type="radio" value="0" required /> <span>Disabled</span>
|
||||
</label>
|
||||
|
||||
<p class="margin-bottom text-size-small text-fade"><span class="text-red">Warning</span>: Untrusted or self-signed certificates may not be secure.
|
||||
<a href="https://en.wikipedia.org/wiki/Self-signed_certificate" target="_blank" rel="noopener">Learn more<i class="icon-link-ext"></i></a>
|
||||
</p>
|
||||
|
||||
<label class="text-bold">HTTP Authentication <span class="tooltip" data-tooltip="Use to secure your endpoint from untrusted sources"><i class="icon-question"></i></span> <small>(optional)</small></label>
|
||||
|
||||
<div class="row responsive thin">
|
||||
<div class="col span-6 margin-bottom">
|
||||
<label for="httpUser">User</label>
|
||||
<input type="text" class="full-width margin-bottom-no" id="httpUser" name="httpUser" autocomplete="off" />
|
||||
</div>
|
||||
<div class="col span-6 margin-bottom">
|
||||
<label for="httpPass">Password</label>
|
||||
<input type="password" data-forms-show-secret class="full-width margin-bottom-no" id="httpPass" name="httpPass" autocomplete="off" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</footer>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -158,30 +158,6 @@ services:
|
|||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
|
||||
appwrite-worker-tasks:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
entrypoint: worker-tasks
|
||||
container_name: appwrite-worker-tasks
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-worker-deletes:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
entrypoint: worker-deletes
|
||||
|
|
|
@ -120,7 +120,7 @@ Console::info(count($list)." functions listed in " . ($executionEnd - $execution
|
|||
* 7. Trigger usage log - DONE
|
||||
*/
|
||||
|
||||
//TODO avoid scheduled execution if delay is bigger than X offest
|
||||
// TODO avoid scheduled execution if delay is bigger than X offest
|
||||
|
||||
class FunctionsV1 extends Worker
|
||||
{
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Resque\Worker;
|
||||
use Cron\CronExpression;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Redis;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../workers.php';
|
||||
|
||||
Console::title('Tasks V1 Worker');
|
||||
Console::success(APP_NAME.' tasks worker v1 has started');
|
||||
|
||||
class TasksV1 extends Worker
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $args = [];
|
||||
|
||||
public function init(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$projectId = $this->args['projectId'] ?? null;
|
||||
$taskId = $this->args['$id'] ?? null;
|
||||
$updated = $this->args['updated'] ?? null;
|
||||
$next = $this->args['next'] ?? null;
|
||||
$delay = \time() - $next;
|
||||
$errors = [];
|
||||
$timeout = 60 * 5; // 5 minutes
|
||||
$errorLimit = 5;
|
||||
$logLimit = 5;
|
||||
$alert = '';
|
||||
|
||||
$dbForConsole = $this->getConsoleDB();
|
||||
|
||||
/*
|
||||
* 1. Get Original Task
|
||||
* 2. Check for updates
|
||||
* If has updates skip task and don't reschedule
|
||||
* If status not equal to play skip task
|
||||
* 3. Check next run date, update task and add new job at the given date
|
||||
* 4. Execute task (set optional timeout)
|
||||
* 5. Update task response to log
|
||||
* On success reset error count
|
||||
* On failure add error count
|
||||
* If error count bigger than allowed change status to pause
|
||||
*/
|
||||
|
||||
if (empty($taskId)) {
|
||||
throw new Exception('Missing task $id');
|
||||
}
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
// Find the task in the $project->getAttribute('tasks') array
|
||||
$taskIndex = array_search($taskId, array_column($project->getAttributes()['tasks'], '$id'));
|
||||
|
||||
if ($taskIndex === false) {
|
||||
throw new Exception('Task Not Found');
|
||||
}
|
||||
|
||||
$task = $project->getAttribute('tasks')[$taskIndex];
|
||||
|
||||
if ($task->getAttribute('updated') !== $updated) { // Task have already been rescheduled by owner
|
||||
return;
|
||||
}
|
||||
|
||||
if ($task->getAttribute('status') !== 'play') { // Skip task and don't schedule again
|
||||
return;
|
||||
}
|
||||
|
||||
// Reschedule
|
||||
|
||||
$cron = new CronExpression($task->getAttribute('schedule'));
|
||||
$next = (int) $cron->getNextRunDate()->format('U');
|
||||
$headers = (\is_array($task->getAttribute('httpHeaders', []))) ? $task->getAttribute('httpHeaders', []) : [];
|
||||
|
||||
$task
|
||||
->setAttribute('next', $next)
|
||||
->setAttribute('previous', \time())
|
||||
;
|
||||
|
||||
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy()); // Async task rescheduale
|
||||
|
||||
$startTime = \microtime(true);
|
||||
|
||||
// Execute Task
|
||||
|
||||
$ch = \curl_init($task->getAttribute('httpUrl'));
|
||||
|
||||
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $task->getAttribute('httpMethod'));
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, '');
|
||||
\curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
\curl_setopt($ch, CURLOPT_USERAGENT, \sprintf(APP_USERAGENT,
|
||||
App::getEnv('_APP_VERSION', 'UNKNOWN'),
|
||||
App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', APP_EMAIL_SECURITY)
|
||||
));
|
||||
\curl_setopt(
|
||||
$ch,
|
||||
CURLOPT_HTTPHEADER,
|
||||
\array_merge($headers, [
|
||||
'X-'.APP_NAME.'-Task-ID: '.$task->getAttribute('$id', ''),
|
||||
'X-'.APP_NAME.'-Task-Name: '.$task->getAttribute('name', ''),
|
||||
])
|
||||
);
|
||||
\curl_setopt($ch, CURLOPT_HEADER, true); // we want headers
|
||||
\curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
\curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
|
||||
if (!$task->getAttribute('security', true)) {
|
||||
\curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
\curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
}
|
||||
|
||||
$httpUser = $task->getAttribute('httpUser');
|
||||
$httpPass = $task->getAttribute('httpPass');
|
||||
|
||||
if (!empty($httpUser) && !empty($httpPass)) {
|
||||
\curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass");
|
||||
\curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
}
|
||||
|
||||
$response = \curl_exec($ch);
|
||||
|
||||
if (false === $response) {
|
||||
$errors[] = \curl_error($ch).'Failed to execute task';
|
||||
}
|
||||
|
||||
$code = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$codeFamily = \mb_substr($code, 0, 1);
|
||||
$headersSize = \curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$headers = \substr($response, 0, $headersSize);
|
||||
$body = \substr($response, $headersSize);
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
$totalTime = \round(\microtime(true) - $startTime, 2);
|
||||
|
||||
switch ($codeFamily) {
|
||||
case '2':
|
||||
case '3':
|
||||
break;
|
||||
default:
|
||||
$errors[] = 'Request failed with status code '.$code;
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$task->setAttribute('failures', 0);
|
||||
|
||||
$alert = 'Task "'.$task->getAttribute('name').'" Executed Successfully';
|
||||
} else {
|
||||
$task
|
||||
->setAttribute('failures', $task->getAttribute('failures', 0) + 1)
|
||||
->setAttribute('status', ($task->getAttribute('failures') >= $errorLimit) ? 'pause' : 'play')
|
||||
;
|
||||
|
||||
$alert = 'Task "'.$task->getAttribute('name').'" failed to execute with the following errors: '.\implode("\n", $errors);
|
||||
}
|
||||
|
||||
$log = \json_decode($task->getAttribute('log', '{}'), true);
|
||||
|
||||
if (\count($log) >= $logLimit) {
|
||||
\array_pop($log);
|
||||
}
|
||||
|
||||
\array_unshift($log, [
|
||||
'code' => $code,
|
||||
'duration' => $totalTime,
|
||||
'delay' => $delay,
|
||||
'errors' => $errors,
|
||||
'headers' => $headers,
|
||||
'body' => $body,
|
||||
]);
|
||||
|
||||
$task
|
||||
->setAttribute('log', \json_encode($log))
|
||||
->setAttribute('duration', $totalTime)
|
||||
->setAttribute('delay', $delay)
|
||||
;
|
||||
|
||||
$project->findAndReplace('$id', $task->getId(), $task);
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
if (false === $dbForConsole->updateDocument('projects', $project->getId(), $project)) {
|
||||
throw new Exception('Failed saving tasks to DB');
|
||||
}
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
// ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy()); // Sync task rescheduale
|
||||
|
||||
// Send alert if needed (use SMTP as default for now)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public function shutdown(): void
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
|
||||
then
|
||||
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
|
||||
else
|
||||
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
|
||||
fi
|
||||
|
||||
INTERVAL=0.1 QUEUE='v1-tasks' APP_INCLUDE='/usr/src/code/app/workers/tasks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php
|
|
@ -191,33 +191,6 @@ services:
|
|||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
|
||||
appwrite-worker-tasks:
|
||||
entrypoint: worker-tasks
|
||||
container_name: appwrite-worker-tasks
|
||||
build:
|
||||
context: .
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-worker-deletes:
|
||||
entrypoint: worker-deletes
|
||||
container_name: appwrite-worker-deletes
|
||||
|
|
|
@ -304,7 +304,7 @@ class MySQL extends Adapter
|
|||
$st2->execute();
|
||||
}
|
||||
|
||||
//TODO remove this dependency (check if related to nested documents)
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -18,9 +18,8 @@ class Database
|
|||
const SYSTEM_COLLECTION_PROJECTS = 'projects';
|
||||
const SYSTEM_COLLECTION_WEBHOOKS = 'webhooks';
|
||||
const SYSTEM_COLLECTION_KEYS = 'keys';
|
||||
const SYSTEM_COLLECTION_TASKS = 'tasks';
|
||||
const SYSTEM_COLLECTION_PLATFORMS = 'platforms';
|
||||
const SYSTEM_COLLECTION_USAGES = 'usages'; //TODO add structure
|
||||
const SYSTEM_COLLECTION_USAGES = 'usages'; // TODO add structure
|
||||
const SYSTEM_COLLECTION_DOMAINS = 'domains';
|
||||
const SYSTEM_COLLECTION_CERTIFICATES = 'certificates';
|
||||
const SYSTEM_COLLECTION_RESERVED = 'reserved';
|
||||
|
|
|
@ -28,7 +28,6 @@ class Event
|
|||
const WEBHOOK_QUEUE_NAME = 'v1-webhooks';
|
||||
const WEBHOOK_CLASS_NAME = 'WebhooksV1';
|
||||
|
||||
const TASK_QUEUE_NAME = 'v1-tasks';
|
||||
const TASK_CLASS_NAME = 'TasksV1';
|
||||
|
||||
const CERTIFICATES_QUEUE_NAME = 'v1-certificates';
|
||||
|
|
|
@ -68,9 +68,9 @@ class V05 extends Migration
|
|||
$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_TASKS:
|
||||
// $document->setAttribute('security', $document->getAttribute('security') ? true : false);
|
||||
// break;
|
||||
|
||||
case Database::SYSTEM_COLLECTION_USERS:
|
||||
foreach ($providers as $key => $provider) {
|
||||
|
|
|
@ -120,8 +120,6 @@ class Response extends SwooleResponse
|
|||
const MODEL_WEBHOOK_LIST = 'webhookList';
|
||||
const MODEL_KEY = 'key';
|
||||
const MODEL_KEY_LIST = 'keyList';
|
||||
const MODEL_TASK = 'task';
|
||||
const MODEL_TASK_LIST = 'taskList';
|
||||
const MODEL_PLATFORM = 'platform';
|
||||
const MODEL_PLATFORM_LIST = 'platformList';
|
||||
const MODEL_DOMAIN = 'domain';
|
||||
|
@ -170,7 +168,6 @@ class Response extends SwooleResponse
|
|||
->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false))
|
||||
->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false))
|
||||
->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false))
|
||||
->setModel(new BaseList('Tasks List', self::MODEL_TASK_LIST, 'tasks', self::MODEL_TASK, true, false))
|
||||
->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false))
|
||||
->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN, true, false))
|
||||
->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY))
|
||||
|
@ -201,7 +198,6 @@ class Response extends SwooleResponse
|
|||
->setModel(new Project())
|
||||
->setModel(new Webhook())
|
||||
->setModel(new Key())
|
||||
->setModel(new Task())
|
||||
->setModel(new Domain())
|
||||
->setModel(new Platform())
|
||||
->setModel(new Country())
|
||||
|
|
|
@ -123,13 +123,6 @@ class Project extends Model
|
|||
'example' => new stdClass,
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('tasks', [
|
||||
'type' => Response::MODEL_TASK,
|
||||
'description' => 'List of Tasks.',
|
||||
'default' => [],
|
||||
'example' => new stdClass,
|
||||
'array' => true,
|
||||
])
|
||||
;
|
||||
|
||||
$providers = Config::getParam('providers', []);
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class Task extends Model
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $public = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('projectId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Project ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task name.',
|
||||
'default' => '',
|
||||
'example' => 'My Task',
|
||||
])
|
||||
->addRule('security', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Indicated if SSL / TLS Certificate verification is enabled.',
|
||||
'default' => true,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('httpMethod', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task HTTP Method.',
|
||||
'default' => '',
|
||||
'example' => 'POST',
|
||||
])
|
||||
->addRule('httpUrl', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task HTTP URL.',
|
||||
'default' => '',
|
||||
'example' => 'https://example.com/task',
|
||||
])
|
||||
->addRule('httpHeaders', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task HTTP headers.',
|
||||
'default' => [],
|
||||
'example' => 'key:value',
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('httpUser', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'HTTP basic authentication username.',
|
||||
'default' => '',
|
||||
'example' => 'username',
|
||||
])
|
||||
->addRule('httpPass', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'HTTP basic authentication password.',
|
||||
'default' => '',
|
||||
'example' => 'password',
|
||||
])
|
||||
->addRule('duration', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Task duration in seconds.',
|
||||
'default' => 0,
|
||||
'example' => 1.2,
|
||||
])
|
||||
->addRule('delay', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Task delay time in seconds.',
|
||||
'default' => 0,
|
||||
'example' => 1.2,
|
||||
])
|
||||
->addRule('failures', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Number of recurring task failures.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('schedule', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task schedule in CRON syntax.',
|
||||
'default' => '',
|
||||
'example' => '* * * * *',
|
||||
])
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Task status. Possible values: play, pause',
|
||||
'default' => '',
|
||||
'example' => 'enabled',
|
||||
])
|
||||
->addRule('updated', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Task last updated time in Unix timestamp.',
|
||||
'default' => 0,
|
||||
'example' => 1592981250,
|
||||
])
|
||||
->addRule('previous', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Task previous run time in Unix timestamp.',
|
||||
'default' => 0,
|
||||
'example' => 1592981250,
|
||||
])
|
||||
->addRule('next', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Task next run time in Unix timestamp.',
|
||||
'default' => 0,
|
||||
'example' => 1592981650,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
{
|
||||
return 'Task';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Collection
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType():string
|
||||
{
|
||||
return Response::MODEL_TASK;
|
||||
}
|
||||
}
|
|
@ -379,7 +379,7 @@ trait AccountBase
|
|||
return $data;
|
||||
}
|
||||
|
||||
//TODO Add tests for OAuth2 session creation
|
||||
// TODO Add tests for OAuth2 session creation
|
||||
|
||||
/**
|
||||
* @depends testCreateAccountSession
|
||||
|
|
|
@ -119,27 +119,6 @@ class HealthCustomServerTest extends Scope
|
|||
return [];
|
||||
}
|
||||
|
||||
public function testTasksSuccess():array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/health/queue/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertIsInt($response['body']['size']);
|
||||
$this->assertLessThan(100, $response['body']['size']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testLogsSuccess():array
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -45,7 +45,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertArrayHasKey('platforms', $response['body']);
|
||||
$this->assertArrayHasKey('webhooks', $response['body']);
|
||||
$this->assertArrayHasKey('keys', $response['body']);
|
||||
$this->assertArrayHasKey('tasks', $response['body']);
|
||||
|
||||
$projectId = $response['body']['$id'];
|
||||
|
||||
|
@ -164,7 +163,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertArrayHasKey('network', $response['body']);
|
||||
$this->assertArrayHasKey('requests', $response['body']);
|
||||
$this->assertArrayHasKey('storage', $response['body']);
|
||||
$this->assertArrayHasKey('tasks', $response['body']);
|
||||
$this->assertArrayHasKey('users', $response['body']);
|
||||
$this->assertIsArray($response['body']['collections']['data']);
|
||||
$this->assertIsInt($response['body']['collections']['total']);
|
||||
|
@ -175,8 +173,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertIsArray($response['body']['requests']['data']);
|
||||
$this->assertIsInt($response['body']['requests']['total']);
|
||||
$this->assertIsInt($response['body']['storage']['total']);
|
||||
$this->assertIsArray($response['body']['tasks']['data']);
|
||||
$this->assertIsInt($response['body']['tasks']['total']);
|
||||
$this->assertIsArray($response['body']['users']['data']);
|
||||
$this->assertIsInt($response['body']['users']['total']);
|
||||
|
||||
|
@ -224,7 +220,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertArrayHasKey('platforms', $response['body']);
|
||||
$this->assertArrayHasKey('webhooks', $response['body']);
|
||||
$this->assertArrayHasKey('keys', $response['body']);
|
||||
$this->assertArrayHasKey('tasks', $response['body']);
|
||||
|
||||
$projectId = $response['body']['$id'];
|
||||
|
||||
|
@ -933,400 +928,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
return $data;
|
||||
}
|
||||
|
||||
// Tasks
|
||||
|
||||
/**
|
||||
* @depends testCreateProject
|
||||
*/
|
||||
public function testCreateProjectTask($data): array
|
||||
{
|
||||
$id = $data['projectId'] ?? '';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test',
|
||||
'status' => 'play',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => true,
|
||||
'httpMethod' => 'GET',
|
||||
'httpUrl' => 'http://example.com',
|
||||
'httpHeaders' => ['demo:value'],
|
||||
'httpUser' => 'username',
|
||||
'httpPass' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEquals('Task Test', $response['body']['name']);
|
||||
$this->assertEquals('play', $response['body']['status']);
|
||||
$this->assertEquals(true, $response['body']['security']);
|
||||
$this->assertEquals('* * * * *', $response['body']['schedule']);
|
||||
$this->assertEquals('GET', $response['body']['httpMethod']);
|
||||
$this->assertEquals('http://example.com', $response['body']['httpUrl']);
|
||||
$this->assertContains('demo:value', $response['body']['httpHeaders']);
|
||||
$this->assertCount(1, $response['body']['httpHeaders']);
|
||||
$this->assertEquals('username', $response['body']['httpUser']);
|
||||
$this->assertEquals('password', $response['body']['httpPass']);
|
||||
|
||||
$data = array_merge($data, ['taskId' => $response['body']['$id']]);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test',
|
||||
'status' => 'unknown',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => true,
|
||||
'httpMethod' => 'GET',
|
||||
'httpUrl' => 'http://example.com',
|
||||
'httpHeaders' => ['demo:value'],
|
||||
'httpUser' => 'username',
|
||||
'httpPass' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test',
|
||||
'status' => 'play',
|
||||
'schedule' => 'unknown',
|
||||
'security' => true,
|
||||
'httpMethod' => 'GET',
|
||||
'httpUrl' => 'http://example.com',
|
||||
'httpHeaders' => ['demo:value'],
|
||||
'httpUser' => 'username',
|
||||
'httpPass' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test',
|
||||
'status' => 'play',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => 'string',
|
||||
'httpMethod' => 'GET',
|
||||
'httpUrl' => 'http://example.com',
|
||||
'httpHeaders' => ['demo:value'],
|
||||
'httpUser' => 'username',
|
||||
'httpPass' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test',
|
||||
'status' => 'play',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => true,
|
||||
'httpMethod' => 'UNKNOWN',
|
||||
'httpUrl' => 'http://example.com',
|
||||
'httpHeaders' => ['demo:value'],
|
||||
'httpUser' => 'username',
|
||||
'httpPass' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test',
|
||||
'status' => 'play',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => true,
|
||||
'httpMethod' => 'GET',
|
||||
'httpUrl' => 'http://example.com',
|
||||
'httpHeaders' => 'string',
|
||||
'httpUser' => 'username',
|
||||
'httpPass' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateProjectTask
|
||||
*/
|
||||
public function testListProjectTask($data): array
|
||||
{
|
||||
$id = $data['projectId'] ?? '';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/tasks', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['sum']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateProjectTask
|
||||
*/
|
||||
public function testGetProjectTask($data): array
|
||||
{
|
||||
$id = $data['projectId'] ?? '';
|
||||
$taskId = $data['taskId'] ?? '';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEquals($taskId, $response['body']['$id']);
|
||||
$this->assertEquals('Task Test', $response['body']['name']);
|
||||
$this->assertEquals('play', $response['body']['status']);
|
||||
$this->assertEquals(true, $response['body']['security']);
|
||||
$this->assertEquals('* * * * *', $response['body']['schedule']);
|
||||
$this->assertEquals('GET', $response['body']['httpMethod']);
|
||||
$this->assertEquals('http://example.com', $response['body']['httpUrl']);
|
||||
$this->assertContains('demo:value', $response['body']['httpHeaders']);
|
||||
$this->assertCount(1, $response['body']['httpHeaders']);
|
||||
$this->assertEquals('username', $response['body']['httpUser']);
|
||||
$this->assertEquals('password', $response['body']['httpPass']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/tasks/error', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateProjectTask
|
||||
*/
|
||||
public function testUpdateProjectTask($data): array
|
||||
{
|
||||
$id = $data['projectId'] ?? '';
|
||||
$taskId = $data['taskId'] ?? '';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause',
|
||||
'schedule' => '*/5 * * * *',
|
||||
'security' => false,
|
||||
'httpMethod' => 'POST',
|
||||
'httpUrl' => 'http://example.com/demo',
|
||||
'httpHeaders' => ['demo1: value1', 'demo2:value2'],
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEquals($taskId, $response['body']['$id']);
|
||||
$this->assertEquals('Task Test 2', $response['body']['name']);
|
||||
$this->assertEquals('pause', $response['body']['status']);
|
||||
$this->assertEquals(false, $response['body']['security']);
|
||||
$this->assertEquals('*/5 * * * *', $response['body']['schedule']);
|
||||
$this->assertEquals('POST', $response['body']['httpMethod']);
|
||||
$this->assertEquals('http://example.com/demo', $response['body']['httpUrl']);
|
||||
$this->assertContains('demo1: value1', $response['body']['httpHeaders']);
|
||||
$this->assertContains('demo2:value2', $response['body']['httpHeaders']);
|
||||
$this->assertCount(2, $response['body']['httpHeaders']);
|
||||
$this->assertEquals('username1', $response['body']['httpUser']);
|
||||
$this->assertEquals('password1', $response['body']['httpPass']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEquals($taskId, $response['body']['$id']);
|
||||
$this->assertEquals('Task Test 2', $response['body']['name']);
|
||||
$this->assertEquals('pause', $response['body']['status']);
|
||||
$this->assertEquals(false, $response['body']['security']);
|
||||
$this->assertEquals('*/5 * * * *', $response['body']['schedule']);
|
||||
$this->assertEquals('POST', $response['body']['httpMethod']);
|
||||
$this->assertEquals('http://example.com/demo', $response['body']['httpUrl']);
|
||||
$this->assertContains('demo1: value1', $response['body']['httpHeaders']);
|
||||
$this->assertContains('demo2:value2', $response['body']['httpHeaders']);
|
||||
$this->assertCount(2, $response['body']['httpHeaders']);
|
||||
$this->assertEquals('username1', $response['body']['httpUser']);
|
||||
$this->assertEquals('password1', $response['body']['httpPass']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause1',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => false,
|
||||
'httpMethod' => 'POST',
|
||||
'httpUrl' => 'http://example.com/demo',
|
||||
'httpHeaders' => ['demo1: value1', 'demo2:value2'],
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause',
|
||||
'schedule' => '* * * * *xxx',
|
||||
'security' => false,
|
||||
'httpMethod' => 'POST',
|
||||
'httpUrl' => 'http://example.com/demo',
|
||||
'httpHeaders' => ['demo1: value1', 'demo2:value2'],
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => 'string',
|
||||
'httpMethod' => 'POST',
|
||||
'httpUrl' => 'http://example.com/demo',
|
||||
'httpHeaders' => ['demo1: value1', 'demo2:value2'],
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => false,
|
||||
'httpMethod' => 'UNKNOWN',
|
||||
'httpUrl' => 'http://example.com/demo',
|
||||
'httpHeaders' => ['demo1: value1', 'demo2:value2'],
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => false,
|
||||
'httpMethod' => 'POST',
|
||||
'httpUrl' => 'example.com/demo',
|
||||
'httpHeaders' => ['demo1: value1', 'demo2:value2'],
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Task Test 2',
|
||||
'status' => 'pause',
|
||||
'schedule' => '* * * * *',
|
||||
'security' => false,
|
||||
'httpMethod' => 'POST',
|
||||
'httpUrl' => 'http://example.com/demo',
|
||||
'httpHeaders' => 'string',
|
||||
'httpUser' => 'username1',
|
||||
'httpPass' => 'password1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateProjectTask
|
||||
*/
|
||||
public function testDeleteProjectTask($data): array
|
||||
{
|
||||
$id = $data['projectId'] ?? '';
|
||||
$taskId = $data['taskId'] ?? '';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
$this->assertEmpty($response['body']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/tasks/error', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Platforms
|
||||
|
||||
/**
|
||||
|
@ -1659,7 +1260,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/tasks/error', array_merge([
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/projects/'.$id.'/webhooks/error', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
|
|
@ -45,7 +45,6 @@ class WebhooksTest extends Scope
|
|||
$this->assertArrayHasKey('platforms', $response['body']);
|
||||
$this->assertArrayHasKey('webhooks', $response['body']);
|
||||
$this->assertArrayHasKey('keys', $response['body']);
|
||||
$this->assertArrayHasKey('tasks', $response['body']);
|
||||
|
||||
$projectId = $response['body']['$id'];
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class MigrationV05Test extends MigrationTest
|
|||
|
||||
$document = $this->fixDocument(new Document([
|
||||
'$uid' => 'unique',
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TASKS
|
||||
'$collection' => Database::SYSTEM_COLLECTION_WEBHOOKS
|
||||
]));
|
||||
|
||||
$this->assertEquals($document->getAttribute('$uid', null), null);
|
||||
|
|
Loading…
Reference in a new issue