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]; }