Skip to content

Commit a989289

Browse files
committedOct 22, 2021
feat: Initial commit
0 parents  commit a989289

File tree

14 files changed

+500
-0
lines changed

14 files changed

+500
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
namespace Gerdemann\GoogleIndex\Controller\Module;
3+
4+
use Gerdemann\GoogleIndex\Service\IndexingService;
5+
use Neos\ContentRepository\Domain\Model\NodeInterface;
6+
use Neos\Eel\FlowQuery\FlowQuery;
7+
use Neos\Error\Messages\Message;
8+
use Neos\Flow\Annotations as Flow;
9+
use Neos\Flow\I18n\Translator;
10+
use Neos\Flow\Mvc\View\ViewInterface;
11+
use Neos\Fusion\View\FusionView;
12+
use Neos\Neos\Controller\CreateContentContextTrait;
13+
use Neos\Neos\Controller\Module\AbstractModuleController;
14+
15+
/**
16+
* @Flow\Scope("singleton")
17+
*/
18+
class IndexController extends AbstractModuleController
19+
{
20+
use CreateContentContextTrait;
21+
22+
const UPDATE = 'URL_UPDATED';
23+
const DELETE = 'URL_UPDATED';
24+
25+
/**
26+
* @var FusionView
27+
*/
28+
protected $view;
29+
30+
/**
31+
* @var string
32+
*/
33+
protected $defaultViewObjectName = FusionView::class;
34+
35+
/**
36+
* @var array
37+
*/
38+
protected $viewFormatToObjectNameMap = [
39+
'html' => FusionView::class,
40+
];
41+
42+
/**
43+
* @Flow\Inject
44+
* @var IndexingService
45+
*/
46+
protected $indexingService;
47+
48+
/**
49+
* @Flow\Inject
50+
* @var Translator
51+
*/
52+
protected $translator;
53+
54+
/**
55+
* Sets the Fusion path pattern on the view to avoid conflicts with the frontend fusion
56+
*
57+
* This is not needed if your package does not register itself to `Neos.Neos.fusion.autoInclude.*`
58+
*/
59+
protected function initializeView(ViewInterface $view)
60+
{
61+
parent::initializeView($view);
62+
$view->setFusionPathPattern('resource://Gerdemann.GoogleIndex/Private/Fusion');
63+
}
64+
65+
/**
66+
* Index action
67+
*
68+
* @param int $page
69+
* @param int $limit
70+
*/
71+
public function indexAction(int $page = 1, int $limit = 20)
72+
{
73+
$offset = ($page - 1) * $limit;
74+
$context = $this->createContentContext('live');
75+
$pages = (new FlowQuery([$context->getCurrentSiteNode()]))->find('[instanceof Neos.Neos:Document]')->sort('_lastPublicationDateTime', 'DESC')->slice($offset, $offset + $limit)->get();
76+
$pageCount = ceil((new FlowQuery([$context->getCurrentSiteNode()]))->find('[instanceof Neos.Neos:Document]')->count() / $limit);
77+
78+
$paginationLinks = [];
79+
if ($pageCount > 1) {
80+
for ($i = 1; $i <= $pageCount; $i++) {
81+
if ($pageCount > 10) {
82+
if ($i > 2 && $i < ($pageCount - 1) && $i != $page && $i != ($page - 1) && $i != ($page + 1) && $i != ($page - 2) && $i != ($page + 2)) {
83+
continue;
84+
}
85+
}
86+
$paginationLinks[] = [
87+
'uri' => $this->uriBuilder->reset()->uriFor('index', ['page' => $i]),
88+
'page' => $i,
89+
'current' => $page === $i,
90+
];
91+
}
92+
}
93+
94+
$this->view->assignMultiple([
95+
'documentNode' => $context->getCurrentSiteNode(),
96+
'pages' => $pages,
97+
'paginationLinks' => $paginationLinks,
98+
'flashMessages' => $this->controllerContext->getFlashMessageContainer()->getMessagesAndFlush(),
99+
]);
100+
}
101+
102+
/**
103+
* @param string $url
104+
* @param string $title
105+
*/
106+
public function updateGoogleAction(string $uri, string $title)
107+
{
108+
try {
109+
$this->notifyGoogle($uri, self::UPDATE);
110+
$message = $this->translateById('successfully.updated', [$title]);
111+
$this->addFlashMessage('', $message, Message::SEVERITY_OK);
112+
} catch (\Google_Service_Exception $error) {
113+
$error = json_decode($error->getMessage(), true);
114+
$message = $this->translateById('failed.updated', [$title]);
115+
$this->addFlashMessage('', $message . '<br />(' . (!empty($error['error']['message']) ? $error['error']['message'] : '') . ')', Message::SEVERITY_ERROR);
116+
}
117+
118+
$this->redirect('index');
119+
}
120+
121+
/**
122+
* @param string $url
123+
* @param string $title
124+
*/
125+
public function deleteGoogleAction(string $uri, string $title)
126+
{
127+
try {
128+
$this->notifyGoogle($uri, self::DELETE);
129+
$message = $this->translateById('successfully.deleted', [$title]);
130+
$this->addFlashMessage('', $message, Message::SEVERITY_OK);
131+
} catch (\Google_Service_Exception $error) {
132+
$error = json_decode($error->getMessage(), true);
133+
$message = $this->translateById('failed.deleted', [$title]);
134+
$this->addFlashMessage('', $message . '<br />(' . (!empty($error['error']['message']) ? $error['error']['message'] : '') . ')', Message::SEVERITY_ERROR);
135+
}
136+
137+
$this->redirect('index');
138+
}
139+
140+
/**
141+
* @param string $uri
142+
* @param string $type
143+
*/
144+
protected function notifyGoogle(string $uri, string $type = self::UPDATE)
145+
{
146+
$urlNotification = new \Google_Service_Indexing_UrlNotification();
147+
$today = new \DateTime();
148+
$urlNotification->setNotifyTime($today->format(\DateTime::RFC3339));
149+
$urlNotification->setUrl($uri);
150+
$urlNotification->setType($type);
151+
$this->indexingService->getUrlNotifications()->publish($urlNotification);
152+
}
153+
154+
/**
155+
* @param string|null $id
156+
* @param array $arguments
157+
* @return string
158+
*/
159+
protected function translateById(string $id, array $arguments = []): ?string
160+
{
161+
return $this->translator->translateById($id, $arguments, null, null, 'Main', 'Gerdemann.GoogleIndex');
162+
}
163+
}

