Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 640 #43

Merged
merged 21 commits into from
Nov 22, 2017
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Gemini/cfg/config.example.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
---

debug: false

fedora_base_url: http://localhost:8080/fcrepo/rest

db.options:
driver: pdo_mysql
host: 127.0.0.1
Expand All @@ -21,4 +25,4 @@ syn:
# Path to the syn config file for authentication.
# example can be found here:
# https://github.com/Islandora-CLAW/Syn/blob/master/conf/syn-settings.example.xml
config: ../syn-settings.xml
config: ../syn-settings.xml
162 changes: 84 additions & 78 deletions Gemini/src/Controller/GeminiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

namespace Islandora\Gemini\Controller;

use Islandora\Crayfish\Commons\PathMapper\PathMapperInterface;
use Islandora\Gemini\UrlMapper\UrlMapperInterface;
use Islandora\Gemini\UrlMinter\UrlMinterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGenerator;

/**
* Class GeminiController
Expand All @@ -14,126 +17,129 @@ class GeminiController
{

/**
* @var \Islandora\Crayfish\Commons\PathMapper\PathMapperInterface
* @var \Islandora\Gemini\UrlMapper\UrlMapperInterface
*/
protected $pathMapper;
protected $urlMapper;

/**
* GeminiController constructor.
* @param \Islandora\Crayfish\Commons\PathMapper\PathMapperInterface
* @var \Islandora\Gemini\UrlMinter\UrlMinterInterface
*/
public function __construct(PathMapperInterface $pathMapper)
{
$this->pathMapper = $pathMapper;
}
protected $urlMinter;

