api/
ved/
admin/
modules/
gyar/
admin/
cron/
api/ved/bookings.php1 lines
<?php
# bookings.php
# API endpoint
# Fil för att läsa av, lägga till och ta bort bokningar.
require_once "ved/modules/utility.php";
# Hämtar alla bokningar för den specifierade dagen.
$functionGET = function () {
require "ved/modules/vedDatabase.php";
# Hämtar öppettiderna för dagen.
$params = array("date" => $_GET["date"]);
$dateData = $db->query(
"SELECT
CONVERT(ROUND(TIME_TO_SEC((CASE WHEN e.exceptionId IS NULL THEN w.openingTime ELSE e.openingTime END))/60), SIGNED) openingTimeMinutes,
CONVERT(ROUND(TIME_TO_SEC((CASE WHEN e.exceptionId IS NULL THEN w.closingTime ELSE e.closingTime END))/60), SIGNED) closingTimeMinutes
FROM weekdayOpenHours w
LEFT JOIN openHoursException e
ON :date >= e.date1 AND :date <= e.date2
WHERE w.weekdayId = WEEKDAY(:date)",
$params
);
# Hämtar bokningarna.
$bookings = $db->queryAll(
"SELECT *, ROUND(TIME_TO_SEC(b.datetime)/60) timeMinutes FROM booking b WHERE datetime BETWEEN :date AND ADDDATE(:date, 1) AND NOT removed;",
$params
);
$data = $dateData;
$data["bookings"] = $bookings;
return $data;
};
# Funktion som kontrollerar POST-metodens parametrar.
# Formatterar även några parametrar som returnas i slutet.
function check_request_POST()
{
# Kontrollera namnet.
$nameLength = strlen($_POST["name"]);
if ($nameLength == 0 || $nameLength > 32)
throw new APIParameterError(400, "name", "Length must be between 1 and 32 characters.");
# Kontrollera telefonnumret.
$cleanPhoneNumber = preg_replace("/[-\s]+/", "", $_POST["phoneNumber"]);
if (!preg_match("/^[0-9]{9,10}$/", $cleanPhoneNumber))
throw new APIParameterError(400, "phoneNumber", "Invalid format.");
$_POST["phoneNumber"] = $cleanPhoneNumber;
# Kontrollerar antalet personer.
if (!is_int($_POST["adultCount"]) || $_POST["adultCount"] < 0)
throw new APIParameterError(400, "adultCount", "Parameter must be a positive integer.");
if (!is_int(value: $_POST["childCount"]) || $_POST["childCount"] < 0)
throw new APIParameterError(400, "childCount", "Parameter must be a positive integer.");
if ($_POST["adultCount"] + $_POST["childCount"] <= 0)
throw new APIParameterError(400, array("adultCount", "childCount"), "Both parameters cannot be 0.");
# Kontrollerar datumet.
try {
$date = new DateTime($_POST["datetime"]);
} catch (DateMalformedStringException) {
throw new APIParameterError(400, "datetime", "Invalid date.");
}
$tomorrow = new DateTime();
$tomorrow->setTime(0, 0);
$tomorrow->add(new DateInterval("P1D"));
$diff = $tomorrow->diff($date);
if ($diff->invert)
throw new APIParameterError(400, "datetime", "Booking cannot be placed earlier than tomorrow.");
return array("date" => $date, "cleanPhoneNumber" => $cleanPhoneNumber);
}
# Lägger till en bokning i systemet.
$functionPOST = function () {
$formatted = check_request_POST();
$date = $formatted["date"];
$phoneNumber = $formatted["cleanPhoneNumber"];
require_once "ved/modules/vedDatabase.php";
# Hämtar öppettiderna för dagen.
$dateString = $date->format("Y-m-d");
$dateData = $db->query(
"SELECT
ROUND(TIME_TO_SEC((CASE WHEN e.exceptionId IS NULL THEN w.openingTime ELSE e.openingTime END))/60) openingTimeMinutes,
ROUND(TIME_TO_SEC(TIMEDIFF((CASE WHEN e.exceptionId IS NULL THEN w.closingTime ELSE e.closingTime END), (CASE WHEN e.exceptionId IS NULL THEN w.openingTime ELSE e.openingTime END)))/60) AS minutesOpen
FROM weekdayOpenHours w
LEFT JOIN openHoursException e
ON :date >= e.date1 AND :date <= e.date2
WHERE w.weekdayId = WEEKDAY(:date)",
array("date" => $dateString)
);
# Kollar om dagen är öppen.
if (!isset($dateData["minutesOpen"]))
throw new APIParameterError(400, "datetime", "Restaurant is closed at the specified date.");
# Här kontrolleras att bokningen passar in i tidsramarna, och att det inte är fullbokat.
$bookings = $db->queryAll(
"SELECT ROUND(TIME_TO_SEC(b.datetime)/60) timeMinutes, b.adultCount + b.childCount peopleCount FROM booking b WHERE datetime BETWEEN :date AND ADDDATE(:date, 1) AND NOT removed;",
array("date" => $dateString)
);
$settings = $db->query("SELECT seatCount, bookingInterval, bookingLength FROM restaurantSettings;");
# Delar upp dagen i tidsramar. Varje tidsram lagrar antalet platser som används.
$timeframes = create_time_frames($dateData, $bookings, $settings);
# Kollar framåt för varje tidsram och beräknar max hur många platser finns tillgängliga en hel bokningslängd framåt.
$bookableFrames = create_bookable_time_frames($dateData, $timeframes, $settings);
$timeString = $date->format("H:i");
if (!isset($bookableFrames[$timeString])) # Kollar ifall den passar in.
throw new APIParameterError(400, "datetime", "The specified time does not fit into the bookings list.");
if ($bookableFrames[$timeString] < $_POST["adultCount"] + $_POST["childCount"]) # Kollar ifall det inte är fullbokat.
throw new APIError(409, "The restaurant is fully booked at the specified time.");
# Lägger till en bokning.
$_POST["phoneNumber"] = $phoneNumber;
$db->query("INSERT INTO booking(name, phoneNumber, adultCount, childCount, datetime, bookedAt) VALUES (:name, :phoneNumber, :adultCount, :childCount, :datetime, NOW())", $_POST);
http_response_code(201);
$data = array("message" => "Your booking was successful.");
return $data;
};
# Tar bort en bokning. Bokningen tas inte faktiskt bort, utan removed-flaggan sätts till 1.
$functionDELETE = function () {
require "ved/modules/vedDatabase.php";
$db->query("UPDATE booking SET removed=1 WHERE bookingId=:bookingId;", array("bookingId" => $_POST["bookingId"]));
$data = array("message" => "Booking was successfully removed.");
return $data;
};
$api = new APIEndpoint();
$auth = require_once "ved/admin/authorization.php";
$httpGET = new APIMethod("GET", $functionGET);
$httpGET->setAuthorization($auth);
$httpGET->setRequiredGETParameters(array("date"));
$api->addMethod($httpGET);
$httpPOST = new APIMethod("POST", $functionPOST);
$httpPOST->setRequiredBodyParameters(array("datetime", "name", "phoneNumber", "adultCount", "childCount"));
$api->addMethod($httpPOST);
$httpDELETE = new APIMethod("DELETE", $functionDELETE);
$httpDELETE->setAuthorization($auth);
$httpDELETE->setRequiredBodyParameters(array("bookingId"));
$api->addMethod($httpDELETE);
return $api;
?>