Commit d6ce0db7 authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Merge branch 'macclane' into macclane-pcru

parents 81cc11a8 5ca35e17
Loading
Loading
Loading
Loading
+133 −0
Changes for module/Oscar/src/Oscar/Command/OscarActivityCsvToJsonCommand.php: 133 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php
/**
 * Created by PhpStorm.
 * User: bouvry
 * Date: 04/10/19
 * Time: 11:49
 */

namespace Oscar\Command;


use Doctrine\ORM\EntityManager;
use Moment\Moment;
use Oscar\Connector\ConnectorActivityCSVWithConf;
use Oscar\Connector\ConnectorActivityJSON;
use Oscar\Entity\Authentification;
use Oscar\Entity\LogActivity;
use Oscar\Entity\OrganizationRole;
use Oscar\Entity\Person;
use Oscar\Entity\Role;
use Oscar\Entity\RoleRepository;
use Oscar\Exception\OscarException;
use Oscar\Formatter\ConnectorRepportToPlainText;
use Oscar\Service\ConnectorService;
use Oscar\Service\OrganizationService;
use Oscar\Service\OscarConfigurationService;
use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
use Oscar\Service\ProjectGrantService;
use Oscar\Utils\ActivityCSVToObject;
use Oscar\Utils\PhpPolyfill;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class OscarActivityCsvToJsonCommand extends OscarCommandAbstract
{
    protected static $defaultName = 'activity:cvstojson';

    protected function configure()
    {
        $this
            ->setDescription("Synchronisation d'activité de recherche à partir d'un fichier JSON")
            ->addOption('fichier', 'f', InputOption::VALUE_REQUIRED, 'Fichier CSV avec les données')
            ->addOption('config', 'c', InputOption::VALUE_REQUIRED, "Fichier de configuration de l'import")
            ->addOption('skip', 's', InputOption::VALUE_REQUIRED, "Fichier de configuration de l'import", 1)
        ;
    }

    private function getReadablePath($path)
    {
        $realpath = realpath($path);

        if (!$realpath) {
            throw new OscarException(sprintf("Le chemin '%s' n'a aucun sens...",
                $path));
        }


        if (!is_file($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas un fichier... faites un effort.",
                $realpath));
        }

        if (!is_readable($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas lisible....",
                $realpath));
        }

        return $realpath;
    }


    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addOutputStyle($output);

        /** @var OscarUserContext $oscaruserContext */
        $oscaruserContext = $this->getServicemanager()->get(OscarUserContext::class);

        $io = new SymfonyStyle($input, $output);

        $io->title("Conversion CSV > JSON des activités");

        ///////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////// SERVICES
        /** @var OscarConfigurationService $oscarConfig */
        $oscarConfig = $this->getServicemanager()->get(OscarConfigurationService::class);

        /** @var ProjectGrantService $projectGrantService */
        $projectGrantService = $this->getServicemanager()->get(ProjectGrantService::class);

        /** @var EntityManager $entityManager */
        $entityManager = $this->getServicemanager()->get(EntityManager::class);


        // Fichiers
        try {
            $sourceFilePath = $this->getReadablePath($input->getOption('fichier'));
            $configurationFilePath = $this->getReadablePath($input->getOption('config'));
            $skip = $input->getOption('skip');

            $configuration = require($configurationFilePath);
            $source = fopen($sourceFilePath, 'r');

            while ($skip > 0) {
                fgetcsv($source);
                $skip--;
            }

            $sync = new ConnectorActivityCSVWithConf($source, $configuration,
                $this->getServicemanager()->get(EntityManager::class));

            $datas = $sync->syncAll();
            $json = PhpPolyfill::jsonEncode($datas, JSON_PRETTY_PRINT);
            $error =  json_last_error();

            if( $error ){
                $io->error($error);
            } else {
                echo $json;
            }

        } catch (\Exception $e) {
            $io->error($e->getMessage());
        }
        /****/
    }
}
 No newline at end of file
+176 −0
Changes for module/Oscar/src/Oscar/Command/OscarActivityImportJsonCommand.php: 176 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php
/**
 * Created by PhpStorm.
 * User: bouvry
 * Date: 04/10/19
 * Time: 11:49
 */

namespace Oscar\Command;


