1
0
Fork 0
mirror of synced 2024-06-29 03:30:34 +12:00

Merge branch 'feat-265-realtime' of https://github.com/appwrite/appwrite into feat-265-realtime-usage

This commit is contained in:
Torsten Dittmann 2021-06-17 13:07:27 +02:00
commit ba8fef944c
6 changed files with 208 additions and 3 deletions

View file

@ -37,10 +37,12 @@ App::post('/v1/teams')
->inject('response')
->inject('user')
->inject('projectDB')
->action(function ($name, $roles, $response, $user, $projectDB) {
->inject('events')
->action(function ($name, $roles, $response, $user, $projectDB, $events) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
/** @var Appwrite\Database\Database $projectDB */
/** @var Appwrite\Event\Event $events */
Authorization::disable();
@ -90,6 +92,10 @@ App::post('/v1/teams')
}
}
if (!empty($user->getId())) {
$events->setParam('userId', $user->getId());
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($team, Response::MODEL_TEAM)

View file

@ -201,6 +201,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
if ($project->getId() !== 'console') {
$realtime
->setEvent($events->getParam('event'))
->setUserId($events->getParam('userId'))
->setProject($project->getId())
->setPayload($response->getPayload())
->trigger();

View file

@ -17,6 +17,11 @@ class Realtime
*/
protected $event = '';
/**
* @var string
*/
protected $userId = '';
/**
* @var array
*/
@ -27,6 +32,11 @@ class Realtime
*/
protected $permissions = [];
/**
* @var false
*/
protected $permissionsChanged = false;
/**
* @var Document
*/
@ -57,6 +67,16 @@ class Realtime
return $this;
}
/**
* @param string $userId
* return $this
*/
public function setUserId(string $userId): self
{
$this->userId = $userId;
return $this;
}
/**
* @return string
*/
@ -120,6 +140,20 @@ class Realtime
$this->channels[] = 'account.' . $this->payload->getId();
$this->permissions = ['user:' . $this->payload->getId()];
break;
case strpos($this->event, 'teams.memberships') === 0:
$this->permissionsChanged = in_array($this->event, ['teams.memberships.update', 'teams.memberships.delete', 'teams.memberships.update.status']);
$this->channels[] = 'memberships';
$this->channels[] = 'memberships.' . $this->payload->getId();
$this->permissions = ['team:' . $this->payload->getAttribute('teamId')];
break;
case strpos($this->event, 'teams.') === 0:
$this->permissionsChanged = $this->event === 'teams.create';
$this->channels[] = 'teams';
$this->channels[] = 'teams.' . $this->payload->getId();
$this->permissions = ['team:' . $this->payload->getId()];
break;
case strpos($this->event, 'database.collections.') === 0:
$this->channels[] = 'collections';
@ -148,7 +182,7 @@ class Realtime
$this->permissions = $this->payload->getAttribute('$permissions.read');
}
break;
}
}
}
/**
@ -166,6 +200,8 @@ class Realtime
$redis->publish('realtime', json_encode([
'project' => $this->project,
'permissions' => $this->permissions,
'permissionsChanged' => $this->permissionsChanged,
'userId' => $this->userId,
'data' => [
'event' => $this->event,
'channels' => $this->channels,

View file

@ -163,6 +163,7 @@ class Parser
$connections[$connection] = [
'projectId' => $projectId,
'roles' => $roles,
'channels' => $channels
];
}

View file

@ -282,7 +282,7 @@ class Server
return $db;
});
$this->register->set('cache', function () use (&$redis) { // Register cache connection
$this->register->set('cache', function () use (&$redis) {
return $redis;
});
@ -440,6 +440,10 @@ class Server
{
$event = json_decode($payload, true);
if ($event['permissionsChanged'] && isset($event['userId'])) {
$this->addPermission($event);
}
$receivers = Parser::identifyReceivers($event, $this->subscriptions);
// Temporarily print debug logs by default for Alpha testing.
@ -512,4 +516,43 @@ class Server
}
}
}
private function addPermission(array $event)
{
$project = $event['project'];
$userId = $event['userId'];
if (array_key_exists($project, $this->subscriptions) && array_key_exists('user:'.$userId, $this->subscriptions[$project])) {
$connection = array_key_first(reset($this->subscriptions[$project]['user:'.$userId]));
} else {
return;
}
/**
* This is redundant soon and will be gone with merging the usage branch.
*/
$db = $this->register->get('dbPool')->get();
$redis = $this->register->get('redisPool')->get();
$this->register->set('db', function () use (&$db) {
return $db;
});
$this->register->set('cache', function () use (&$redis) {
return $redis;
});
$projectDB = new Database();
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($this->register), $this->register));
$projectDB->setNamespace('app_'.$project);
$projectDB->setMocks(Config::getParam('collections', []));
$user = $projectDB->getDocument($userId);
Parser::setUser($user);
$roles = Parser::getRoles();
Parser::subscribe($project, $connection, $roles, $this->subscriptions, $this->connections, $this->connections[$connection]['channels']);
}
}

