Commit c2ef1337 authored by Thomas Löffler's avatar Thomas Löffler

Merge branch...

Merge branch '225-add-function-to-karmaservice-for-fetching-sum-of-user-s-karma-from-a-single-source' into 'develop'

Resolve "Add function to KarmaService for fetching sum of user's karma from a single source"

Closes #225

See merge request !126
parents e27007a7 f879e8fb
Pipeline #6182 passed with stages
in 4 minutes and 42 seconds
......@@ -3,7 +3,6 @@
namespace T3o\Karma\Controller;
use T3o\Karma\Domain\Repository\FrontendUserRepository;
use T3o\Karma\Domain\Repository\KarmaSourceRepository;
use T3o\Karma\Domain\Repository\LedgerEntryRepository;
use T3o\Karma\Service\KarmaService;
......@@ -42,11 +41,6 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
*/
protected $frontendUserRepository;
/**
* @var KarmaSourceRepository
*/
protected $karmaSourceRepository;
/**
* @var LedgerEntryRepository
*/
......@@ -69,18 +63,18 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
}
/**
* @param KarmaSourceRepository $karmaSourceRepository
* @param LedgerEntryRepository $ledgerEntryRepository
*/
public function injectKarmaSourceRepository(KarmaSourceRepository $karmaSourceRepository)
public function injectLedgerEntryRepository(LedgerEntryRepository $ledgerEntryRepository)
{
$this->karmaSourceRepository = $karmaSourceRepository;
$this->ledgerEntryRepository = $ledgerEntryRepository;
}
/**
* @param LedgerEntryRepository $ledgerEntryRepository
* @return array The source codes for karma
*/
public function injectLedgerEntryRepository(LedgerEntryRepository $ledgerEntryRepository)
public function getKarmaSourceCodes()
{
$this->ledgerEntryRepository = $ledgerEntryRepository;
return array_keys($this->settings['sourceCodes']);
}
}
......@@ -48,9 +48,15 @@ class UserDisplayController extends AbstractController
$immutableValue = $this->karmaService->getImmutableKarmaForUser($frontendUser);
$mutableValue = $this->karmaService->getMutableKarmaForUser($frontendUser);
$sourceTotals = [];
foreach ($this->getKarmaSourceCodes() as $sourceCode) {
$sourceTotals[$sourceCode] = $this->karmaService->getImmutableKarmaSourceTotalForUser($sourceCode, $frontendUser);
}
$this->view->assign('immutableValue', $immutableValue);
$this->view->assign('mutableValue', $mutableValue);
$this->view->assign('hasKarma', ($immutableValue > 0 || $mutableValue > 0));
$this->view->assign('sourceTotals', $sourceTotals);
}
}
}
......@@ -48,6 +48,18 @@ class FrontendUser extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
*/
protected $karmaCacheTimestamp = 0;
/**
* JSON encoded associative array containing totals for the karma source
*
* @var string
*/
protected $karmaSourceTotalCache = '';
/**
* @var array|null
*/
private $karmaSourceTotalCacheDecoded;
/**
* Get the cached immutable karma total
*
......@@ -107,4 +119,50 @@ class FrontendUser extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
{
$this->karmaCacheTimestamp = $karmaCacheTimestamp;
}
/**
* Get the JSON string containing the karma source total cache array
*
* @return string
*/
public function getKarmaSourceTotalCache(): string
{
return $this->karmaSourceTotalCache;
}
/**
* Set the JSON string containing the karma source total cache array
*
* @param string $karmaSourceTotalCache
*/
public function setKarmaSourceTotalCache(string $karmaSourceTotalCache)
{
$this->karmaSourceTotalCache = $karmaSourceTotalCache;
}
/**
* @return array|null
*/
public function getKarmaSourceTotalCacheDecoded(): ?array
{
if ($this->karmaSourceTotalCacheDecoded === null) {
$this->karmaSourceTotalCacheDecoded = json_decode($this->getKarmaSourceTotalCache());
if (!is_array($this->karmaSourceTotalCacheDecoded)) {
$this->karmaSourceTotalCacheDecoded = [];
$this->setKarmaSourceTotalCache(json_encode($this->karmaSourceTotalCacheDecoded));
}
}
return $this->karmaSourceTotalCacheDecoded;
}
/**
* @param array|null $karmaSourceTotalCacheDecoded
*/
public function setKarmaSourceTotalCacheDecoded(array $karmaSouceTotalDecoded)
{
$this->karmaSourceTotalCacheDecoded = $karmaSouceTotalDecoded;
$this->setKarmaSourceTotalCache(json_encode($this->karmaSourceTotalCacheDecoded));
}
}
<?php
namespace T3o\Karma\Domain\Model;
/***************************************************************
* Copyright notice
*
* (c) 2018
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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 General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class KarmaSource extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
/**
* The title of the karma source
*
* @var string
*/
protected $title;
/**
* The alphanumeric code of the karma source
*
* Used for API calls etc.
*
* @var string
*/
protected $code;
/**
* Get the title of the karma source
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set the title of the karma source
*
* @param string $title
*/
public function setTitle(string $title)
{
$this->title = $title;
}
/**
* Get the karma source code
*
* Alphanumeric code for use in APIs etc.
*
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set the karma code
*
* Set the alphanumeric code for use in APIs etc.
*
* @param string $code
*/
public function setCode(string $code)
{
$this->code = $code;
}
}
......@@ -62,12 +62,22 @@ class LedgerEntry extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
protected $mutableValue;
/**
* The entry karma source
* The entry karma source code
*
* @var \T3o\Karma\Domain\Model\KarmaSource
* @var string
*/
protected $karmaSource;
/**
* @var string
*/
protected $issuer;
/**
* @var string
*/
protected $issuerAction;
/**
* Set to the related campaign if the entry is generated through a campaign
*
......@@ -197,7 +207,7 @@ class LedgerEntry extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
/**
* Get the entry karma source
*
* @return \T3o\Karma\Domain\Model\KarmaSource
* @return string
*/
public function getKarmaSource()
{
......@@ -207,13 +217,53 @@ class LedgerEntry extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
/**
* Set the entry karma source
*
* @param \T3o\Karma\Domain\Model\KarmaSource $karmaSource
* @param string $karmaSource
*/
public function setKarmaSource(KarmaSource $karmaSource)
public function setKarmaSource(string $karmaSource)
{
$this->karmaSource = $karmaSource;
}
/**
* Get the issuer code
*
* @return string
*/
public function getIssuer()
{
return $this->issuer;
}
/**
* Set the issuer code
*
* @param string $issuer
*/
public function setIssuer(string $issuer)
{
$this->issuer = $issuer;
}
/**
* Get the issuer action code
*
* @return string
*/
public function getIssuerAction()
{
return $this->issuerAction;
}
/**
* Set the issuer action code
*
* @param string $issuerAction
*/
public function setIssuerAction(string $issuerAction)
{
$this->issuerAction = $issuerAction;
}
/**
* Get the entry campaign that generated this entry, or null if no campaign
*
......
<?php
namespace T3o\Karma\Domain\Repository;
use T3o\Karma\Domain\Model\LedgerEntry;
use T3o\Karma\Service\KarmaService;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMap;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
/***************************************************************
* Copyright notice
*
* (c) 2018
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script 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 General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
class KarmaSourceRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
{
/**
* @var KarmaService
*/
public $karmaService;
public function injectKarmaService(KarmaService $karmaService)
{
$this->karmaService = $karmaService;
}
/**
* Calculates the immutable karma total for a user
*
* @param \TYPO3\CMS\Extbase\Domain\Model\FrontendUser $frontendUser
* @return int
*/
public function calculateImmutableKarmaTotalForUser(\TYPO3\CMS\Extbase\Domain\Model\FrontendUser $frontendUser)
{
$frontendUser = $this->karmaService->ensureCorrectFrontendUserSubclass($frontendUser);
$queryBuilder = $this->getQueryBuilder();
$result = $queryBuilder
->addSelectLiteral($queryBuilder->expr()->sum('immutable_value'))
->from($this->getTableName())
->where(
$queryBuilder->expr()->eq('user', $frontendUser->getUid()),
$queryBuilder->expr()->eq('expired', 0)
)
->execute();
$sum = $result->fetchColumn(0);
return $sum;
}
/**
* Calculates the mutable karma total for a user
*
* @param \TYPO3\CMS\Extbase\Domain\Model\FrontendUser $frontendUser
*/
public function calculateMutableKarmaTotalForUser(\TYPO3\CMS\Extbase\Domain\Model\FrontendUser $frontendUser)
{
$frontendUser = $this->karmaService->ensureCorrectFrontendUserSubclass($frontendUser);
$queryBuilder = $this->getQueryBuilder();
$result = $queryBuilder
->addSelectLiteral($queryBuilder->expr()->sum('mutable_value'))
->from($this->getTableName())
->where(
$queryBuilder->expr()->eq('user', $frontendUser->getUid()),
$queryBuilder->expr()->eq('expired', 0)
)
->execute();
$sum = $result->fetchColumn(0);
return $sum;
}
/**
* Get the table name for this class
*
* @return string
* @internal
*/
protected function getTableName()
{
/** @var DataMapper $dataMapper */
$dataMapper = GeneralUtility::makeInstance(DataMapper::class);
/** @var DataMap $dataMap */
$dataMap = $dataMapper->getDataMap(LedgerEntry::class);
return $dataMap->getTableName();
}
/**
* Get a QueryBuilder object
*
* @return QueryBuilder
*/
protected function getQueryBuilder()
{
return GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->getTableName());
}
}
......@@ -94,6 +94,37 @@ class LedgerEntryRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
return $sum;
}
/**
* Calculates the immutable karma from a specific source for a specific user
*
* REGARDING MUTABLE VERSION: The mutable version of this function does not
* exist on purpose, because the mutable karma is intended to be source-independent
* so that e.g. writers and developers have the same usage right for their karma.
*
* @param string $source The Karma SourceCode
* @param \TYPO3\CMS\Extbase\Domain\Model\FrontendUser $frontendUser
* @return bool|string
*/
public function calculateImmutableKarmaSourceTotalForUser(string $source, \TYPO3\CMS\Extbase\Domain\Model\FrontendUser $frontendUser)
{
$frontendUser = $this->karmaService->ensureCorrectFrontendUserSubclass($frontendUser);
$queryBuilder = $this->getQueryBuilder();
$result = $queryBuilder
->addSelectLiteral($queryBuilder->expr()->sum('immutable_value'))
->from($this->getTableName())
->where(
$queryBuilder->expr()->eq('user', $frontendUser->getUid()),
$queryBuilder->expr()->eq('expired', 0),
$queryBuilder->expr()->eq('karma_source', $queryBuilder->quote($source))
)
->execute();
$sum = $result->fetchColumn(0);
return $sum;
}
/**
* Get the table name for this class
*
......
......@@ -2,12 +2,9 @@
namespace T3o\Karma\Service;
use T3o\Karma\Domain\Model\Campaign;
use T3o\Karma\Domain\Model\FrontendUser;
use T3o\Karma\Domain\Model\KarmaSource;
use T3o\Karma\Domain\Model\LedgerEntry;
use T3o\Karma\Domain\Repository\FrontendUserRepository;
use T3o\Karma\Domain\Repository\KarmaSourceRepository;
use T3o\Karma\Domain\Repository\LedgerEntryRepository;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser as ExtbaseFrontendUser;
......@@ -46,11 +43,6 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
*/
protected $frontendUserRepository;
/**
* @var \T3o\Karma\Domain\Repository\KarmaSourceRepository
*/
protected $karmaSourceRepository;
/**
* @param LedgerEntryRepository $ledgerEntryRepository
*/
......@@ -67,14 +59,6 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
$this->frontendUserRepository = $frontendUserRepository;
}
/**
* @param KarmaSourceRepository $karmaSourceRepository
*/
public function injectKarmaSourceRepository(KarmaSourceRepository $karmaSourceRepository)
{
$this->karmaSourceRepository = $karmaSourceRepository;
}
/**
* Get the imimmutable karma total from the user
*
......@@ -99,6 +83,7 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
$frontendUser->setKarmaImmutableValueCache($immutableKarma);
$frontendUser->setKarmaMutableValueCache($mutableKarma);
$frontendUser->setKarmaCacheTimestamp(time());
$frontendUser->setKarmaSourceTotalCacheDecoded([]);
$this->frontendUserRepository->update($frontendUser);
}
......@@ -130,6 +115,7 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
$frontendUser->setKarmaMutableValueCache($mutableKarma);
$frontendUser->setKarmaImmutableValueCache($immutableKarma);
$frontendUser->setKarmaCacheTimestamp(time());
$frontendUser->setKarmaSourceTotalCacheDecoded([]);
$this->frontendUserRepository->update($frontendUser);
}
......@@ -137,15 +123,48 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
return $mutableKarma;
}
/**
* Get the immutable karma total for a specific karma source code from the user
*
* @param string $karmaSourceCode The source code to fetch the total for
* @param ExtbaseFrontendUser $frontendUser
* @param bool $ignoreCache Fetch value directly from ledger
* @param bool $updateCacheEntry Update the user's cache entry if we're ignoring cache. Will also update mutable cache.
* @return int Mutable Karma Total
*/
public function getImmutableKarmaSourceTotalForUser($karmaSourceCode, ExtbaseFrontendUser $frontendUser, $ignoreCache = false, $updateCacheEntry = true)
{
$frontendUser = $this->ensureCorrectFrontendUserSubclass($frontendUser);
$totals = $frontendUser->getKarmaSourceTotalCacheDecoded();
if (!$ignoreCache) {
if (isset($totals[$karmaSourceCode])) {
return $totals[$karmaSourceCode];
}
}
$sourceTotal = $this->ledgerEntryRepository->calculateImmutableKarmaSourceTotalForUser($karmaSourceCode, $frontendUser);
if ($updateCacheEntry) {
$totals[$karmaSourceCode] = $sourceTotal;
$frontendUser->setKarmaSourceTotalCacheDecoded($totals);
$this->frontendUserRepository->update($frontendUser);
}
return $sourceTotal;
}
/**
* Add karma to a user
*
* @param int $karmaValue to add to the user
* @param ExtbaseFrontendUser $frontendUser to add the value to
* @param KarmaSource $karmaSource for the karma value
* @param Campaign $campaign for the value (optional)
* @param string $karmaSource for the karma value
* @param string $karmaIssuer code
* @param string $karmaIssuerAction code
*/
public function addKarmaToUser(int $karmaValue, ExtbaseFrontendUser $frontendUser, KarmaSource $karmaSource, Campaign $campaign = null)
public function addKarmaToUser(int $karmaValue, ExtbaseFrontendUser $frontendUser, string $karmaSource, string $karmaIssuer, string $karmaIssuerAction)
{
$frontendUser = $this->ensureCorrectFrontendUserSubclass($frontendUser);
......@@ -155,9 +174,8 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
$ledgerEntry->setMutableValue($karmaValue);
$ledgerEntry->setUser($frontendUser);
$ledgerEntry->setKarmaSource($karmaSource);
if ($campaign !== null) {
$ledgerEntry->setCampaign($campaign);
}
$ledgerEntry->setIssuer($karmaIssuer);
$ledgerEntry->setIssuerAction($karmaIssuerAction);
$this->ledgerEntryRepository->add($ledgerEntry);
......@@ -167,34 +185,6 @@ class KarmaService implements \TYPO3\CMS\Core\SingletonInterface
$this->frontendUserRepository->update($frontendUser);
}
/**
* Get a Karma Source object. Will generate a new object with code and label if none exists.
*
* @param string $sourceCode
* @param string $defaultLabel
* @return KarmaSource
* @throws \Exception when $sourceCode is an empty string
*/
public function getKarmaSourceByCode(string $sourceCode, $defaultLabel='[No Label Set]')
{
if ($sourceCode == '') {
throw new \Exception('Empty karma source code supplied.', 1541508560);
}
$karmaSource = $this->karmaSourceRepository->findByCode($sourceCode)->getFirst();
if ($karmaSource === null) {
/** @var KarmaSource $karmaSource */
$karmaSource = new KarmaSource();
$karmaSource->setCode($sourceCode);
$karmaSource->setTitle($defaultLabel);
$this->karmaSourceRepository->add($karmaSource);
}
return $karmaSource;
}
/**
* Will take any FrontendUser object and return a karma extension FrontendUser subclass with the data we need
*
......
......@@ -3,9 +3,7 @@
namespace T3o\Karma\Utility;
use In2code\Femanager\Controller\AbstractController as In2CodeAbstractController;
use T3o\Karma\Domain\Model\KarmaSource;
use T3o\Karma\Domain\Repository\FrontendUserRepository;
use T3o\Karma\Domain\Repository\KarmaSourceRepository;
use T3o\Karma\Service\KarmaService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser as ExtbaseFrontendUser;
......@@ -36,6 +34,8 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
class UserProfileChangeKarmaIssuerUtility
{
public const ISSUER_CODE = 'userProfileChange';
/**
* @var \T3o\Karma\Service\KarmaService
*/
......@@ -46,11 +46,6 @@ class UserProfileChangeKarmaIssuerUtility
*/
protected $frontendUserRepository;
/**
* @var \T3o\Karma\Domain\Repository\KarmaSourceRepository
*/
protected $karmaSourceRepository;
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
*/
......@@ -91,14 +86,6 @@ class UserProfileChangeKarmaIssuerUtility
$this->frontendUserRepository = $frontendUserRepository;
}
/**
* @param \T3o\Karma\Domain\Repository\KarmaSourceRepository $karmaSourceRepository
*/
public function injectKarmaSourceRepository(KarmaSourceRepository $karmaSourceRepository)
{
$this->karmaSourceRepository = $karmaSourceRepository;
}
/**
* @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
*/
......@@ -114,27 +101,19 @@ class UserProfileChangeKarmaIssuerUtility
*/
public function newUserWasCreated(ExtbaseFrontendUser $frontendUser)
{
$karmaSourceCode = $this->settings['userProfileChangeKarmaIssuer']['newUserWasCreated']['sourceCode'];
$issuerActionSettings = $this->settings['issuers'][self::ISSUER_CODE][__FUNCTION__];
$karmaSourceCode = $issuerActionSettings['sourceCode'];
if ($karmaSourceCode === '') {
throw new \Exception('Empty karma source code supplied. Please configure it in TypoScript.', 1541508560);
}
$karmaSource = $this->karmaSourceRepository->findByCode($karmaSourceCode)->getFirst();
if ($karmaSource === null) {
/** @var KarmaSource $karmaSource */
$karmaSource = new KarmaSource();
$karmaSource->setCode($karmaSourceCode);
$karmaSource->setTitle($this->settings['userProfileChangeKarmaIssuer']['newUserWasCreated']['defaultSourceLabel']);
$this->karmaSourceRepository->add($karmaSource);
}
$this->karmaService->addKarmaToUser(
$this->settings['userProfileChangeKarmaIssuer']['newUserWasCreated']['valueEarned'],
$issuerActionSettings['valueEarned'],
$frontendUser,
$karmaSource
$issuerActionSettings['sourceCode'],
self::ISSUER_CODE,
__FUNCTION__
);
}
}
......@@ -34,6 +34,15 @@ $feUsersColumns = [
'readOnly' => true,
],
],
'karma_source_total_cache' => [
'exclude' => 0,
'config' => [
'label' => $ll . 'fe_users.karma_source_total_cache',
'type' => 'text',
'eval' => '',
'readOnly' => true,