-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOmnipediaWikiNodeChangesController.php
260 lines (228 loc) · 9 KB
/
OmnipediaWikiNodeChangesController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
<?php
declare(strict_types=1);
namespace Drupal\omnipedia_changes\Controller;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Drupal\omnipedia_changes\Service\WikiNodeChangesBuilderInterface;
use Drupal\omnipedia_changes\Service\WikiNodeChangesCacheInterface;
use Drupal\omnipedia_changes\Service\WikiNodeChangesInfoInterface;
use Drupal\omnipedia_core\Service\WikiNodeRevisionInterface;
use Drupal\omnipedia_date\Service\TimelineInterface;
use Drupal\omnipedia_main_page\Service\MainPageResolverInterface;
use Drupal\typed_entity\EntityWrapperInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Returns responses for the Omnipedia wiki node changes route.
*/
class OmnipediaWikiNodeChangesController implements ContainerInjectionInterface {
use StringTranslationTrait;
/**
* Constructs this controller; saves dependencies.
*
* @param \Drupal\Core\Session\AccountProxyInterface $currentUser
* The current user proxy service.
*
* @param \Psr\Log\LoggerInterface $loggerChannel
* Our logger channel.
*
* @param \Drupal\omnipedia_main_page\Service\MainPageResolverInterface $mainPageResolver
* The Omnipedia main page resolver service.
*
* @param \Drupal\omnipedia_date\Service\TimelineInterface $timeline
* The Omnipedia timeline service.
*
* @param \Drupal\typed_entity\EntityWrapperInterface $typedEntityRepositoryManager
* The Typed Entity repository manager.
*
* @param \Drupal\omnipedia_changes\Service\WikiNodeChangesBuilderInterface $wikiNodeChangesBuilder
* The Omnipedia wiki node changes builder service.
*
* @param \Drupal\omnipedia_changes\Service\WikiNodeChangesCacheInterface $wikiNodeChangesCache
* The Omnipedia wiki node changes cache service.
*
* @param \Drupal\omnipedia_changes\Service\WikiNodeChangesInfoInterface $wikiNodeChangesInfo
* The Omnipedia wiki node changes info service.
*
* @param \Drupal\omnipedia_core\Service\WikiNodeRevisionInterface $wikiNodeRevision
* The Omnipedia wiki node revision service.
*
* @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation
* The Drupal string translation service.
*/
public function __construct(
protected readonly AccountProxyInterface $currentUser,
protected readonly LoggerInterface $loggerChannel,
protected readonly MainPageResolverInterface $mainPageResolver,
protected readonly TimelineInterface $timeline,
protected readonly EntityWrapperInterface $typedEntityRepositoryManager,
protected readonly WikiNodeChangesBuilderInterface $wikiNodeChangesBuilder,
protected readonly WikiNodeChangesCacheInterface $wikiNodeChangesCache,
protected readonly WikiNodeChangesInfoInterface $wikiNodeChangesInfo,
protected readonly WikiNodeRevisionInterface $wikiNodeRevision,
protected $stringTranslation,
) {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
$container->get('logger.channel.omnipedia_changes'),
$container->get('omnipedia_main_page.resolver'),
$container->get('omnipedia.timeline'),
$container->get('Drupal\typed_entity\RepositoryManager'),
$container->get('omnipedia.wiki_node_changes_builder'),
$container->get('omnipedia.wiki_node_changes_cache'),
$container->get('omnipedia.wiki_node_changes_info'),
$container->get('omnipedia.wiki_node_revision'),
$container->get('string_translation'),
);
}
/**
* Checks access for the request.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
*
* @param \Drupal\node\NodeInterface $node
* A node object to check access for.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result. Access is granted if the provided node is a wiki node,
* the wiki node is not a main page, the wiki node has a previous revision,
* and $account has access to both the provided wiki node and its previous
* revision.
*/
public function access(
AccountInterface $account, NodeInterface $node,
): AccessResultInterface {
/** @var \Drupal\omnipedia_core\WrappedEntities\NodeWithWikiInfoInterface|null */
$previousWrappedNode = $this->typedEntityRepositoryManager->wrap(
$node,
)->getPreviousWikiRevision();
return AccessResult::allowedIf(
!$this->mainPageResolver->is($node) &&
$node->access('view', $account) &&
\is_object($previousWrappedNode) &&
$previousWrappedNode->getEntity()->access('view', $account),
)
->addCacheableDependency($node);
}
/**
* Checks access for the build route.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
*
* @param \Drupal\node\NodeInterface $node
* A node object to check access for.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function accessBuild(
AccountInterface $account, NodeInterface $node,
): AccessResultInterface {
return $this->access($account, $node)->andIf(
AccessResult::allowedIfHasPermission(
$account, 'build omnipedia_changes',
),
);
}
/**
* Title callback for the route.
*
* @param \Drupal\node\NodeInterface $node
* A node object.
*
* @return array
* A render array containing the changes title for this request.
*/
public function title(NodeInterface $node): array {
/** @var \Drupal\omnipedia_core\WrappedEntities\NodeWithWikiInfoInterface|null */
$previousWrappedNode = $this->typedEntityRepositoryManager->wrap(
$node,
)->getPreviousWikiRevision();
return [
'#markup' => $this->t(
'<span class="page-title__primary">@title<span class="page-title__glue">: </span></span><span class="page-title__secondary">Changes since @date</span>',
[
'@title' => $node->getTitle(),
'@date' => $this->timeline->getDateFormatted(
$previousWrappedNode->getWikiDate(), 'short'
),
]
),
'#allowed_tags' => Xss::getHtmlTagList(),
];
}
/**
* Content callback for the route.
*
* Note that this intentionally checks for and returns invalidated cached
* changes if available to minimize the amount of time the placeholder would
* be shown. We're erring on the side of showing potentially out of date
* changes rather than none at all.
*
* @param \Drupal\node\NodeInterface $node
* A node object.
*
* @return array
* A render array containing the changes content for this request, or a
* placeholder render array if the changes have not yet been built.
*/
public function view(NodeInterface $node): array {
if (!$this->wikiNodeChangesCache->isCached($node, true)) {
// Log this uncached view attempt in case it's useful data for debugging
// or future optimizations.
$this->loggerChannel->debug(
'Wiki node changes not cached: user <code>%uid</code> requested node <code>%nid</code> with cache ID <code>%cid</code><br>Available cache IDs for this node:<pre>%cids</pre>Current user\'s roles:<pre>%roles</pre>',
[
'%uid' => $this->currentUser->id(),
'%nid' => $node->nid->getString(),
'%cid' => $this->wikiNodeChangesInfo->getCacheId(
$node->nid->getString()
),
'%cids' => \print_r($this->wikiNodeChangesInfo->getCacheIds(
$node->nid->getString()
), true),
'%roles' => \print_r($this->currentUser->getRoles(), true),
]
);
return $this->wikiNodeChangesBuilder->buildPlaceholder($node);
}
return $this->wikiNodeChangesBuilder->build($node, true);
}
/**
* Content callback for the build route.
*
* This invalidates the changes for the provided wiki node, builds the
* changes, and then redirects to the changes route.
*
* @param \Drupal\node\NodeInterface $node
* A node object.
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* A redirect response object.
*/
public function viewBuild(NodeInterface $node): RedirectResponse {
$this->wikiNodeChangesCache->invalidate($node);
$this->wikiNodeChangesBuilder->build($node);
/** @var \Drupal\Core\GeneratedUrl */
$generatedUrl = Url::fromRoute('entity.node.omnipedia_changes', [
'node' => $node->nid->getString(),
])->toString(true);
return (new RedirectResponse(
$generatedUrl->getGeneratedUrl(), 302,
));
}
}