loggedInUserId = $UserId;
$this->serverContainer = $serverContainer;
}
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
*/
public function singleUserTimeGate($userId, $url) {
// XXX workaround, as nextcloud corrupts the $url parameter.
$url = getUrlParameter("u/$userId/timegate");
$matchingMementos = $this->findSingleUserMementosForUrl($userId, $url);
return $this->makeResponse($url, $matchingMementos);
}
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
*/
public function allUsersTimeGate($url) {
$url = getUrlParameter('timegate');
$matchingMementos = $this->findAllUsersMementosForUrl($url);
return $this->makeResponse($url, $matchingMementos);
}
private function makeResponse($url, $matchingMementos) {
// Choose one of the matched mementos, if any.
if (count($matchingMementos) === 0) {
// No matches. :(
$message = "
No snapshots found for requested URL. :(
";
return new DataDisplayResponse($message, 404);
} else if (count($matchingMementos) === 1) {
// One match; no need to choose.
$chosenMemento = $matchingMementos[0];
} else {
// Multiple matches: choose based on requested date.
$acceptDatetimeHeader = $this->request->getHeader('Accept-Datetime');
if ($acceptDatetimeHeader) {
try {
$requestedDatetime = datetimeStringToTimestamp($acceptDatetimeHeader);
} catch (Exception $e) {
return new DataDisplayResponse("Invalid Accept-Datetime header.", 400);
}
} else {
// Not sending the header means requesting the most recent version.
$requestedDatetime = time();
}
// Pick the one closest to the requested date (either before or after it).
$chosenMemento = minBy($matchingMementos,
function ($matchingMemento) use ($requestedDatetime) {
return abs($matchingMemento['datetime'] - $requestedDatetime);
}
);
}
// Send a 302 Found redirect pointing to the chosen memento.
$response = new RedirectResponse($chosenMemento['mementoUrl']);
$response->setStatus(302);
// Both the requested datetime and the authenticated user influence the response.
$response->addHeader('Vary', 'accept-datetime, cookie');
// Add a link to the original(s) and to the timemap.
$originalLinks = implode(", ", array_map(
function ($originalUrl) { return "<$originalUrl>;rel=\"original\""; },
$chosenMemento['originalUrls']
));
// XXX hardcoding the route URL.
$timeMapUrl = $this->serverContainer->getURLGenerator()
->getAbsoluteUrl("/apps/memento/timemap/$url");
$firstDatetime = datetimeTimestampToString($matchingMementos[0]['datetime']);
$lastMemento = $matchingMementos[count($matchingMementos)-1];
$lastDatetime = datetimeTimestampToString($lastMemento['datetime']);
$timeMapLink = "<$timeMapUrl>"
. ";rel=\"timemap\""
. ";type=\"application/link-format\""
. ";from=\"$firstDatetime\";until=\"$lastDatetime\"";
$response->addHeader('Link', "$originalLinks, $timeMapLink");
return $response;
}
}
function minBy($array, $iteratee) {
$values = array_map($iteratee, $array);
$argmin = array_search(min($values), $values);
return $array[$argmin];
}