<?php
namespace Diplix\KMGBundle\Repository;
use Diplix\Commons\DataHandlingBundle\Repository\SysLogRepository;
use Diplix\KMGBundle\Entity\Accounting\CoopMember;
use Diplix\KMGBundle\Entity\Customer;
use Diplix\KMGBundle\Entity\DeviceToken;
use Diplix\KMGBundle\Entity\Role;
use Diplix\KMGBundle\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\Query\Parameter;
use Doctrine\Persistence\ManagerRegistry;
use sngrl\PhpFirebaseCloudMessaging\Recipient\Device;
use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserRepository extends ServiceEntityRepository implements UserProviderInterface, UserLoaderInterface
{
use BasicRepositoryTrait;
function em()
{
return $this->_em;
}
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
public function getRoleObjectByRoleName($name)
{
$q = $this->_em->createQueryBuilder()
->select("R")
->from('Diplix\KMGBundle\Entity\Role','R')
->where(sprintf("R.role = '%s'",$name))
->getQuery();
$roles = $q->getResult(AbstractQuery::HYDRATE_OBJECT);
return $roles[0];
}
/**
* Get all users with the given role#
* @param $roleName
* @param null $sort
* @param null $order
* @return array of object
* @throws \Exception
*/
public function findUsersByRole($roleName,$sort=null, $order=null)
{
$role = $this->getRoleObjectByRoleName($roleName);
$qb = $this->createQueryBuilder('A');
$qb->where($qb->expr()->isMemberOf(':role', 'A.roles'))
->setParameter('role',$role)
->andWhere("A.hidden = '0'");
if ($sort!==null)
{
$qb->addOrderBy($sort,$order);
}
$res = $qb->getQuery()->getResult();
$keyed = [];
foreach ($res as $o)
{
$keyed[$o->getId()] = $o;
}
return $keyed;
}
public function getPendingPasswordResetUser($email,$hash)
{
$q = $this->createQueryBuilder('U')
->select('U')
->andWhere('U.email = :email')
->andWhere('U.mailActionHash = :hash')
->andWhere('U.mailActionMode = :mode')
->setParameters(new ArrayCollection(array(
new Parameter('email',$email),
new Parameter('hash',$hash),
new Parameter('mode',User::MAIL_ACTION_RESET_PASSWORD)
)))
->getQuery();
try
{
return $q->getSingleResult(AbstractQuery::HYDRATE_OBJECT);
}
catch (\Exception $ex)
{
return false;
}
}
/**
* @param User $me
* @return array
*/
public function findUsersISubstitute(User $me)
{
$qb = $this->createQueryBuilder("U")
->select("U")
->where("U.currentSubstituteUser = :me")
->setParameter("me",$me)
->andWhere("U.hidden = '0'");
return $qb->getQuery()->getResult();
}
public function findUsersOfCustomer(Customer $customer)
{
$qb = $this->createQueryBuilder("U")
->select("U")
->where("U.customer = :me")
->setParameter("me", $customer)
->andWhere("U.hidden = '0'")
->orderBy('U.lastName')
->addOrderBy('U.firstName');
return $qb->getQuery()->getResult();
}
public function findUsersOfMember(CoopMember $member)
{
$qb = $this->createQueryBuilder('U')
->select('U')
->where('U.member = :me')
->setParameter('me', $member)
->andWhere("U.hidden = '0'");
return $qb->getQuery()->getResult();
}
public function findUsersWhichAreMember()
{
$qb = $this->createQueryBuilder('U')
->select('U','M')
->leftJoin('U.member','M')
->where('U.member is not null')
->andWhere("U.hidden = '0'")
->andWhere("M.active = '1'")
->orderBy('M.shortCode','asc')
->addOrderBy('U.lastName','asc');
return $qb->getQuery()->getResult();
}
public function findUserForList($show='', $filterCustomer=null)
{
$qb = $this->createQueryBuilder("U")
->select("U")
->where("U.hidden = '0'");
if ($show==='customers')
{
$qb->andWhere("U.customer is not null");
// also show entries with a set member
}
else
if ($show==='members')
{
$qb->andWhere("U.member is not null");
// also show entries with a set customer
}
else
{
// no filtering
}
if ($filterCustomer!==null)
{
$qb->andWhere("U.customer = :me")
->setParameter("me", $filterCustomer);
}
return $qb->getQuery()->getResult();
}
public function addFcmTokenToUser($userId, $token, $platform='')
{
if (strlen($token)<1) return false;
$qb = $this->_em->createQueryBuilder()
->select('A,B')
->from(DeviceToken::class,'A')
->leftJoin('A.user','B')
->where('A.token = :token')
->setParameter('token',$token);
$t = $qb->getQuery()->getResult();
$u = $this->findOneBy(['id'=>$userId]);
if ($u===null)
{
return false;
}
$exist = false;
if (count($t)>0)
{
$exist = true;
/** @var DeviceToken $tk */
$tk = $t[0];
// falls das token vorher einem anderen user gehört hat -> umhängen auf den neuen User
// es kann nur ein User ein Token haben !
if ($tk->getUser()->getId()!== $u->getId())
{
$tk->setBeComment(sprintf("[%s] owner for token changed from #%d to #%d",date('d.m.Y H:i:s'),$tk->getUser()->getId(),$u->getId()));
$tk->setUser($u);
}
$tk->setLastSeen(new \DateTime());
}
else
{
$u->getDeviceTokens()->add(DeviceToken::create($u,$token,$platform));
}
$this->flush();
return !$exist;
// /** @var User $u */
// $qb = $this->createQueryBuilder('A')
// ->select('A,B')
// ->leftJoin('A.deviceTokens', 'B')
// ->where('A.id = :id')
// ->setParameter('id',$userId);
// $u = $qb->getQuery()->getResult();
// if (count($u)!==1) return false;
// $u = $u[0];
// $exist = false;
// foreach ($u->getDeviceTokens() as $deviceToken)
// {
// /** @noinspection TypeUnsafeComparisonInspection */
// if ($deviceToken->getToken()==$token)
// {
// $deviceToken->setLastSeen(new \DateTime());
// $exist = true;
// $this->flush($deviceToken);
// break;
// }
// }
// if (!$exist)
// {
// $u->getDeviceTokens()->add(DeviceToken::create($u,$token,$platform));
// }
// $this->flush($u);
// return !$exist;
}
public function findDispoTelegramIds()
{
$users = $this->findUsersByRole(Role::DISPO);
$tids = [];
/** @var User $u */
foreach ($users as $u)
{
if ($u->getTelegramId()!=='')
$tids[]=$u->getTelegramId();
}
return $tids;
}
/***************************************************************************************************
* Implementing the UserProviderInterface
***************************************************************************************************/
/**
* Loads the user for the given username or email address
*
* This method must throw UsernameNotFoundException if the user is not
* found.
*
* @param string $username The username
* @return UserInterface
* @see UsernameNotFoundException
* @see \Symfony\Component\Security\Core\User\UserProviderInterface::loadUserByUsername()
* @throws UsernameNotFoundException if the user is not found
*/
public function loadUserByUsername($username, $suppressSymfonyAuth=false)
{
$qb = $this
->createQueryBuilder('u')
->select('u, r')
->leftJoin('u.roles', 'r');
$qb
->where(
$qb->expr()->orX(
$qb->expr()->eq("u.username",":username"),
$qb->expr()->eq('u.email', ":username"))
)
->setParameter("username",$username);
$q = $qb->getQuery();
try
{
// The Query::getSingleResult() method throws an exception
// if there is no record matching the criteria.
$user = $q->getSingleResult();
}
catch (NoResultException | NonUniqueResultException $e) // php >= 7.1
{
$message = sprintf(
'Unable to find an %s active user object identified by "%s".',
($e instanceof NonUniqueResultException ? 'unique':''),
$username
);
if ($suppressSymfonyAuth)
throw new \RuntimeException($message,0,$e);
else
// UserNameNotFound exception will redirect to auth subsystem and force a http 500 error if this not configured (like when within the service)
throw new UsernameNotFoundException($message, 0, $e);
}
return $user;
}
/**
* Refreshes the user for the account interface.
*
* It is up to the implementation to decide if the user data should be
* totally reloaded (e.g. from the database), or if the UserInterface
* object can just be merged into some internal array of users / identity
* map.
*
* @param UserInterface $user
*
* @return UserInterface
*
* @throws UnsupportedUserException if the account is not supported
*/
public function refreshUser(UserInterface $user)
{
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(
sprintf(
'Instances of "%s" are not supported.',
$class
)
);
}
return $this->find($user->getId());
}
/**
* Whether this provider supports the given user class.
*
* @param string $class
*
* @return bool
*/
public function supportsClass($class)
{
return $this->getEntityName() === $class || is_subclass_of($class, $this->getEntityName());
}
}