lib/private/User/AccountMapper.php
<?php
/**
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC\User;
use OC\DB\QueryBuilder\Literal;
use OCP\AppFramework\Db\Entity;
use OCP\AppFramework\Db\Mapper;
use OCP\IConfig;
use OCP\IDBConnection;
class AccountMapper extends Mapper {
/* @var IConfig */
protected $config;
/* @var AccountTermMapper */
protected $termMapper;
public function __construct(IConfig $config, IDBConnection $db, AccountTermMapper $termMapper) {
parent::__construct($db, 'accounts', Account::class);
$this->config = $config;
$this->termMapper = $termMapper;
}
/**
* Delegate to term mapper to avoid needing to inject term mapper
* @param $account_id
* @param array $terms
*/
public function setTermsForAccount($account_id, array $terms) {
$this->termMapper->setTermsForAccount($account_id, $terms);
}
/**
* Delegate to term mapper to avoid needing to inject term mapper
* @param $account_id
* @return AccountTerm[] $terms
*/
public function findByAccountId($account_id) {
return $this->termMapper->findByAccountId($account_id);
}
/**
* @param Account $entity
* @return Entity the saved entity with the set id
*/
public function insert(Entity $entity) {
$entity->setCreationTime(\time());
// run the normal entity insert operation to get an id
$entity = parent::insert($entity);
/** @var Account $entity */
if ($entity->haveTermsChanged()) {
$this->termMapper->setTermsForAccount($entity->getId(), $entity->getSearchTerms());
}
return $entity;
}
/**
* @param Account $entity
* @return Entity the deleted entity
*/
public function delete(Entity $entity) {
// First delete the search terms for this account
$this->termMapper->deleteTermsForAccount($entity->getId());
return parent::delete($entity);
}
/**
* @param Account $entity
* @return Entity the updated entity
*/
public function update(Entity $entity) {
if ($entity->haveTermsChanged()) {
$this->termMapper->setTermsForAccount($entity->getId(), $entity->getSearchTerms());
}
// Then run the normal entity insert operation
return parent::update($entity);
}
/**
* @param string $email
* @return Account[]
*/
public function getByEmail($email) {
if ($email === null || \trim($email) === '') {
throw new \InvalidArgumentException('$email must be defined');
}
$qb = $this->db->getQueryBuilder();
// RFC 5321 says that only domain name is case insensitive, but in practice
// it's the whole email
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq($qb->createFunction('LOWER(`email`)'), $qb->createFunction('LOWER(' . $qb->createNamedParameter($email) . ')')));
return $this->findEntities($qb->getSQL(), $qb->getParameters());
}
/**
* @param string $uid
* @return Account
*/
public function getByUid($uid) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('lower_user_id', $qb->createNamedParameter(\strtolower($uid))));
return $this->findEntity($qb->getSQL(), $qb->getParameters());
}
/**
* @param string $fieldName
* @param string $pattern
* @param integer $limit
* @param integer $offset
* @return Account[]
*/
public function search($fieldName, $pattern, $limit, $offset) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->iLike($fieldName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%')))
->orderBy($fieldName);
return $this->findEntities($qb->getSQL(), $qb->getParameters(), $limit, $offset);
}
/**
* @param string $pattern
* @param integer $limit
* @param integer $offset
* @return Account[]
*/
public function find($pattern, $limit = null, $offset = null) {
$allowMedialSearches = $this->config->getSystemValue('accounts.enable_medial_search', true);
if ($allowMedialSearches) {
$parameter = '%' . $this->db->escapeLikeParameter($pattern) . '%';
$loweredParameter = '%' . $this->db->escapeLikeParameter(\strtolower($pattern)) . '%';
} else {
$parameter = $this->db->escapeLikeParameter($pattern) . '%';
$loweredParameter = $this->db->escapeLikeParameter(\strtolower($pattern)) . '%';
}
$qb = $this->db->getQueryBuilder();
$qb->selectAlias('DISTINCT a.id', 'id')
->addSelect(['user_id', 'lower_user_id', 'display_name', 'email', 'last_login', 'creation_time', 'backend', 'state', 'quota', 'home'])
->from($this->getTableName(), 'a')
->leftJoin('a', 'account_terms', 't', $qb->expr()->eq('a.id', 't.account_id'))
->orderBy('user_id')
->where($qb->expr()->like('lower_user_id', $qb->createPositionalParameter($loweredParameter)))
->orWhere($qb->expr()->iLike('display_name', $qb->createPositionalParameter($parameter)))
->orWhere($qb->expr()->iLike('email', $qb->createPositionalParameter($parameter)))
->orWhere($qb->expr()->like('t.term', $qb->createPositionalParameter($loweredParameter)));
return $this->findEntities($qb->getSQL(), $qb->getParameters(), $limit, $offset);
}
public function getUserCountPerBackend($hasLoggedIn) {
$qb = $this->db->getQueryBuilder();
$qb->select(['backend', $qb->createFunction('count(*) as `count`')])
->from($this->getTableName())
->groupBy('backend');
if ($hasLoggedIn) {
$qb->where($qb->expr()->gt('last_login', new Literal(0)));
}
$result = $qb->execute();
$data = $result->fetchAll();
$result->closeCursor();
$return = [];
foreach ($data as $d) {
$return[$d['backend']] = $d['count'];
}
return $return;
}
public function getUserCount($hasLoggedIn) {
$qb = $this->db->getQueryBuilder();
$qb->select([$qb->createFunction('count(*) as `count`')])
->from($this->getTableName());
if ($hasLoggedIn) {
$qb->where($qb->expr()->gt('last_login', new Literal(0)));
}
$result = $qb->execute();
$data = $result->fetch();
$result->closeCursor();
return (int) $data['count'];
}
public function callForAllUsers($callback, $search, $onlySeen) {
$this->callForUsers($callback, $search, $onlySeen);
}
public function callForUsers($callback, $search, $onlySeen, $limit = null, $offset = null) {
$qb = $this->db->getQueryBuilder();
$qb->select(['*'])
->from($this->getTableName());
if ($search) {
$qb->where($qb->expr()->iLike(
'user_id',
$qb->createNamedParameter('%' . $this->db->escapeLikeParameter($search) . '%')
));
}
if ($onlySeen) {
$qb->where($qb->expr()->gt('last_login', new Literal(0)));
}
if ($limit !== null || $offset !== null) {
$qb->orderBy('user_id'); // needed for predictable limit & offset
}
if ($limit !== null) {
$qb->setMaxResults($limit);
}
if ($offset !== null) {
$qb->setFirstResult($offset);
}
$stmt = $qb->execute();
while ($row = $stmt->fetch()) {
$return = $callback($this->mapRowToEntity($row));
if ($return === false) {
break;
}
}
$stmt->closeCursor();
}
/**
* @param string $backend
* @param bool $hasLoggedIn
* @param integer $limit
* @param integer $offset
* @return string[]
*/
public function findUserIds($backend = null, $hasLoggedIn = null, $limit = null, $offset = null) {
$qb = $this->db->getQueryBuilder();
$qb->select('user_id')
->from($this->getTableName())
->orderBy('user_id'); // needed for predictable limit & offset
if ($backend !== null) {
$qb->andWhere($qb->expr()->eq('backend', $qb->createNamedParameter($backend)));
}
if ($hasLoggedIn === true) {
$qb->andWhere($qb->expr()->gt('last_login', new Literal(0)));
} elseif ($hasLoggedIn === false) {
$qb->andWhere($qb->expr()->eq('last_login', new Literal(0)));
}
if ($limit !== null) {
$qb->setMaxResults($limit);
}
if ($offset !== null) {
$qb->setFirstResult($offset);
}
$stmt = $qb->execute();
$rows = $stmt->fetchAll(\PDO::FETCH_COLUMN);
$stmt->closeCursor();
return $rows;
}
}