Merge remote-tracking branch 'origin/1.8.x' into feat-multi-create

This commit is contained in:
Jake Barnby 2025-12-03 20:49:36 +13:00
commit c09c2848af
11 changed files with 63 additions and 12 deletions

View file

@ -24,9 +24,9 @@ ENV _APP_VERSION=$VERSION \
_APP_HOME=https://appwrite.io
RUN \
if [ "$DEBUG" == "true" ]; then \
if [ "$DEBUG" == "true" ]; then \
apk add boost boost-dev; \
fi
fi
WORKDIR /usr/src/code

Binary file not shown.

View file

@ -681,7 +681,13 @@ App::post('/v1/storage/buckets/:bucketId/files')
'metadata' => $metadata,
]);
$file = $dbForProject->createDocument('bucket_' . $bucket->getSequence(), $doc);
try {
$file = $dbForProject->createDocument('bucket_' . $bucket->getSequence(), $doc);
} catch (DuplicateException) {
throw new Exception(Exception::STORAGE_FILE_ALREADY_EXISTS);
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
} else {
$file = $file
->setAttribute('$permissions', $permissions)
@ -731,6 +737,8 @@ App::post('/v1/storage/buckets/:bucketId/files')
try {
$file = $dbForProject->createDocument('bucket_' . $bucket->getSequence(), $doc);
} catch (DuplicateException) {
throw new Exception(Exception::STORAGE_FILE_ALREADY_EXISTS);
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}

View file

@ -117,14 +117,19 @@ function createUser(Hash $hash, string $userId, ?string $email, ?string $passwor
$hashedPassword = null;
$isHashed = !$hash instanceof Plaintext;
$defaultHash = new ProofsPassword();
if (!empty($password)) {
if (!$isHashed) { // Password was never hashed, hash it with the default hash
$defaultHash = new ProofsPassword();
$hashedPassword = $defaultHash->hash($password);
$hash = $defaultHash->getHash();
} else {
$hashedPassword = $password;
}
} else {
// when password is not provided, plaintext was set as the default hash causing the issue
$hash = $defaultHash->getHash();
$isHashed = !$hash instanceof Plaintext;
}
$user = new Document([
@ -160,7 +165,7 @@ function createUser(Hash $hash, string $userId, ?string $email, ?string $passwor
'emailIsFree' => $emailCanonical?->isFree(),
]);
if (!$isHashed) {
if (!$isHashed && !empty($password)) {
$hooks->trigger('passwordValidator', [$dbForProject, $project, $plaintextPassword, &$user, true]);
}
@ -2627,7 +2632,8 @@ App::post('/v1/users/:userId/jwts')
$session = \count($sessions) > 0 ? $sessions[\count($sessions) - 1] : new Document();
} else {
// Find by ID
foreach ($sessions as $loopSession) { /** @var Utopia\Database\Document $loopSession */
foreach ($sessions as $loopSession) {
/** @var Utopia\Database\Document $loopSession */
if ($loopSession->getId() == $sessionId) {
$session = $loopSession;
break;

View file

@ -1796,7 +1796,8 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
throw new Exception(Exception::INSTALLATION_NOT_FOUND);
}
$repository = Authorization::skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [
$repository = Authorization::skip(fn () => $dbForPlatform->findOne('repositories', [
Query::equal('$id', [$repositoryId]),
Query::equal('projectInternalId', [$project->getSequence()])
]));

View file

@ -372,7 +372,7 @@ $register->set('smtp', function () {
return $mail;
});
$register->set('geodb', function () {
return new Reader(__DIR__ . '/../assets/dbip/dbip-country-lite-2024-09.mmdb');
return new Reader(__DIR__ . '/../assets/dbip/dbip-country-lite-2025-12.mmdb');
});
$register->set('passwordsDictionary', function () {
$content = \file_get_contents(__DIR__ . '/../assets/security/10k-common-passwords');

View file

@ -849,7 +849,7 @@ $image = $this->getParam('image', '');
- _APP_DB_PASS
appwrite-assistant:
image: appwrite/assistant:0.8.3
image: appwrite/assistant:0.8.4
container_name: appwrite-assistant
<<: *x-logging
restart: unless-stopped
@ -857,7 +857,7 @@ $image = $this->getParam('image', '');
- appwrite
environment:
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
image: appwrite/browser:0.3.2
container_name: appwrite-browser

View file

@ -951,7 +951,7 @@ services:
appwrite-assistant:
container_name: appwrite-assistant
image: appwrite/assistant:0.8.3
image: appwrite/assistant:0.8.4
networks:
- appwrite
environment:

View file

@ -55,7 +55,7 @@ trait AccountBase
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
'x-forwarded-for' => '103.152.127.250' // Test IP for denied access region
'x-forwarded-for' => '31.6.14.220' // Test IP for denied access region
]), [
'userId' => ID::unique(),
'email' => $email,

View file

@ -6,6 +6,7 @@ use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideConsole;
use Utopia\Database\Helpers\ID;
class UsersConsoleClientTest extends Scope
{
@ -45,4 +46,39 @@ class UsersConsoleClientTest extends Scope
$this->assertIsArray($response['body']['users']);
$this->assertIsArray($response['body']['sessions']);
}
public function testCreateUserWithoutPasswordThenSetPassword()
{
// Create a user with email but without password
$userId = ID::unique();
$email = $userId . '@example.com';
$response = $this->client->call(Client::METHOD_POST, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), [
'userId' => $userId,
'email' => $email,
// no password provided
]);
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertEquals($userId, $response['body']['$id']);
$this->assertEquals($email, $response['body']['email']);
$this->assertEmpty($response['body']['password']);
// Now set the password for that user (console-side)
$newPassword = 'NewPass123!';
$set = $this->client->call(Client::METHOD_PATCH, '/users/' . $userId . '/password', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), [
'password' => $newPassword,
]);
$this->assertEquals(200, $set['headers']['status-code']);
$this->assertEquals($userId, $set['body']['$id']);
$this->assertNotEmpty($set['body']['password']);
}
}