‎Classes/Service/IndexingService.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
namespace Gerdemann\GoogleIndex\Service;
3+
4+
use Google_Client;
5+
use Neos\Flow\Annotations as Flow;
6+
7+
/**
8+
*
9+
* @Flow\Scope("singleton")
10+
*/
11+
class IndexingService extends \Google_Service_Indexing
12+
{
13+
/**
14+
* @inheritdoc
15+
*/
16+
public function __construct(Google_Client $client)
17+
{
18+
parent::__construct($client);
19+
$client->addScope(\Google_Service_Indexing::INDEXING);
20+
}
21+
22+
/**
23+
* @return \Google_Service_Indexing_Resource_UrlNotifications
24+
*/
25+
public function getUrlNotifications() {
26+
return $this->urlNotifications;
27+
}
28+
}

‎Configuration/Objects.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Gerdemann\GoogleIndex\Service\IndexingService:
2+
arguments:
3+
1:
4+
object:
5+
factoryObjectName: Flowpack\GoogleApiClient\Service\ClientFactory
6+
factoryMethodName: create

‎Configuration/Policy.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
privilegeTargets:
2+
'Neos\Neos\Security\Authorization\Privilege\ModulePrivilege':
3+
'Gerdemann.GoogleIndex:BackendModule':
4+
matcher: 'management/googleIndex'
5+
6+
roles:
7+
'Neos.Neos:Editor':
8+
privileges:
9+
-
10+
privilegeTarget: 'Gerdemann.GoogleIndex:BackendModule'
11+
permission: GRANT

