feat: Add endpoint for adding new URLs

This commit is contained in:
overflowerror 2023-12-02 21:20:19 +01:00
parent 1f7932d505
commit 411491f7f5
4 changed files with 90 additions and 9 deletions

View file

@ -0,0 +1,53 @@
<?php
require_once(ROOT . "/utils/error.php");
const CANDIDATES_PER_ITERATION = 10;
const MIN_LENGTH = 3;
const MAX_LENGTH = 20;
function generate_candidate($length) {
$charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return join("",
array_map(
fn($_) => $charset[rand(0, strlen($charset) - 1)],
range(1, $length)
)
);
}
return function (array &$context) {
$url = $_POST["url"] ?? "";
if (!$url) {
setStatusCode(400);
echo json_encode(
errorResponse("URL missing", "Please provide a URL.")
);
return;
}
$repository = $context[REPOSITORIES]->urls;
$candidates = [];
for ($length = MIN_LENGTH; count($candidates) == 0 || $length > MAX_LENGTH; $length++) {
$candidates = $repository->getUnusedSlugs(
array_map(
fn($_) => generate_candidate($length),
range(1, CANDIDATES_PER_ITERATION)
)
);
}
$slug = $candidates[0];
$accessKey = sha1($url . "-" . $url . "-" . microtime() . "-" . rand());
$result = $context[REPOSITORIES]->urls->add(new URL(
$slug,
$url,
$accessKey
));
echo json_encode($result);
};

View file

@ -13,6 +13,7 @@ function fromController(string $path, string $endpoint = null) {
return function(Router $router) { return function(Router $router) {
$router->addRoute(GET, "/", fromController("/GET")); $router->addRoute(GET, "/", fromController("/GET"));
$router->addRoute(POST, "/manage", fromController("/manage/POST"));
$router->addRoute(GET, "/.*", fromController("/slug/GET")); $router->addRoute(GET, "/.*", fromController("/slug/GET"));
}; };

View file

@ -22,6 +22,40 @@ class URLs {
$entry->url, $entry->url,
$entry->accessKey, $entry->accessKey,
]); ]);
return $this->getById($this->connection->lastInsertId());
}
public function getUnusedSlugs(array $slugs) {
$placeholderList = join(",", array_map(fn($_) => "?", $slugs));
$statement = $this->connection->prepare(<<<EOF
SELECT `slug` FROM `$this->table`
WHERE `slug` IN ($placeholderList)
EOF);
$statement->execute($slugs);
$existing = $statement->fetchAll(PDO::FETCH_COLUMN, 0);
return array_values(array_diff($slugs, $existing));
}
private function entityFromRow($row) {
$url = new URL($row["slug"], $row["url"], $row["access_key"]);
$url->id = $row["id"];
$url->created = new DateTime($row["created"]);
$url->updated = new DateTime($row["updated"]);
$url->deleted = ($row["deleted"]) ? new DateTime($row["deleted"]) : null;
return $url;
}
public function getById(int $id) {
$statement = $this->connection->prepare(<<<EOF
SELECT * FROM `$this->table` WHERE `id` = ?
EOF);
$statement->execute([$id]);
return $this->entityFromRow($statement->fetch());
} }
public function getBySlug(string $slug) { public function getBySlug(string $slug) {
@ -34,14 +68,7 @@ class URLs {
if ($statement->rowCount() == 0) { if ($statement->rowCount() == 0) {
return null; return null;
} else { } else {
$row = $statement->fetch(); return $this->entityFromRow($statement->fetch());
$url = new URL($row["slug"], $row["url"], $row["access_key"]);
$url->id = $row["id"];
$url->created = new DateTime($row["created"]);
$url->updated = new DateTime($row["updated"]);
$url->deleted = ($row["deleted"]) ? new DateTime($row["deleted"]) : null;
return $url;
} }
} }
} }

View file

@ -10,7 +10,7 @@ require(__DIR__ . "/../layout/top.php");
<img class="bottle" src="/static/img/bottle.png" alt="picture of a vile with a tag 'Drnk Me'" /> <img class="bottle" src="/static/img/bottle.png" alt="picture of a vile with a tag 'Drnk Me'" />
<div class="center-panel"> <div class="center-panel">
<form action="?create" method="POST"> <form action="/manage" method="POST">
<input type="text" name="url" placeholder="<?php echo $data["url"] ?? "URL" ?>"> <input type="text" name="url" placeholder="<?php echo $data["url"] ?? "URL" ?>">
<input type="submit" value="Submit"> <input type="submit" value="Submit">
</form> </form>