use Doctrine\ORM\EntityManager;
use Moment\Moment;
use Oscar\Connector\ConnectorActivityJSON;
use Oscar\Entity\Authentification;
use Oscar\Entity\LogActivity;
use Oscar\Entity\OrganizationRole;
use Oscar\Entity\Person;
use Oscar\Entity\Role;
use Oscar\Entity\RoleRepository;
use Oscar\Exception\OscarException;
use Oscar\Formatter\ConnectorRepportToPlainText;
use Oscar\Service\ConnectorService;
use Oscar\Service\OrganizationService;
use Oscar\Service\OscarConfigurationService;
use Oscar\Service\OscarUserContext;
use Oscar\Service\PersonService;
use Oscar\Service\ProjectGrantService;
use Oscar\Utils\ActivityCSVToObject;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class OscarActivityImportJsonCommand extends OscarCommandAbstract
{
    protected static $defaultName = 'activity:import-json';

    protected function configure()
    {
        $this
            ->setDescription("Synchronisation d'activité de recherche à partir d'un fichier JSON")
            ->addOption('fichier', 'f', InputOption::VALUE_REQUIRED, 'Fichier JSON')
        ;

        $this->addOption('create-missing-project', 'p', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les projets manquants",false);
//
        $this->addOption('create-missing-person', 'e', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les personnes manquantes",false);

        $this->addOption('create-missing-person-role', 'r', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les rôles des personnes manquants",false);

        $this->addOption('create-missing-organization', 'o', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les organisations manquantes",false);

        $this->addOption('create-missing-organization-role', 'l', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les rôles des organisations manquants",false);

        $this->addOption('create-missing-activity-type', 'y', InputOption::VALUE_OPTIONAL,
            "Créer automatiquement les types d'activités manquantes",false);
    }

    private function getReadablePath($path)
    {
        $realpath = realpath($path);

        if (!$realpath) {
            throw new OscarException(sprintf("Le chemin '%s' n'a aucun sens...",
                $path));
        }


        if (!is_file($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas un fichier... faites un effort.",
                $realpath));
        }

        if (!is_readable($realpath)) {
            throw new OscarException(sprintf("Le chemin '%s' n'est pas lisible....",
                $realpath));
        }

        return $realpath;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->addOutputStyle($output);

        /** @var OscarUserContext $oscaruserContext */
        $oscaruserContext = $this->getServicemanager()->get(OscarUserContext::class);

        $io = new SymfonyStyle($input, $output);

        $io->title("Synchronisation des activités");

        ///////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////// SERVICES
        /** @var OscarConfigurationService $oscarConfig */
        $oscarConfig = $this->getServicemanager()->get(OscarConfigurationService::class);

        /** @var ProjectGrantService $projectGrantService */
        $projectGrantService = $this->getServicemanager()->get(ProjectGrantService::class);

        /** @var EntityManager $entityManager */
        $entityManager = $this->getServicemanager()->get(EntityManager::class);


        ///////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////// OPTIONS
        try {
            $file = $this->getReadablePath($input->getOption('fichier'));
        } catch (\Exception $e ){
            $io->error("Impossible de lire le fichier source : " . $e->getMessage());
            return;
        }

        $options = [
            'create-missing-project' => $input->getOption('create-missing-project', false) !== false,
            'create-missing-person' => $input->getOption('create-missing-person', false) !== false,
            'create-missing-person-role' => $input->getOption('create-missing-person-role', false) !== false,
            'create-missing-organization' => $input->getOption('create-missing-organization', false) !== false,
            'create-missing-organization-role' => $input->getOption('create-missing-organization-role', false) !== false,
            'create-missing-activity-type' => $input->getOption('create-missing-activity-type', false) !== false,
        ];

        $fileExtension = pathinfo($file)['extension'];

        if ($fileExtension == "csv") {
            $handler = fopen($file, 'r');
            $headers = fgetcsv($handler);

            /** @var RoleRepository $repositoryRole */
            $repositoryRole = $entityManager->getRepository(Role::class);

            // Construction de la correspondance role > colonne
            $rolesPersons = $repositoryRole->getRolesAtActivityArray();
            $correspondanceRolesActivites = [];
            /** @var Role $role */
            foreach ($rolesPersons as $role) {
                $correspondanceRolesActivites[$role] = array_search($role,
                    $headers);
            }

            // Construction de la correspondance role > colonne
            $rolesOrganizations = $entityManager->getRepository(OrganizationRole::class)->findAll();
            $correspondanceRolesOrga = [];
            /** @var OrganizationRole $role */
            foreach ($rolesOrganizations as $role) {
                $correspondanceRolesOrga[$role->getLabel()] = array_search($role->getLabel(),
                    $headers);
            }

            $converteur = new ActivityCSVToObject($correspondanceRolesActivites,
                $correspondanceRolesOrga);
            $json = $converteur->convert($file);
        } elseif ($fileExtension == "json") {
            $json = json_decode(file_get_contents($file));
        } else {
            die("ERROR : Format non pris en charge.");
        }

        $importer = new ConnectorActivityJSON($json, $entityManager,
            $options);
        $repport = $importer->syncAll();

        $output = new ConnectorRepportToPlainText();
        $output->format($repport);
        /****/
    }
}
 No newline at end of file
+26 −14
Changes for module/Oscar/src/Oscar/Entity/PersonRepository.php: 26 added lines, 14 removed lines.
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
    private $_cacheSelectebleRolesOrganisation;


    public function removePersonById(int $personId){
    public function removePersonById(int $personId)
    {
        $sql = "DELETE FROM person WHERE id = :id";
        $params = array('id' => $personId);
        $stmt = $this->getEntityManager()->getConnection()->prepare($sql);
@@ -32,18 +33,21 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
    }


    public function removePerson(Person $person){
    public function removePerson(Person $person)
    {
        $this->getEntityManager()->remove($person);
    }

    public function removePersons( array $ids ){
    public function removePersons(array $ids)
    {
        return $this->createQueryBuilder('p')->delete()->where('p.id IN(:ids)')
            ->setParameter('ids', $ids)
            ->getQuery()
            ->execute();
    }

    public function getPersonsByIds( array $ids ){
    public function getPersonsByIds(array $ids)
    {
        $qb = $this->getBaseQuery()
            ->where('p.id IN (:ids)')
            ->setParameter('ids', $ids);
@@ -58,7 +62,8 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
     * @param $connector
     * @return array
     */
    public function getUidsConnector($connector){
    public function getUidsConnector($connector)
    {
        $qb = $this->getEntityManager()->createQueryBuilder();
        $search = sprintf('s:%s:"%s";', strlen($connector), $connector);

@@ -74,7 +79,8 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
        return $uids;
    }

    public function getPersonsIdsForActivitiesids( $activitiesIds ){
    public function getPersonsIdsForActivitiesids($activitiesIds)
    {
        $queryActivity = $this->createQueryBuilder('p')
            ->select('DISTINCT p.id')
            ->innerJoin('p.activities', 'ap')
@@ -102,7 +108,8 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
     * @param $organisationIds
     * @return array
     */
    public function getPersonIdsInOrganizations( $organisationIds ){
    public function getPersonIdsInOrganizations($organisationIds)
    {
        $result = $this->createQueryBuilder('p')
            ->select('p.id')
            ->innerJoin('p.organizations', 'op')
@@ -113,7 +120,8 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
        return array_map('current', $result);
    }

    public function getPersonIdsForOrganizationsActivities( $organizationIds ){
    public function getPersonIdsForOrganizationsActivities($organizationIds)
    {
        $activityMembers = $this->getEntityManager()->getRepository(Person::class)->createQueryBuilder('p')
            ->select('DISTINCT p.id')
            ->innerJoin('p.activities', 'ap')
@@ -141,18 +149,19 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
        return array_unique(array_merge($idsFromActivities, $idsFromProjects));
    }

    public function getSubordinates( $idReferent ){
    public function getSubordinates($idReferent)
    {
        $ids = $this->getSubordinatesIds($idReferent);
        return $this->createQueryBuilder('p')
            ->where('p.id IN(:ids)')
            ->setParameter('ids', $ids)
            ->getQuery()
            ->getResult()
        ;
            ->getResult();

    }

    public function getSubordinatesIds( $referentId ){
    public function getSubordinatesIds($referentId)
    {
        $result = $this->getEntityManager()->getRepository(Referent::class)->createQueryBuilder('r')
            ->select('p.id')
            ->innerJoin('r.person', 'p')
@@ -169,11 +178,14 @@ class PersonRepository extends EntityRepository implements IConnectedRepository
     *
     * @return mixed
     */
    public function getPersonsWithUnreadNotificationsAndAuthentification(){
    public function getPersonsWithUnreadNotificationsAndAuthentification($normalize = false)
    {
        $qb = $this->createQueryBuilder('p');
        $persons = $qb
            ->select('p')
            ->innerJoin(Authentification::class, 'a', Join::WITH, $qb->expr()->eq('p.ladapLogin', 'a.username'))
            ->innerJoin(Authentification::class, 'a', Join::WITH, $qb->expr()->eq(
                $normalize ? 'lower(p.ladapLogin)' : 'p.ladapLogin',
                $normalize ? 'lower(a.username)' : 'a.username'))
            ->innerJoin(NotificationPerson::class, 'n', Join::WITH, $qb->expr()->eq('p.id', 'n.person'))
            ->where('n.read IS NULL')
            ->getQuery()
+4 −1
Changes for module/Oscar/src/Oscar/Service/PersonService.php: 4 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -476,7 +476,10 @@ class PersonService implements UseOscarConfigurationService, UseEntityManager, U
        $this->getLoggerService()->info("Notifications des inscrits à '$cron'");

        // Liste des personnes ayant des notifications non-lues
        $persons = $this->getRepository()->getPersonsWithUnreadNotificationsAndAuthentification();
        $persons = $this->getRepository()->getPersonsWithUnreadNotificationsAndAuthentification(
            $this->getOscarConfigurationService()->getConfiguration('authPersonNormalize', false)
        );

        $this->getLoggerService()->info(sprintf(" %s personne(s) ont des notifications non-lues", count($persons)));

        /** @var Person $person */