‎Configuration/Settings.yaml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Flowpack:
2+
GoogleApiClient:
3+
applicationName: 'rezepte-indexing'
4+
Neos:
5+
Neos:
6+
modules:
7+
'management':
8+
submodules:
9+
'googleIndex':
10+
label: 'Google Index'
11+
controller: 'Gerdemann\GoogleIndex\Controller\Module\IndexController'
12+
description: 'Send pages to google.'
13+
icon: 'icon-star'
14+
userInterface:
15+
translation:
16+
autoInclude:
17+
Gerdemann.GoogleIndex:
18+
- 'Main'

‎LICENSE.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2021 Michael Gerdmeann <michael@gerdemann.me>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Gerdemann.GoogleIndex
2+
3+
This package provides a backend module that can be used to trigger
4+
the indexing of pages at Google or to remove pages from the Google index.
5+
6+
**Attention!** Currently, Google officially supports only special page types (e.g. job pages).
7+
Unofficially, however, you can send all pages to Google.
8+
9+
## Installation
10+
11+
You can install the package via composer:
12+
13+
```bash
14+
composer require gerdemann/googleindex
15+
```
16+
17+
The package will register itself automatically.
18+
19+
## Usage
20+
21+
Go to the backend module "Google Index". There you can send the page to Google or remove it from Google.
22+
23+
## License
24+
25+
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
prototype(Gerdemann.GoogleIndex:Component.FlashMessages) < prototype(Neos.Fusion:Component) {
2+
flashMessages = ${[]}
3+
4+
renderer = afx`
5+
<div id="neos-notification-container" class="neos-notification-top" @if.hasMessages={props.flashMessages}>
6+
<Neos.Fusion:Loop items={props.flashMessages} itemName="message">
7+
<Gerdemann.GoogleIndex:Component.FlashMessages.Message message={message}/>
8+
</Neos.Fusion:Loop>
9+
</div>
10+
`
11+
}
12+
13+
prototype(Gerdemann.GoogleIndex:Component.FlashMessages.Message) < prototype(Neos.Fusion:Component) {
14+
message = ${{}}
15+
16+
severity = ${String.toLowerCase(this.message.severity)}
17+
severity.@process.replaceOKStatus = ${value == 'ok' ? 'success' : value}
18+
severity.@process.replaceNoticeStatus = ${value == 'notice' ? 'info' : value}
19+
20+
renderer = afx`
21+
<div id="test" class={'neos-notification neos-notification-' + props.severity}>
22+
<i class="fas fa-times neos-close-button"></i>
23+
<div class="neos-title">{props.message.title}</div>
24+
<div class="neos-message">
25+
<div class={'neos-notification-content' + (props.message.message ? ' expandable' : '')}>
26+
<i class={'fas fa-' + props.severity}></i>
27+
<div class="neos-notification-heading">{props.message.title}</div>
28+
<div class="neos-expand-content">
29+
{props.message.message}
30+
</div>
31+
</div>
32+
</div>
33+
</div>
34+
35+
`
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Gerdemann.GoogleIndex.Module.IndexController.index = Gerdemann.GoogleIndex:Page.List {
2+
pages = Neos.Fusion:Map {
3+
items = ${pages}
4+
itemName = 'page'
5+
itemRenderer = Neos.Fusion:DataStructure {
6+
title = ${q(page).property('title')}
7+
link = Neos.Neos:NodeUri {
8+
node = ${page}
9+
absolute = true
10+
}
11+
updateAction = Neos.Fusion:UriBuilder {
12+
action = 'updateGoogle'
13+
arguments {
14+
title = ${q(page).property('title')}
15+
uri = Neos.Neos:NodeUri {
16+
node = ${page}
17+
absolute = true
18+
}
19+
}
20+
}
21+
deleteAction = Neos.Fusion:UriBuilder {
22+
action = 'deleteGoogle'
23+
arguments {
24+
title = ${q(page).property('title')}
25+
uri = Neos.Neos:NodeUri {
26+
node = ${page}
27+
absolute = true
28+
}
29+
}
30+
}
31+
lastPublicationDateTime = ${Date.format(page.lastPublicationDateTime ? page.lastPublicationDateTime : page.lastModificationDateTime, 'Y-m-d H:i:s')}
32+
}
33+
}
34+
35+
paginationLinks = ${paginationLinks}
36+
}

0 commit comments

Comments
 (0)
Please sign in to comment.