mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
msgraph: add metadata to users to connect with default calendar
This commit is contained in:
parent
5331f1becc
commit
9935af0497
@ -40,13 +40,10 @@ class AzureGetMachineAccessTokenCommand extends Command
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->addOption('tenant', 't', InputOption::VALUE_OPTIONAL, 'the tenant, usually the application name', 'common');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->azure->tenant = $input->getOption('tenant');
|
||||
$this->azure->scope = ['https://graph.microsoft.com/.default'];
|
||||
$authorizationUrl = explode('?', $this->azure->getAuthorizationUrl(['prompt' => 'consent']));
|
||||
// replace the first part by the admin consent authorization url
|
||||
|
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\CalendarBundle\Command;
|
||||
|
||||
use Chill\CalendarBundle\Synchro\Connector\MSGraph\MachineTokenStorage;
|
||||
use Chill\CalendarBundle\Synchro\Connector\MSGraphRemoteCalendarConnector;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MapUserCalendarCommand extends Command
|
||||
{
|
||||
private MSGraphRemoteCalendarConnector $remoteCalendarConnector;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(MSGraphRemoteCalendarConnector $remoteCalendarConnector)
|
||||
{
|
||||
parent::__construct('chill:calendar:map-user');
|
||||
|
||||
$this->remoteCalendarConnector = $remoteCalendarConnector;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$limit = 2;
|
||||
|
||||
do {
|
||||
$users = $this->userRepository->findByNotHavingAttribute('ms:graph', $limit);
|
||||
|
||||
foreach ($users as $user) {
|
||||
$usersData = $this->remoteCalendarConnector->getUserByEmail($user->getEmailCanonical());
|
||||
|
||||
$defaultCalendar
|
||||
|
||||
$user->setAttributes(['ms:graph' => [
|
||||
|
||||
]]);
|
||||
}
|
||||
|
||||
} while (count($users) === $limit);
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -20,6 +20,8 @@ class MSGraphClient
|
||||
|
||||
private MSGraphTokenStorage $tokenStorage;
|
||||
|
||||
private MachineTokenStorage $machineTokenStorage;
|
||||
|
||||
/**
|
||||
* @param mixed $calendar
|
||||
*
|
||||
@ -36,4 +38,6 @@ class MSGraphClient
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\CalendarBundle\Synchro\Connector\MSGraph;
|
||||
|
||||
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
|
||||
|
||||
class MachineHttpClient implements HttpClientInterface
|
||||
{
|
||||
private HttpClientInterface $decoratedClient;
|
||||
|
||||
private MachineTokenStorage $machineTokenStorage;
|
||||
|
||||
use BearerAuthorizationTrait;
|
||||
|
||||
/**
|
||||
* @param HttpClientInterface $decoratedClient
|
||||
*/
|
||||
public function __construct(MachineTokenStorage $machineTokenStorage, ?HttpClientInterface $decoratedClient = null)
|
||||
{
|
||||
$this->decoratedClient = $decoratedClient ?? \Symfony\Component\HttpClient\HttpClient::create();
|
||||
$this->machineTokenStorage = $machineTokenStorage;
|
||||
}
|
||||
|
||||
public function request(string $method, string $url, array $options = []): ResponseInterface
|
||||
{
|
||||
$options['headers'] = array_merge(
|
||||
$options['headers'] ?? [],
|
||||
//['Content-Type' => 'application/json'],
|
||||
$this->getAuthorizationHeaders($this->machineTokenStorage->getToken())
|
||||
);
|
||||
$options['base_uri'] = 'https://graph.microsoft.com/v1.0/';
|
||||
|
||||
dump($options);
|
||||
|
||||
return $this->decoratedClient->request($method, $url, $options);
|
||||
}
|
||||
|
||||
public function stream($responses, float $timeout = null): ResponseStreamInterface
|
||||
{
|
||||
return $this->decoratedClient->stream($responses, $timeout);
|
||||
}
|
||||
}
|
@ -12,6 +12,8 @@ declare(strict_types=1);
|
||||
namespace Chill\CalendarBundle\Synchro\Connector\MSGraph;
|
||||
|
||||
use Chill\MainBundle\Redis\ChillRedis;
|
||||
use League\OAuth2\Client\Token\AccessTokenInterface;
|
||||
use TheNetworg\OAuth2\Client\Provider\Azure;
|
||||
use TheNetworg\OAuth2\Client\Token\AccessToken;
|
||||
|
||||
class MachineTokenStorage
|
||||
@ -20,14 +22,29 @@ class MachineTokenStorage
|
||||
|
||||
private ChillRedis $chillRedis;
|
||||
|
||||
public function __construct(ChillRedis $chillRedis)
|
||||
private Azure $azure;
|
||||
|
||||
private ?AccessTokenInterface $accessToken = null;
|
||||
|
||||
public function __construct(Azure $azure, ChillRedis $chillRedis)
|
||||
{
|
||||
$this->azure = $azure;
|
||||
$this->chillRedis = $chillRedis;
|
||||
}
|
||||
|
||||
public function getToken(): AccessToken
|
||||
public function getToken(): AccessTokenInterface
|
||||
{
|
||||
return unserialize($this->chillRedis->get(self::KEY));
|
||||
if (null === $this->accessToken || $this->accessToken->hasExpired()) {
|
||||
$this->accessToken = $this->azure->getAccessToken('client_credentials', [
|
||||
'scope' => 'https://graph.microsoft.com/.default',
|
||||
]);
|
||||
}
|
||||
|
||||
dump($this->accessToken);
|
||||
|
||||
return $this->accessToken;
|
||||
|
||||
//return unserialize($this->chillRedis->get(self::KEY));
|
||||
}
|
||||
|
||||
public function storeToken(AccessToken $token): void
|
||||
|
@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Synchro\Connector;
|
||||
|
||||
use Chill\CalendarBundle\Synchro\Connector\MSGraph\MachineHttpClient;
|
||||
use Chill\CalendarBundle\Synchro\Connector\MSGraph\MSGraphClient;
|
||||
use Chill\CalendarBundle\Synchro\Connector\MSGraph\MSGraphTokenStorage;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
@ -18,21 +19,26 @@ use DateTimeImmutable;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use function Amp\Iterator\toArray;
|
||||
|
||||
class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
{
|
||||
private MSGraphClient $client;
|
||||
|
||||
private MachineHttpClient $machineHttpClient;
|
||||
|
||||
private MSGraphTokenStorage $tokenStorage;
|
||||
|
||||
private UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
public function __construct(
|
||||
MachineHttpClient $machineHttpClient,
|
||||
MSGraphClient $client,
|
||||
MSGraphTokenStorage $tokenStorage,
|
||||
UrlGeneratorInterface $urlGenerator
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->machineHttpClient = $machineHttpClient;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
@ -52,4 +58,18 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
||||
{
|
||||
return $this->client->listEventsForUserCalendar($user->getEmail(), $startDate, $endDate);
|
||||
}
|
||||
|
||||
public function getUserByEmail(string $email): array
|
||||
{
|
||||
return $this->machineHttpClient->request('GET', 'users', [
|
||||
'query' => ['$filter' => "mail eq '${email}'"],
|
||||
])->toArray()['value'];
|
||||
}
|
||||
|
||||
public function getDefaultUserCalendar(string $idOrUserPrincipalName): array
|
||||
{
|
||||
return $this->machineHttpClient->request('GET', "users/$idOrUserPrincipalName/calendars", [
|
||||
'query' => ['$filter' => 'isDefaultCalendar eq true'],
|
||||
])->toArray()['value'];
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,10 @@ use Chill\CalendarBundle\Synchro\Connector\MSGraphRemoteCalendarConnector;
|
||||
use Chill\CalendarBundle\Synchro\Connector\NullRemoteCalendarConnector;
|
||||
use Chill\CalendarBundle\Synchro\Connector\RemoteCalendarConnectorInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use TheNetworg\OAuth2\Client\Provider\Azure;
|
||||
|
||||
class RemoteCalendarCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
@ -30,6 +32,10 @@ class RemoteCalendarCompilerPass implements CompilerPassInterface
|
||||
} else {
|
||||
if ($config['remote_calendars_sync']['microsoft_graph']['enabled']) {
|
||||
$connector = MSGraphRemoteCalendarConnector::class;
|
||||
|
||||
if (!$container->hasAlias(Azure::class)) {
|
||||
$container->setAlias(Azure::class, 'knpu.oauth2.provider.azure');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,15 +350,20 @@ class User implements AdvancedUserInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set attributes.
|
||||
* Merge the attributes with existing attributes.
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Report
|
||||
* Only the key provided will be created or updated.
|
||||
*/
|
||||
public function setAttributes($attributes)
|
||||
public function setAttributes(array $attributes): self
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
$this->attributes = array_merge($this->attributes, $attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function unsetAttribute($key): self
|
||||
{
|
||||
unset($this->attributes[$key]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\GroupCenter;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
@ -157,6 +158,29 @@ final class UserRepository implements ObjectRepository
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find users which does not have a key on attribute column
|
||||
*
|
||||
* @return array|User[]
|
||||
*/
|
||||
public function findByNotHavingAttribute(string $key, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
$rsm = new ResultSetMappingBuilder($this->entityManager);
|
||||
$rsm->addRootEntityFromClassMetadata(User::class, 'u');
|
||||
|
||||
$sql = "SELECT ".$rsm->generateSelectClause()." FROM users u WHERE NOT attributes ? :key OR attributes IS NULL AND enabled IS TRUE";
|
||||
|
||||
if (null !== $limit) {
|
||||
$sql .= " LIMIT $limit";
|
||||
}
|
||||
|
||||
if (null !== $offset) {
|
||||
$sql .= " OFFET $offset";
|
||||
}
|
||||
|
||||
return $this->entityManager->createNativeQuery($sql, $rsm)->setParameter(':key', $key)->getResult();
|
||||
}
|
||||
|
||||
public function getClassName()
|
||||
{
|
||||
return User::class;
|
||||
|
Loading…
x
Reference in New Issue
Block a user