Merge branch '1.8.x' of https://github.com/appwrite/appwrite into migrations-cleanup

This commit is contained in:
fogelito
2026-01-06 10:45:19 +02:00
10 changed files with 335 additions and 8 deletions
@@ -0,0 +1,86 @@
<?php
namespace Appwrite\Platform\Modules\Projects\Http\Projects\Labels;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Text;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectLabels';
}
protected function getQueriesValidator(): Validator
{
return new Projects();
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT)
->setHttpPath('/v1/projects/:projectId/labels')
->desc('Update project labels')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'projects',
name: 'updateLabels',
description: <<<EOT
Update the project labels by its unique ID. Labels can be used to easily filter projects in an organization.
EOT,
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT
)
],
contentType: ContentType::JSON
))
->param('projectId', '', new UID(), 'Project unique ID.')
->param('labels', [], new ArrayList(new Text(36, allowList: [...Text::NUMBERS, ...Text::ALPHABET_UPPER, ...Text::ALPHABET_LOWER]), APP_LIMIT_ARRAY_LABELS_SIZE), 'Array of project labels. Replaces the previous labels. Maximum of ' . APP_LIMIT_ARRAY_LABELS_SIZE . ' labels are allowed, each up to 36 alphanumeric characters long.')
->inject('response')
->inject('dbForPlatform')
->callback($this->action(...));
}
/**
* @param array<string> $labels
*/
public function action(
string $projectId,
array $labels,
Response $response,
Database $dbForPlatform
): void {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$project->setAttribute('labels', (array) \array_values(\array_unique($labels)));
$project = $dbForPlatform->updateDocument('projects', $project->getId(), $project);
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -7,6 +7,7 @@ use Appwrite\Platform\Modules\Projects\Http\DevKeys\Delete as DeleteDevKey;
use Appwrite\Platform\Modules\Projects\Http\DevKeys\Get as GetDevKey;
use Appwrite\Platform\Modules\Projects\Http\DevKeys\Update as UpdateDevKey;
use Appwrite\Platform\Modules\Projects\Http\DevKeys\XList as ListDevKeys;
use Appwrite\Platform\Modules\Projects\Http\Projects\Labels\Update as UpdateProjectLabels;
use Appwrite\Platform\Modules\Projects\Http\Projects\XList as ListProjects;
use Utopia\Platform\Service;
@@ -22,5 +23,6 @@ class Http extends Service
$this->addAction(DeleteDevKey::getName(), new DeleteDevKey());
$this->addAction(ListProjects::getName(), new ListProjects());
$this->addAction(UpdateProjectLabels::getName(), new UpdateProjectLabels());
}
}
+4 -5
View File
@@ -148,7 +148,7 @@ class Deletes extends Action
break;
case DELETE_TYPE_AUDIT:
if (!$project->isEmpty()) {
$this->deleteAuditLogs($project, $auditRetention, $getAudit);
$this->deleteAuditLogs($project, $getAudit, $auditRetention);
}
break;
case DELETE_TYPE_REALTIME:
@@ -783,14 +783,13 @@ class Deletes extends Action
}
/**
* @param Database $dbForPlatform
* @param callable $getProjectDB
* @param string $auditRetention
* @param Document $project
* @param callable $getAudit
* @param string $auditRetention
* @return void
* @throws Exception
*/
private function deleteAuditLogs(Document $project, string $auditRetention, callable $getAudit): void
private function deleteAuditLogs(Document $project, callable $getAudit, string $auditRetention): void
{
$projectId = $project->getId();
/** @var Audit $audit */
+7 -1
View File
@@ -68,7 +68,8 @@ class Mails extends Action
throw new Exception('Skipped mail processing. No SMTP configuration has been set.');
}
$log->addTag('type', empty($smtp) ? 'cloud' : 'smtp');
$type = empty($smtp) ? 'cloud' : 'smtp';
$log->addTag('type', $type);
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
$hostname = System::getEnv('_APP_CONSOLE_DOMAIN');
@@ -182,6 +183,9 @@ class Mails extends Action
try {
$mail->send();
} catch (\Throwable $error) {
if ($type === 'smtp') {
throw new Exception('Error sending mail: ' . $error->getMessage(), 401);
}
throw new Exception('Error sending mail: ' . $error->getMessage(), 500);
}
}
@@ -209,6 +213,8 @@ class Mails extends Action
$mail->SMTPSecure = $smtp['secure'];
$mail->SMTPAutoTLS = false;
$mail->CharSet = 'UTF-8';
$mail->Timeout = 10; /* Connection timeout */
$mail->getSMTPInstance()->Timelimit = 30; /* Timeout for each individual SMTP command (e.g. HELO, EHLO, etc.) */
$mail->setFrom($smtp['senderEmail'], $smtp['senderName']);
@@ -6,7 +6,8 @@ class Projects extends Base
{
public const ALLOWED_ATTRIBUTES = [
'name',
'teamId'
'teamId',
'labels',
];
/**
@@ -276,6 +276,13 @@ class Project extends Model
'default' => '',
'example' => self::TYPE_DATETIME_EXAMPLE,
])
->addRule('labels', [
'type' => self::TYPE_STRING,
'description' => 'Labels for the project.',
'default' => [],
'example' => ['vip'],
'array' => true,
])
;
$services = Config::getParam('services', []);