Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi tenancy #1560

Merged
merged 18 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions api/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,13 @@ services:
class: Symfony\Component\Cache\DoctrineProvider
arguments:
- '@doctrine.system_cache_pool'

doctrine.system_cache_pool:
parent: 'cache.app'
tags:
- { name: 'cache.pool', namespace: 'app' }

doctrine.result_cache_pool:
parent: 'cache.app'
tags:
- { name: 'cache.pool', namespace: 'app' }
2 changes: 1 addition & 1 deletion api/docs/classes/App/Entity/Organization.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# App\Entity\Organization

This entity holds the information about an Organisation.
This entity holds the information about an Organization.



Expand Down
62 changes: 31 additions & 31 deletions api/docs/classes/App/Entity/User.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ This entity holds the information about an User.

## Methods

| Name | Description |
|------|-------------|
|[__construct](#user__construct)||
|[addApplication](#useraddapplication)||
|[addUserGroup](#useraddusergroup)||
|[getApplications](#usergetapplications)||
|[getDateCreated](#usergetdatecreated)||
|[getDateModified](#usergetdatemodified)||
|[getEmail](#usergetemail)||
|[getId](#usergetid)||
|[getLocale](#usergetlocale)||
|[getName](#usergetname)||
|[getOrganisation](#usergetorganization)||
|[getPassword](#usergetpassword)||
|[getPerson](#usergetperson)||
|[getRoles](#usergetroles)||
|[getUserGroups](#usergetusergroups)||
|[removeApplication](#userremoveapplication)||
|[removeUserGroup](#userremoveusergroup)||
|[setDateCreated](#usersetdatecreated)||
|[setDateModified](#usersetdatemodified)||
|[setEmail](#usersetemail)||
|[setLocale](#usersetlocale)||
|[setName](#usersetname)||
|[setOrganisation](#usersetorganization)||
|[setPassword](#usersetpassword)||
|[setPerson](#usersetperson)||
| Name | Description |
|---------------------------------------------|-------------|
| [__construct](#user__construct) ||
| [addApplication](#useraddapplication) ||
| [addUserGroup](#useraddusergroup) ||
| [getApplications](#usergetapplications) ||
| [getDateCreated](#usergetdatecreated) ||
| [getDateModified](#usergetdatemodified) ||
| [getEmail](#usergetemail) ||
| [getId](#usergetid) ||
| [getLocale](#usergetlocale) ||
| [getName](#usergetname) ||
| [getOrganization](#usergetorganization) ||
| [getPassword](#usergetpassword) ||
| [getPerson](#usergetperson) ||
| [getRoles](#usergetroles) ||
| [getUserGroups](#usergetusergroups) ||
| [removeApplication](#userremoveapplication) ||
| [removeUserGroup](#userremoveusergroup) ||
| [setDateCreated](#usersetdatecreated) ||
| [setDateModified](#usersetdatemodified) ||
| [setEmail](#usersetemail) ||
| [setLocale](#usersetlocale) ||
| [setName](#usersetname) ||
| [setOrganisation](#usersetorganization) ||
| [setPassword](#usersetpassword) ||
| [setPerson](#usersetperson) ||



Expand Down Expand Up @@ -279,12 +279,12 @@ This entity holds the information about an User.
<hr />


### User::getOrganisation
### User::getOrganization

**Description**

```php
getOrganisation (void)
getOrganization (void)
```


Expand Down Expand Up @@ -567,12 +567,12 @@ This entity holds the information about an User.
<hr />


### User::setOrganisation
### User::setOrganization

**Description**

```php
setOrganisation (void)
setOrganization (void)
```


Expand Down
34 changes: 34 additions & 0 deletions api/migrations/Version20230922133622.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20230922133622 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE action ADD user_id VARCHAR(255) DEFAULT NULL');
$this->addSql('ALTER TABLE cronjob ADD user_id VARCHAR(255) DEFAULT NULL');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE action DROP user_id');
$this->addSql('ALTER TABLE cronjob DROP user_id');
}
}
32 changes: 32 additions & 0 deletions api/migrations/Version20230926112500.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20230926112500 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE "user" RENAME COLUMN organisation_id TO organization_id');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE "user" DROP organisation_id');
}
}
16 changes: 16 additions & 0 deletions api/src/Command/CronjobCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace App\Command;

use App\Entity\Cronjob;
use App\Entity\User;
use App\Event\ActionEvent;
use Cron\CronExpression;
use Doctrine\ORM\EntityManagerInterface;
Expand Down Expand Up @@ -66,6 +67,8 @@ protected function configure(): void
/**
* This function makes action events.
*
* After running this function, even if it returns an exception, currentCronJobUserId should always be removed from cache.
*
* @param Cronjob $cronjob
* @param SymfonyStyle $io
*
Expand All @@ -85,6 +88,16 @@ public function makeActionEvent(Cronjob $cronjob, SymfonyStyle $io): void
$io->newLine();
$io->newLine();

// Keep track of the user used for running this CronJob.
// After makeActionEvent() is done, even if it returns an exception, currentCronJobUserId should be removed from cache (outside this function)
$this->session->remove('currentCronjobUserId');
if ($cronjob->getUserId() !== null && Uuid::isValid($cronjob->getUserId()) === true) {
$user = $this->entityManager->getRepository('App:User')->find($cronjob->getUserId());
if ($user instanceof User === true) {
$this->session->set('currentCronjobUserId', $cronjob->getUserId());
}
}

$throws = $cronjob->getThrows();
foreach ($throws as $key => $throw) {
$io->block("Dispatch ActionEvent for Throw: \"$throw\"");
Expand Down Expand Up @@ -158,6 +171,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$io->block("Trace: {$exception->getTraceAsString()}");
$errorCount++;
}
// Make sure we remove currentCronJobUserid from cache.
$this->session->remove('currentCronJobUserId');

$io->progressAdvance();
}
Expand Down Expand Up @@ -186,6 +201,7 @@ private function handleCronjobIoStart(SymfonyStyle $io, Cronjob $cronjob)
['Id' => $cronjob->getId()->toString()],
['Name' => $cronjob->getName()],
['Description' => $cronjob->getDescription()],
['UserId' => $cronjob->getUserId()],
['Crontab' => $cronjob->getCrontab()],
['Throws' => implode(', ', $cronjob->getThrows())],
// ['Data' => "[{$this->objectEntityService->implodeMultiArray($cronjob->getData())}]"],
Expand Down
2 changes: 1 addition & 1 deletion api/src/Command/InitializationCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$user->setPassword($this->hasher->hashPassword($user, '!ChangeMe!'));
$user->addSecurityGroup($securityGroupAdmin);
$user->addApplication($application);
$user->setOrganisation($organization);
$user->setOrganization($organization);

$this->entityManager->persist($user);
} else {
Expand Down
18 changes: 9 additions & 9 deletions api/src/Controller/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ public function resetTokenAction(SerializerInterface $serializer, \CommonGateway

$user = $this->entityManager->getRepository('App:User')->find($user->getUserIdentifier());

if ($user->getOrganisation() !== null) {
$organizations[] = $user->getOrganisation();
if ($user->getOrganization() !== null) {
$organizations[] = $user->getOrganization();
}
foreach ($user->getApplications() as $application) {
if ($application->getOrganization() !== null) {
Expand All @@ -110,7 +110,7 @@ public function resetTokenAction(SerializerInterface $serializer, \CommonGateway
}

// If user has no organization, we default activeOrganization to an organization of a userGroup this user has and else the application organization;
$this->session->set('activeOrganization', $user->getOrganisation()->getId()->toString());
$this->session->set('activeOrganization', $user->getOrganization()->getId()->toString());

$user->setJwtToken($authenticationService->createJwtToken($user->getApplications()[0]->getPrivateKey(), $authenticationService->serializeUser($user, $this->session)));

Expand Down Expand Up @@ -145,7 +145,7 @@ public function createAuthenticationUser(User $user): AuthenticationUser
'id' => $user->getId()->toString(),
'email' => $user->getEmail(),
'locale' => $user->getLocale(),
'organization' => $user->getOrganisation()->getId()->toString(),
'organization' => $user->getOrganization()->getId()->toString(),
'roles' => $roleArray['roles'],
];

Expand Down Expand Up @@ -203,8 +203,8 @@ public function apiLoginAction(Request $request, UserPasswordHasherInterface $ha
return new Response(json_encode($response), 401, ['Content-type' => 'application/json']);
}

if ($user->getOrganisation() !== null) {
$organizations[] = $user->getOrganisation();
if ($user->getOrganization() !== null) {
$organizations[] = $user->getOrganization();
}
foreach ($user->getApplications() as $application) {
if ($application->getOrganization() !== null) {
Expand All @@ -213,7 +213,7 @@ public function apiLoginAction(Request $request, UserPasswordHasherInterface $ha
}

// If user has no organization, we default activeOrganization to an organization of a userGroup this user has and else the application organization;
$this->session->set('activeOrganization', $user->getOrganisation()->getId()->toString());
$this->session->set('activeOrganization', $user->getOrganization()->getId()->toString());

$token = $authenticationService->createJwtToken($user->getApplications()[0]->getPrivateKey(), $authenticationService->serializeUser($user, $this->session));

Expand Down Expand Up @@ -255,7 +255,7 @@ private function getActiveOrganization(array $user, array $organizations): ?stri
}

/**
* Get all the child organisations for an organisation.
* Get all the child organizations for an organization.
*
* @param array $organizations
* @param string $organization
Expand Down Expand Up @@ -284,7 +284,7 @@ private function getSubOrganizations(array $organizations, string $organization,
}

/**
* Get al the parent organizations for an organisation.
* Get al the parent organizations for an organization.
*
* @param array $organizations
* @param string $organization
Expand Down
22 changes: 22 additions & 0 deletions api/src/Entity/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ class Action
*/
private ?array $configuration = [];

/**
* @var string|null The userId of a user. This user will be used to run this Action for, if there is no logged-in user.
* This helps when, for example: setting the organization of newly created ObjectEntities while running this Action.
*
* @Groups({"read","write"})
*
* @ORM\Column(type="string", length=255, nullable=true)
*/
private ?string $userId = null;

/**
* @Groups({"read", "write"})
*
Expand Down Expand Up @@ -481,6 +491,18 @@ public function setConfiguration(?array $configuration): self
return $this;
}

public function getUserId(): ?string
{
return $this->userId;
}

public function setUserId(?string $userId): self
{
$this->userId = $userId;

return $this;
}

public function getIsLockable(): ?bool
{
return $this->isLockable;
Expand Down
22 changes: 22 additions & 0 deletions api/src/Entity/Cronjob.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ class Cronjob
*/
private string $crontab = '*/5 * * * *';

/**
* @var string|null The userId of a user. This user will be used to run this Cronjob for, if there is no logged-in user.
* This helps when, for example: setting the organization of newly created ObjectEntities while running this Cronjob.
*
* @Groups({"read","write"})
*
* @ORM\Column(type="string", length=255, nullable=true)
*/
private ?string $userId = null;

/**
* @var array The actions that put on the stack by the crontab.
*
Expand Down Expand Up @@ -320,6 +330,18 @@ public function setCrontab(string $crontab): self
return $this;
}

public function getUserId(): ?string
{
return $this->userId;
}

public function setUserId(?string $userId): self
{
$this->userId = $userId;

return $this;
}

public function getThrows(): ?array
{
return $this->throws;
Expand Down
2 changes: 1 addition & 1 deletion api/src/Entity/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class Entity
private $extend = false;

/**
* Whether objects created from this entity should be available to child organisations.
* Whether objects created from this entity should be available to child organizations.
*
* @Groups({"read","write"})
*
Expand Down
Loading
Loading