/**
* @param string $fedora_path
* @return \Symfony\Component\HttpFoundation\Response
* @var \Symfony\Component\Routing\Generator\UrlGenerator
*/
public function getDrupalPath($fedora_path)
{
try {
if (!$result = $this->pathMapper->getDrupalPath($fedora_path)) {
return new Response(null, 404);
}
protected $urlGenerator;

return new Response($result, 200);
} catch (\Exception $e) {
return new Response($e->getMessage(), 500);
}
/**
* GeminiController constructor.
* @param \Islandora\Gemini\UrlMapper\UrlMapperInterface
* @param \Islandora\Gemini\UrlMinter\UrlMinterInterface
* @param \Symfony\Component\Routing\Generator\UrlGenerator
*/
public function __construct(
UrlMapperInterface $urlMapper,
UrlMinterInterface $urlMinter,
UrlGenerator $urlGenerator
) {
$this->urlMapper = $urlMapper;
$this->urlMinter = $urlMinter;
$this->urlGenerator = $urlGenerator;
}

/**
* @param string $drupal_path
* @param string $uuid
* @return \Symfony\Component\HttpFoundation\Response
*/
public function getFedoraPath($drupal_path)
public function get($uuid)
{
try {
if (!$result = $this->pathMapper->getFedoraPath($drupal_path)) {
return new Response(null, 404);
}

return new Response($result, 200);
} catch (\Exception $e) {
return new Response($e->getMessage(), 500);
$result = $this->urlMapper->getUrls($uuid);
if (empty($result)) {
return new Response("Could not locate URL pair for $uuid", 404);
}
return new JsonResponse($result, 200);
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function createPair(Request $request)
public function post(Request $request)
{
$content_type = $request->headers->get("Content-Type");
if (strcmp($content_type, "application/json") != 0) {
return new Response("POST only accepts json requests", 400);
}

$body = json_decode($request->getContent(), true);

if (!isset($body['drupal'])) {
return new Response("POST body must contain Drupal path", 400);
}
// Request contents are a UUID.
$uuid = $request->getContent();

if (!isset($body['fedora'])) {
return new Response("POST body must contain Fedora path", 400);
if (empty($uuid)) {
return new Response(
"Requests to mint new URLS must contain a UUID in the request body",
400
);
}

try {
$this->pathMapper->createPair(
$this->sanitize($body['drupal']),
$this->sanitize($body['fedora'])
return new Response(
$this->urlMinter->mint($uuid),
200
);
} catch (\InvalidArgumentException $e) {
return new Response(
$e->getMessage(),
$e->getCode()
);
return new Response(null, 201);
} catch (\Exception $e) {
return new Response($e->getMessage(), 500);
}
}

/**
* @param string $drupal_path
* @param string $uuid
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function deleteFromDrupalPath($drupal_path)
public function put($uuid, Request $request)
{
try {
if (!$result = $this->pathMapper->deleteFromDrupalPath($drupal_path)) {
return new Response("Not Found", 404);
}
// Reject non json requests.
if (0 !== strpos($request->headers->get('Content-Type'), 'application/json')) {
return new Response("Invalid Content-Type. Expecting application/json", 400);
}

// Parse request and reject malformed bodies.
$urls = json_decode($request->getContent(), true);

return new Response(null, 204);
} catch (\Exception $e) {
return new Response($e->getMessage(), 500);
if (!isset($urls['drupal'])) {
return new Response("Missing 'drupal' entry in reqeust body.", 400);
}
}

/**
* @param string $fedora_path
* @return \Symfony\Component\HttpFoundation\Response
*/
public function deleteFromFedoraPath($fedora_path)
{
try {
if (!$result = $this->pathMapper->deleteFromFedoraPath($fedora_path)) {
return new Response(null, 404);
}
if (!isset($urls['fedora'])) {
return new Response("Missing 'fedora' entry in reqeust body.", 400);
}

return new Response(null, 204);
} catch (\Exception $e) {
return new Response($e->getMessage(), 500);
// Save URL pair.
$is_new = $this->urlMapper->saveUrls(
$uuid,
$urls['drupal'],
$urls['fedora']
);

// Return 201 or 204 depending on if a new record was created.
$response = new Response(null, $is_new ? 201 : 204);
if ($is_new) {
// Add a Location header if a new record was created.
$url = $this->urlGenerator->generate(
'GET_uuid',
['uuid' => $uuid],
UrlGenerator::ABSOLUTE_URL
);
$response->headers->add(['Location' => $url]);
}
return $response;
}

/**
* @param string $path
* @return string
* @param string $uuid
* @return \Symfony\Component\HttpFoundation\Response
*/
public function sanitize($path)
public function delete($uuid)
{
$sanitized = ltrim($path);
return ltrim($sanitized, '/');
$deleted = $this->urlMapper->deleteUrls($uuid);
return new Response(null, $deleted ? 204 : 404);
}
}
96 changes: 96 additions & 0 deletions Gemini/src/UrlMapper/UrlMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace Islandora\Gemini\UrlMapper;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;

/**
* Class UrlMapper
* @package Islandora\Crayfish\Commons
*/
class UrlMapper implements UrlMapperInterface
{

/**
* @var \Doctrine\DBAL\Connection
*/
protected $connection;

/**
* UrlMapper constructor.
* @param \Doctrine\DBAL\Connection $connection
*/
public function __construct(Connection $connection)
{
$this->connection = $connection;
}

/**
* {@inheritDoc}
*/
public function getUrls($uuid)
{
$sql = 'SELECT drupal, fedora FROM Gemini WHERE uuid = :uuid';
return $this->connection->fetchAssoc(
$sql,
['uuid' => $uuid]
);
}

/**
* {@inheritDoc}
*/
public function saveUrls(
$uuid,
$drupal,
$fedora
) {
$this->connection->beginTransaction();

try {
// Try to insert first, and if the record already exists, update it.
try {
$this->connection->insert(
'Gemini',
['uuid' => $uuid, 'drupal' => $drupal, 'fedora' => $fedora]
);
$this->connection->commit();
return true;
} catch (UniqueConstraintViolationException $e) {
$sql = "UPDATE Gemini SET fedora = :fedora, drupal = :drupal WHERE uuid = :uuid";
$this->connection->executeUpdate(
$sql,
['uuid' => $uuid, 'drupal' => $drupal, 'fedora' => $fedora]
);
$this->connection->commit();
return false;
}
} catch (\Exception $e) {
$this->connection->rollBack();
throw $e;
}
}

/**
* {@inheritDoc}
*/
public function deleteUrls($uuid)
{
$this->connection->beginTransaction();

try {
$count = $this->connection->delete(
'Gemini',
['uuid' => $uuid]
);

$this->connection->commit();

return $count > 0;
} catch (\Exception $e) {
$this->connection->rollBack();
throw $e;
}
}
}
47 changes: 47 additions & 0 deletions Gemini/src/UrlMapper/UrlMapperInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Islandora\Gemini\UrlMapper;

/**
* Interface UrlMapperInterface
* @package Islandora\Crayfish\Commons
*/
interface UrlMapperInterface
{
/**
* @param string $uuid
*
* @throws \Exception
*
* @return mixed array|null
*/
public function getUrls(
$uuid
);

/**
* @param string $uuid
* @param string $drupal
* @param string $fedora
*
* @throws \Exception
*
* @return bool True if new record is created.
*/
public function saveUrls(
$uuid,
$drupal,
$fedora
);

/**
* @param string $uuid
*
* @throws \Exception
*
* @return bool True if record is found and deleted.
*/
public function deleteUrls(
$uuid
);
}
Loading