View file

@ -686,4 +686,122 @@ trait RealtimeBase
$client->close();
}
public function testChannelTeams(): array
{
$user = $this->getUser();
$session = $user['session'] ?? '';
$projectId = $this->getProject()['$id'];
$client = $this->getWebsocket(['teams'], [
'origin' => 'http://localhost',
'cookie' => 'a_session_'.$projectId.'=' . $session
]);
$response = json_decode($client->receive(), true);
$this->assertCount(1, $response);
$this->assertArrayHasKey('teams', $response);
/**
* Test Team Create
*/
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
'name' => 'Arsenal'
]);
$teamId = $team['body']['$id'] ?? '';
$this->assertEquals(201, $team['headers']['status-code']);
$this->assertNotEmpty($team['body']['$id']);
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('timestamp', $response);
$this->assertCount(2, $response['channels']);
$this->assertContains('teams', $response['channels']);
$this->assertContains('teams.' . $teamId, $response['channels']);
$this->assertEquals('teams.create', $response['event']);
$this->assertNotEmpty($response['payload']);
/**
* Test Team Update
*/
$team = $this->client->call(Client::METHOD_PUT, '/teams/'.$teamId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), [
'name' => 'Manchester'
]);
$this->assertEquals($team['headers']['status-code'], 200);
$this->assertNotEmpty($team['body']['$id']);
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('timestamp', $response);
$this->assertCount(2, $response['channels']);
$this->assertContains('teams', $response['channels']);
$this->assertContains('teams.' . $teamId, $response['channels']);
$this->assertEquals('teams.update', $response['event']);
$this->assertNotEmpty($response['payload']);
$client->close();
return ['teamId' => $teamId];
}
/**
* @depends testChannelTeams
*/
public function testChannelMemberships(array $data)
{
$teamId = $data['teamId'] ?? '';
$user = $this->getUser();
$session = $user['session'] ?? '';
$projectId = $this->getProject()['$id'];
$client = $this->getWebsocket(['memberships'], [
'origin' => 'http://localhost',
'cookie' => 'a_session_'.$projectId.'='.$session
]);
$response = json_decode($client->receive(), true);
$this->assertCount(1, $response);
$this->assertArrayHasKey('memberships', $response);
$response = $this->client->call(Client::METHOD_GET, '/teams/'.$teamId.'/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$membershipId = $response['body']['memberships'][0]['$id'];
/**
* Test Update Membership
*/
$roles = ['admin', 'editor', 'uncle'];
$this->client->call(Client::METHOD_PATCH, '/teams/'.$teamId.'/memberships/'.$membershipId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'roles' => $roles
]);
$response = json_decode($client->receive(), true);
$this->assertArrayHasKey('timestamp', $response);
$this->assertCount(2, $response['channels']);
$this->assertContains('memberships', $response['channels']);
$this->assertContains('memberships.' . $membershipId, $response['channels']);
$this->assertEquals('teams.memberships.update', $response['event']);
$this->assertNotEmpty($response['payload']);
$client->close();
}
}