Commit 6356443d authored by Thomas Löffler's avatar Thomas Löffler

Add likes to extensions

parent 72099a02
......@@ -37,7 +37,7 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
protected $versionRepository;
/**
* @var \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository
* @var \T3o\TerFe2\Domain\Repository\FrontendUserRepository
*/
protected $ownerRepository;
......@@ -94,9 +94,9 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
/**
* inject ownerRepository
*
* @param \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository $ownerRepository
* @param \T3o\TerFe2\Domain\Repository\FrontendUserRepository $ownerRepository
*/
public function injectOwnerRepository(\TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository $ownerRepository)
public function injectOwnerRepository(\T3o\TerFe2\Domain\Repository\FrontendUserRepository $ownerRepository)
{
$this->ownerRepository = $ownerRepository;
}
......@@ -202,6 +202,13 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
);
$otherExtensionsByUser = $this->extensionRepository->findAllOtherFromFrontendUser($extension, $extension->getFrontendUser());
$this->view->assign('extensionsByUser', $otherExtensionsByUser);
if ($GLOBALS['TSFE'] && $GLOBALS['TSFE']->loginUser) {
$currentUser = $this->ownerRepository->findByUid((int)$GLOBALS['TSFE']->fe_user->user['uid']);
if ($currentUser instanceof \T3o\TerFe2\Domain\Model\FrontendUser) {
$this->view->assign('hasLiked', $currentUser->getLikedExtensions()->contains($extension));
}
}
}
}
......@@ -505,6 +512,42 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
$this->forwardWithError($this->translate('msg.createVersionUploadFailed'), 'uploadVersion');
}
/**
* @param \T3o\TerFe2\Domain\Model\Extension $extension
* @return bool
*/
public function likeAction(\T3o\TerFe2\Domain\Model\Extension $extension)
{
$liked = false;
if ($GLOBALS['TSFE'] && $GLOBALS['TSFE']->loginUser) {
$currentUser = $this->ownerRepository->findByUid((int)$GLOBALS['TSFE']->fe_user->user['uid']);
if ($currentUser instanceof \T3o\TerFe2\Domain\Model\FrontendUser) {
$currentUser->addLikedExtension($extension);
$this->ownerRepository->update($currentUser);
$this->extensionRepository->update($extension);
$liked = true;
}
}
return json_encode($liked);
}
public function disLikeAction(\T3o\TerFe2\Domain\Model\Extension $extension)
{
$disliked = false;
if ($GLOBALS['TSFE'] && $GLOBALS['TSFE']->loginUser) {
$currentUser = $this->ownerRepository->findByUid((int)$GLOBALS['TSFE']->fe_user->user['uid']);
if ($currentUser instanceof \T3o\TerFe2\Domain\Model\FrontendUser) {
$currentUser->removeLikedExtension($extension);
$this->ownerRepository->update($currentUser);
$this->extensionRepository->update($extension);
$disliked = true;
}
}
return json_encode($disliked);
}
/**
* Check if current frontend user can upload given extension
*
......
......@@ -116,6 +116,11 @@ class Extension extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
*/
protected $composerName = '';
/**
* @var int
*/
protected $likes = 0;
/**
* Initialize all ObjectStorage instances.
*/
......@@ -566,4 +571,33 @@ class Extension extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
$this->composerName = $composerName;
}
/**
* @return int
*/
public function getLikes()
{
return $this->likes;
}
/**
* @param int $likes
* @return void
*/
public function setLikes(int $likes)
{
$this->likes = $likes;
}
public function increaseLikes()
{
$this->likes++;
}
public function decreaseLikes()
{
if ($this->likes > 0) {
$this->likes--;
}
}
}
......@@ -225,5 +225,15 @@ return [
'format' => 'datetime'
],
],
'likes' => [
'exclude' => 1,
'label' => 'Likes from users',
'config' => [
'type' => 'select',
'renderType' => 'selectMultipleSideBySide',
'foreign_table' => 'fe_users',
'MM' => 'tx_terfe2_extension_feuser_mm'
]
]
],
];
......@@ -145,6 +145,9 @@ plugin.tx_terfe2 {
# cat=TER Frontend/view/7020; type=string; label=Layout root path: Path to template layouts
layoutRootPath = EXT:ter_fe2/Resources/Private/Layouts/
}
like.typeNum = 4500
unlike.typeNum = 4501
}
const.page.ter_fe = 1
......@@ -126,3 +126,47 @@ page.jsInline.1.value = var versionChartData = "";
tt_content.list.20.solr_pi_results = TEXT
tt_content.list.20.solr_pi_results.value =
[global]
like = PAGE
like {
typeNum = {$plugin.tx_terfe2.like.typeNum}
config {
disableAllHeaderCode = 1
xhtml_cleaning = none
admPanel = 0
debug = 0
disablePrefixComment = 1
metaCharset = utf-8
additionalHeaders.10.header = Content-Type:application/json
}
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
vendorName = T3o
extensionName = TerFe2
pluginName = Rating
controller = Extension
switchableControllerActions {
Extension {
1 = like
}
}
}
}
dislike < like
dislike.typeNum = {$plugin.tx_terfe2.unlike.typeNum}
dislike.10.switchableControllerActions.Extension.1 = disLike
plugin.tx_terfe2_rating {
features.requireCHashArgumentForActionArguments = 0
}
config.tx_extbase.persistence.classes {
T3o\TerFe2\Domain\Model\FrontendUser {
mapping {
tableName = fe_users
}
}
}
<h3>Installation</h3>
<h3 id="installation">Installation</h3>
<div class="mb-3" id="accordion" role="tablist" aria-multiselectable="true">
<div class="card bgWhite">
<div class="card-header" role="tab" id="headingOne">
......
......@@ -66,6 +66,68 @@
<div hidden itemprop="fileFormat">application/zip</div>
<div hidden itemprop="operatingSystem">Windows,Linux,MacOS</div>
<nav id="extension-nav" class="navbar navbar-light bg-light sticky-top" role="tablist">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarMobile" aria-controls="navbarMobile" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<ul class="nav">
<li class="nav-item">
<f:render partial="Like" arguments="{hasLiked: hasLiked, extension: extension}"></f:render>
</li>
</ul>
<div id="navbarMobile" class="collapse navbar-collapse">
<ul class="navbar-nav">
<li class="nav-item">
<f:if condition="{extension.externalManual}">
<f:then>
<f:link.external class="btn btn-info btn-block" rel="nofollow" uri="{extension.externalManual}" target="_blank">
<i class="fa fa-book"></i> External Manual
</f:link.external>
</f:then>
<f:else>
<f:if condition="{documentationLink}">
<f:link.external class="btn btn-info btn-block" uri="{documentationLink}" target="_blank">
<i class="fa fa-book"></i> Extension Manual
</f:link.external>
</f:if>
</f:else>
</f:if>
</li>
<f:if condition="{extension.forgeLink}">
<li class="nav-item">
<f:link.external class="btn btn-success btn-block" rel="nofollow" uri="{extension.forgeLink}" target="_blank">
<i class="fa fa-hand-o-right"></i> Found an Issue?
</f:link.external>
</li>
</f:if>
<f:if condition="{extension.repositoryUrl}">
<li class="nav-item">
<f:link.external class="btn btn-secondary btn-block" rel="nofollow" uri="{extension.repositoryUrl}" target="_blank">
<i class="fa fa-code-fork"></i> Code Insights
</f:link.external>
</li>
</f:if>
<f:if condition="{extension.paypalUrl}">
<li class="nav-item">
<f:link.external class="btn btn-dark btn-block" rel="nofollow" uri="{extension.paypalUrl}" target="_blank">
<i class="fa fa-thumbs-o-up"></i> Donate
</f:link.external>
</li>
</f:if>
<li class="nav-item dropdown">
<button class="btn btn-light btn-block dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Jump to
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#extension-top">Basic Information</a>
<a class="dropdown-item" href="#installation">Installation HowTo</a>
<a class="dropdown-item" href="#version-history">Version History</a>
</div>
</li>
</ul>
</div>
</nav>
<div class="row mt-3 align-items-center">
<div class="col-md-9">
<header>
......@@ -104,7 +166,7 @@
<h3>Tags</h3>
<p class="tags">
<f:for each="{extension.tags}" as="tag">
<f:link.page class="btn btn-info mb-1" pageUid="{settings.pages.searchResultsPid}" additionalParams="{tx_solr: {filter: {0: 'tags:{tag.title}'}}}">
<f:link.page class="btn btn-outline-info mb-1" pageUid="{settings.pages.searchResultsPid}" additionalParams="{tx_solr: {filter: {0: 'tags:{tag.title}'}}}">
<strong>#{tag.title}</strong>
</f:link.page>
</f:for>
......@@ -130,35 +192,6 @@
</f:if>
</div>
<div class="col-md-4">
<f:if condition="{extension.externalManual}">
<f:then>
<f:link.external class="btn btn-info btn-block" rel="nofollow" uri="{extension.externalManual}" target="_blank">
<i class="fa fa-book"></i> <f:translate key="external_manual" />
</f:link.external>
</f:then>
<f:else>
<f:if condition="{documentationLink}">
<f:link.external class="btn btn-info btn-block" uri="{documentationLink}" target="_blank">
<i class="fa fa-book"></i> Extension manual
</f:link.external>
</f:if>
</f:else>
</f:if>
<f:if condition="{extension.forgeLink}">
<f:link.external class="btn btn-success btn-block" rel="nofollow" uri="{extension.forgeLink}" target="_blank">
<i class="fa fa-hand-o-right"></i> Found an issue? Get in contact!
</f:link.external>
</f:if>
<f:if condition="{extension.repositoryUrl}">
<f:link.external class="btn btn-secondary btn-block" rel="nofollow" uri="{extension.repositoryUrl}" target="_blank">
<i class="fa fa-code-fork"></i> Take a look into the code
</f:link.external>
</f:if>
<f:if condition="{extension.paypalUrl}">
<f:link.external class="btn btn-dark btn-block" rel="nofollow" uri="{extension.paypalUrl}" target="_blank">
<i class="fa fa-thumbs-o-up"></i> Like it? Support it.
</f:link.external>
</f:if>
<div class="alert alert-secondary">
<f:render partial="ExtensionSingleInfo" arguments="{extension:extension, settings:settings, owner:owner, flattrUrl:flattrUrl, documentationLink:documentationLink, qualityLinkNotBroken:qualityLinkNotBroken, urlToQualityServer:urlToQualityServer}" />
</div>
......@@ -167,14 +200,12 @@
<f:render partial="InstallationHowTo" arguments="{_all}" />
<f:if condition="{versionHistory->f:count()} >= 1">
<h3>
<f:translate key="version_history" />
</h3>
<div class="ter-ext-single-versionhistory ter-toggle-hide">
<f:render partial="ExtensionUploadHistoryList" arguments="{versionHistory: extension.reverseVersionsByVersionNumber, extension: extension}" />
</div>
</f:if>
<h3 id="version-history">
<f:translate key="version_history" />
</h3>
<div class="ter-ext-single-versionhistory ter-toggle-hide">
<f:render partial="ExtensionUploadHistoryList" arguments="{versionHistory: extension.reverseVersionsByVersionNumber, extension: extension}" />
</div>
<div class="socialshareprivacy"></div>
</div>
......
......@@ -23,6 +23,17 @@ if (!defined('TYPO3_MODE')) {
]
);
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'T3o.ter_fe2',
'Rating',
[
'Extension' => 'like,disLike'
],
[
'Extension' => 'like,disLike'
]
);
// Register extension providers
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ter_fe2']['extensionProviders'])) {
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ter_fe2']['extensionProviders'] = [];
......
......@@ -19,6 +19,7 @@ CREATE TABLE tx_terfe2_domain_model_extension (
external_manual varchar(255) DEFAULT '' NOT NULL,
paypal_url varchar(255) DEFAULT '' NOT NULL,
expire int(11) unsigned default '0' NOT NULL,
likes int(11) unsigned default '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
......@@ -220,6 +221,10 @@ CREATE TABLE tx_terfe2_domain_model_author (
KEY parent (pid)
);
CREATE TABLE fe_users (
liked_extensions int(11) unsigned DEFAULT '0' NOT NULL
);
# ======================================================================
# Table configuration for table "tx_terfe2_extension_tag_mm"
# ======================================================================
......@@ -232,3 +237,13 @@ CREATE TABLE tx_terfe2_extension_tag_mm (
KEY uid_local (uid_local),
KEY uid_foreign (uid_foreign)
);
CREATE TABLE `tx_terfe2_extension_feuser_mm` (
`uid_local` int(10) unsigned DEFAULT '0' NOT NULL,
`uid_foreign` int(10) unsigned DEFAULT '0' NOT NULL,
`sorting` int(10) unsigned DEFAULT '0' NOT NULL,
`sorting_foreign` int(10) unsigned DEFAULT '0' NOT NULL,
KEY `uid_local` (`uid_local`),
KEY `uid_foreign` (`uid_foreign`)
);
......@@ -67,3 +67,6 @@ span.ter-ext-state-expiremental {
}
}
.tx_terfe2_content .navbar {
padding: 0.5rem 1rem;
}
<?php
namespace T3o\TerFe2\Domain\Model;
/*
* This file is part of a TYPO3 extension.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
class FrontendUser extends \TYPO3\CMS\Extbase\Domain\Model\FrontendUser
{
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\T3o\TerFe2\Domain\Model\Extension>
*/
protected $likedExtensions;
public function __construct()
{
$this->likedExtensions = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getLikedExtensions(): \TYPO3\CMS\Extbase\Persistence\ObjectStorage
{
return $this->likedExtensions;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $likedExtensions
* @return void
*/
public function setLikedExtensions(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $likedExtensions)
{
$this->likedExtensions = $likedExtensions;
}
public function addLikedExtension(Extension $extension)
{
if (!$this->likedExtensions->contains($extension)) {
$extension->increaseLikes();
$this->likedExtensions->attach($extension);
}
}
public function removeLikedExtension(Extension $extension)
{
if ($this->likedExtensions->contains($extension)) {
$extension->decreaseLikes();
$this->likedExtensions->detach($extension);
}
}
}
<?php
/*
* This file is part of a TYPO3 extension.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace T3o\TerFe2\Domain\Repository;
class FrontendUserRepository extends \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository
{
}
<?php
$columns = [
'liked_extensions' => [
'exclude' => 1,
'label' => 'Liked extensions',
'config' => [
'type' => 'select',
'renderType' => 'selectMultipleSideBySide',
'foreign_table' => 'tx_terfe2_domain_model_extension',
'MM' => 'tx_terfe2_extension_feuser_mm',
'MM_opposite_field' => 'likes'
]
]
];
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('fe_users', $columns);
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:security.ifAuthenticated>
<f:then>
<f:if condition="{hasLiked}">
<f:then>
<button class="btn btn-primary" data-rating-type="dislike" title="Click to dislike">
<i class="fa fa-heart"></i>&nbsp;<f:format.number decimals="0" thousandsSeparator=".">{extension.likes}</f:format.number>
</button>
</f:then>
<f:else>
<button class="btn btn-primary" data-rating-type="like" title="Click to like">
<i class="fa fa-heart-o"></i>&nbsp;<f:format.number decimals="0" thousandsSeparator=".">{extension.likes}</f:format.number>
</button>
</f:else>
</f:if>
</f:then>
<f:else>
<button class="btn btn-outline-primary" title="Login to like"><i class="fa fa-heart-o"></i>&nbsp;<f:format.number decimals="0" thousandsSeparator=".">{extension.likes}</f:format.number>
</button>
</f:else>
</f:security.ifAuthenticated>
</html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment