mirror of
https://github.com/appwrite/appwrite
synced 2026-05-21 16:08:22 +00:00
Merge branch 'main' into feat-zoho-oauth
This commit is contained in:
commit
3e0f63e499
6 changed files with 115 additions and 47 deletions
|
|
@ -3,30 +3,36 @@
|
|||
"settings.locale": "tr",
|
||||
"settings.direction": "ltr",
|
||||
"emails.sender": "%s Takımı",
|
||||
"emails.verification.subject": "",
|
||||
"emails.verification.hello": "",
|
||||
"emails.verification.body": "",
|
||||
"emails.verification.footer": "",
|
||||
"emails.verification.thanks": "",
|
||||
"emails.verification.signature": "",
|
||||
"emails.magicSession.subject": "",
|
||||
"emails.magicSession.hello": "",
|
||||
"emails.magicSession.body": "",
|
||||
"emails.magicSession.footer": "",
|
||||
"emails.magicSession.thanks": "",
|
||||
"emails.magicSession.signature": "",
|
||||
"emails.recovery.subject": "",
|
||||
"emails.recovery.hello": "",
|
||||
"emails.recovery.body": "",
|
||||
"emails.recovery.footer": "",
|
||||
"emails.recovery.thanks": "",
|
||||
"emails.recovery.signature": "",
|
||||
"emails.invitation.subject": "",
|
||||
"emails.invitation.hello": "",
|
||||
"emails.invitation.body": "",
|
||||
"emails.invitation.footer": "",
|
||||
"emails.invitation.thanks": "",
|
||||
"emails.invitation.signature": "",
|
||||
"emails.verification.subject": "Hesabını Doğrula",
|
||||
"emails.verification.hello": "Merhaba {{user}}",
|
||||
"emails.verification.body": "Eposta adresini doğrulamak için bu bağlantıyı kullanın.",
|
||||
"emails.verification.footer": "Eğer bu eposta adresini doğrulamak isteyen siz değilseniz devam etmeyin.",
|
||||
"emails.verification.thanks": "Teşekkürler",
|
||||
"emails.verification.signature": "{{project}} takımı",
|
||||
"emails.magicSession.subject": "Giriş",
|
||||
"emails.magicSession.hello": "Merhaba,",
|
||||
"emails.magicSession.body": "Giriş yapmak için tıklayın.",
|
||||
"emails.magicSession.footer": "Eğer bu eposta adresini kullanarak giriş yapmak istemediyseniz devam etmeyin.",
|
||||
"emails.magicSession.thanks": "Teşekkürler",
|
||||
"emails.magicSession.signature": "{{project}} takımı",
|
||||
"emails.recovery.subject": "Şifremi Sıfırla",
|
||||
"emails.recovery.hello": "Merhaba {{user}}",
|
||||
"emails.recovery.body": "{{project}} şifrenizi sıfırlamak için bu bağlantıyı kullanın.",
|
||||
"emails.recovery.footer": "Eğer şifre sıfırlama talebinde bulunmadıysanız devam etmeyin.",
|
||||
"emails.recovery.thanks": "Teşekkürler",
|
||||
"emails.recovery.signature": "{{project}} takımı",
|
||||
"emails.invitation.subject": "%s üzerinde %s Takımına Davet",
|
||||
"emails.invitation.hello": "Merhaba",
|
||||
"emails.invitation.body": "Bu epostayı aldınız, çünkü {{owner}} sizi {{project}} üzerinde {{team}} takımının üyesi olmaya davet etti.",
|
||||
"emails.invitation.footer": "Eğer ilgilenmiyorsanız devam etmeyin.",
|
||||
"emails.invitation.thanks": "Teşekkürler",
|
||||
"emails.invitation.signature": "{{project}} takımı",
|
||||
"emails.certificate.subject": "%s için sertifika hatası",
|
||||
"emails.certificate.hello": "Merhaba",
|
||||
"emails.certificate.body": "Alan adınız '{{domain}}' için sertifika oluşturulamadı. Deneme sayısı {{attempt}} ve hata sebebi: {{error}}",
|
||||
"emails.certificate.footer": "Geçmiş sertifikanız ilk denemeden sonra 30 gün daha geçerli kalacaktır. Bu konuyu araştırmanızı öneriyoruz, aksi taktirde alan adınız SSL sertifikasız kalacaktır.",
|
||||
"emails.certificate.thanks": "Teşekkürler",
|
||||
"emails.certificate.signature": "{{project}} takımı",
|
||||
"locale.country.unknown": "Bilinmeyen",
|
||||
"countries.af": "Afganistan",
|
||||
"countries.ao": "Angola",
|
||||
|
|
@ -229,4 +235,4 @@
|
|||
"continents.na": "Kuzey Amerika",
|
||||
"continents.oc": "Okyanusya",
|
||||
"continents.sa": "Güney Amerika"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,11 +550,19 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
if (!$user->isEmpty()) {
|
||||
$userId = $user->getId();
|
||||
|
||||
$identitiesWithMatchingEmail = $dbForProject->find('identities', [
|
||||
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
|
||||
Query::equal('providerEmail', [$email]),
|
||||
Query::notEqual('userId', $userId),
|
||||
]);
|
||||
if (!empty($identitiesWithMatchingEmail)) {
|
||||
if (!empty($identityWithMatchingEmail)) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$userWithMatchingEmail = $dbForProject->find('users', [
|
||||
Query::equal('email', [$email]),
|
||||
Query::notEqual('$id', $userId),
|
||||
]);
|
||||
if (!empty($userWithMatchingEmail)) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -551,6 +551,11 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
break;
|
||||
}
|
||||
$data = $compressor->compress($data);
|
||||
} else {
|
||||
// reset the algorithm to none as we do not compress the file
|
||||
// if file size exceedes the APP_STORAGE_READ_BUFFER
|
||||
// regardless the bucket compression algoorithm
|
||||
$algorithm = COMPRESSION_TYPE_NONE;
|
||||
}
|
||||
|
||||
if ($bucket->getAttribute('encryption', true) && $fileSize <= APP_STORAGE_READ_BUFFER) {
|
||||
|
|
@ -872,14 +877,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ((\strpos($request->getAccept(), 'image/webp') === false) && ('webp' === $output)) { // Fallback webp to jpeg when no browser support
|
||||
$output = 'jpg';
|
||||
}
|
||||
|
||||
$inputs = Config::getParam('storage-inputs');
|
||||
$outputs = Config::getParam('storage-outputs');
|
||||
$fileLogos = Config::getParam('storage-logos');
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
|
|
@ -890,9 +887,17 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ((\strpos($request->getAccept(), 'image/webp') === false) && ('webp' === $output)) { // Fallback webp to jpeg when no browser support
|
||||
$output = 'jpg';
|
||||
}
|
||||
|
||||
$inputs = Config::getParam('storage-inputs');
|
||||
$outputs = Config::getParam('storage-outputs');
|
||||
$fileLogos = Config::getParam('storage-logos');
|
||||
|
||||
$path = $file->getAttribute('path');
|
||||
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
|
||||
$algorithm = $file->getAttribute('algorithm', 'none');
|
||||
$algorithm = $file->getAttribute('algorithm', COMPRESSION_TYPE_NONE);
|
||||
$cipher = $file->getAttribute('openSSLCipher');
|
||||
$mime = $file->getAttribute('mimeType');
|
||||
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
|
||||
|
|
@ -903,7 +908,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
$path = $fileLogos['default_image'];
|
||||
}
|
||||
|
||||
$algorithm = 'none';
|
||||
$algorithm = COMPRESSION_TYPE_NONE;
|
||||
$cipher = null;
|
||||
$background = (empty($background)) ? 'eceff1' : $background;
|
||||
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
|
||||
|
|
@ -915,12 +920,17 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
}
|
||||
|
||||
if (empty($output)) {
|
||||
// when file extension is provided but it's not one of our
|
||||
// supported outputs we fallback to `jpg`
|
||||
if (!empty($type) && !array_key_exists($type, $outputs)) {
|
||||
$type = 'jpg';
|
||||
}
|
||||
|
||||
// when file extension is not provided and the mime type is not one of our supported outputs
|
||||
// we fallback to `jpg` output format
|
||||
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
|
||||
}
|
||||
|
||||
|
||||
$source = $deviceFiles->read($path);
|
||||
|
||||
if (!empty($cipher)) { // Decrypt
|
||||
|
|
@ -935,11 +945,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
}
|
||||
|
||||
switch ($algorithm) {
|
||||
case 'zstd':
|
||||
case COMPRESSION_TYPE_ZSTD:
|
||||
$compressor = new Zstd();
|
||||
$source = $compressor->decompress($source);
|
||||
break;
|
||||
case 'gzip':
|
||||
case COMPRESSION_TYPE_GZIP:
|
||||
$compressor = new GZIP();
|
||||
$source = $compressor->decompress($source);
|
||||
break;
|
||||
|
|
@ -1080,15 +1090,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
);
|
||||
}
|
||||
|
||||
switch ($file->getAttribute('algorithm', 'none')) {
|
||||
case 'zstd':
|
||||
switch ($file->getAttribute('algorithm', COMPRESSION_TYPE_NONE)) {
|
||||
case COMPRESSION_TYPE_ZSTD:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
}
|
||||
$compressor = new Zstd();
|
||||
$source = $compressor->decompress($source);
|
||||
break;
|
||||
case 'gzip':
|
||||
case COMPRESSION_TYPE_GZIP:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
}
|
||||
|
|
@ -1231,15 +1241,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
);
|
||||
}
|
||||
|
||||
switch ($file->getAttribute('algorithm', 'none')) {
|
||||
case 'zstd':
|
||||
switch ($file->getAttribute('algorithm', COMPRESSION_TYPE_NONE)) {
|
||||
case COMPRESSION_TYPE_ZSTD:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
}
|
||||
$compressor = new Zstd();
|
||||
$source = $compressor->decompress($source);
|
||||
break;
|
||||
case 'gzip':
|
||||
case COMPRESSION_TYPE_GZIP:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
}
|
||||
|
|
@ -1253,10 +1263,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
$response->send(substr($source, $start, ($end - $start + 1)));
|
||||
}
|
||||
$response->send($source);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
return;
|
||||
}
|
||||
|
||||
$size = $deviceFiles->getFileSize($path);
|
||||
|
|
|
|||
|
|
@ -556,6 +556,22 @@ App::shutdown()
|
|||
->setParam('project.{scope}.network.outbound', $response->getSize())
|
||||
->submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user last activity
|
||||
*/
|
||||
if (!$user->isEmpty()) {
|
||||
$accessedAt = $user->getAttribute('accessedAt', '');
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCCESS)) > $accessedAt) {
|
||||
$user->setAttribute('accessedAt', DateTime::now());
|
||||
|
||||
if (APP_MODE_ADMIN !== $mode) {
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
} else {
|
||||
$dbForConsole->updateDocument('users', $user->getId(), $user);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
App::init()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ trait StorageBase
|
|||
'name' => 'Test Bucket',
|
||||
'fileSecurity' => true,
|
||||
'maximumFileSize' => 2000000, //2MB
|
||||
'allowedFileExtensions' => ["jpg", "png"],
|
||||
'allowedFileExtensions' => ["jpg", "png", 'jfif'],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
|
|
@ -462,6 +462,32 @@ trait StorageBase
|
|||
$this->assertEquals('image/png', $file2['headers']['content-type']);
|
||||
$this->assertNotEmpty($file2['body']);
|
||||
|
||||
// upload JXL file for preview
|
||||
$fileJfif = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'fileId' => ID::unique(),
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/disk-a/preview-test.jfif'), 'image/jxl', 'preview-test.jfif'),
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(201, $fileJfif['headers']['status-code']);
|
||||
$this->assertNotEmpty($fileJfif['body']['$id']);
|
||||
|
||||
// TEST preview JXL
|
||||
$preview = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileJfif['body']['$id'] . '/preview', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $preview['headers']['status-code']);
|
||||
$this->assertEquals('image/jpeg', $preview['headers']['content-type']);
|
||||
$this->assertNotEmpty($preview['body']);
|
||||
|
||||
//new image preview features
|
||||
$file3 = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $data['fileId'] . '/preview', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
|
|||
BIN
tests/resources/disk-a/preview-test.jfif
Normal file
BIN
tests/resources/disk-a/preview-test.jfif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 129 KiB |
Loading…
Reference in a new issue