owncloud/core

View on GitHub
lib/private/User/AccountMapper.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?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;
    }
}