This repository has been archived by the owner on Oct 2, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathMediaAvailableAccess.php
157 lines (141 loc) · 5.62 KB
/
MediaAvailableAccess.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
<?php
namespace Drupal\media_mpx\Access;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\media\MediaInterface;
use Drupal\media_mpx\Plugin\media\Source\Media;
use Drupal\media_mpx\StubMediaObjectTrait;
use Lullabot\Mpx\DataService\DateTime\AvailabilityCalculator;
use Lullabot\Mpx\DataService\DateTime\ConcreteDateTime;
use Lullabot\Mpx\DataService\Media\Media as MpxMedia;
use Lullabot\Mpx\Exception\ClientException;
use Lullabot\Mpx\Exception\ServerException;
/**
* Check the availability of an mpx media entity.
*
* While mpx has an availability state property, we want to be able to use
* cached mpx data instead of having to re-fetch it from upstream.
*
* @see \Lullabot\Mpx\DataService\DateTime\AvailabilityCalculator
*/
class MediaAvailableAccess {
use StubMediaObjectTrait;
const MAX_AGE_TEN_YEARS = 10 * 365 * 24 * 60 * 60;
/**
* The system time service.
*
* @var \Drupal\Component\Datetime\TimeInterface
*/
protected $time;
/**
* MediaAvailableAccess constructor.
*
* @param \Drupal\Component\Datetime\TimeInterface $time
* The system time service.
*/
public function __construct(TimeInterface $time) {
$this->time = $time;
}
/**
* Return if access is forbidden by availability rules.
*
* @param \Drupal\media\MediaInterface $media
* The media entity to check.
* @param \Drupal\Core\Session\AccountInterface $account
* The account to check access for.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result. A neutral result is returned if the entity is not an
* mpx media object, or if availability rules permit access. A forbidden
* result is returned if the video is expired.
*/
public function view(MediaInterface $media, AccountInterface $account) {
// The media entity is not an mpx media object.
if (!($media->getSource() instanceof Media)) {
return AccessResult::neutral();
}
// If you can update an entity, don't apply availability rules.
if ($media->access('update', $account)) {
return AccessResult::neutral();
}
try {
$access = $this->mpxObjectViewAccess($media);
}
catch (ClientException $e) {
// The requested media was not found in mpx, so deny view access.
$access = AccessResult::forbidden('Requested media was not found in mpx.');
}
catch (ServerException $e) {
// The mpx server errored out for some reason, and as such we can't check
// availability, err on the side of caution and deny access.
$access = AccessResult::forbidden('Mpx server returned an error, could not validate availability');
// Set a cache max age of 15 minutes, allowing for a retry to happen when
// the mpx server is available for a more definitive access check.
$access->setCacheMaxAge(15 * 60);
}
return $access;
}
/**
* Determine the view access of the given media by its availability.
*
* @param \Drupal\media\MediaInterface $media
* The media entity to check.
*
* @return \Drupal\Core\Access\AccessResultInterface
* View access result for the given MPX object.
*
* @throws \Lullabot\Mpx\Exception\ClientException
* @throws \Lullabot\Mpx\Exception\ServerException
*/
protected function mpxObjectViewAccess(MediaInterface $media) {
$mpx_object = $this->getStubMediaObject($media);
$now = \DateTime::createFromFormat('U', $this->time->getCurrentTime());
$calculator = new AvailabilityCalculator();
// Add cache max age based on availability dates.
$this->mergeCacheMaxAge($mpx_object, $media);
// We need to use forbid instead of allowing on available. Otherwise, if
// we allow, Drupal will ignore other access controls like the published
// status.
if ($calculator->isExpired($mpx_object, $now)) {
$access = AccessResult::forbidden('This video is not available.');
}
else {
$access = AccessResult::neutral();
}
// Since access is tied to the availability dates, add media as a cacheable
// dependency so that downstream code can always incorporate it, whether
// the media is being shown or not.
$access->addCacheableDependency($media);
return $access;
}
/**
* Merge cache max age based on availability dates into media cache metadata.
*
* @param \Lullabot\Mpx\DataService\Media\Media $mpx_media
* Mpx media object.
* @param \Drupal\media\MediaInterface $media
* Drupal media entity.
*/
protected function mergeCacheMaxAge(MpxMedia $mpx_media, MediaInterface $media) {
$now = \DateTime::createFromFormat('U', $this->time->getCurrentTime());
$available_date = $mpx_media->getAvailableDate();
if ($available_date instanceof ConcreteDateTime &&
$now < $available_date->getDateTime()) {
$delta = $available_date->getDateTime()->getTimestamp() - $now->getTimestamp();
// Safe guard against radically far out dates. Set the max age to the min
// of the delta between the available date and now and ten years.
$max_age = min($delta, self::MAX_AGE_TEN_YEARS);
$media->mergeCacheMaxAge($max_age);
}
$expiration_date = $mpx_media->getExpirationDate();
if ($expiration_date instanceof ConcreteDateTime &&
$now < $expiration_date->getDateTime()) {
$delta = $expiration_date->getDateTime()->getTimestamp() - $now->getTimestamp();
// Safe guard against radically far out dates. Set the max age to the min
// of the delta between the expiration date and now and ten years.
$max_age = min($delta, self::MAX_AGE_TEN_YEARS);
$media->mergeCacheMaxAge($max_age);
}
}
}