From f180a9bd59def3bfe44b91c6c34917e338bb4906 Mon Sep 17 00:00:00 2001 From: Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de> Date: Mon, 8 Nov 2021 17:43:05 +0100 Subject: [PATCH] fix checks for overlapping bookings, fixes #251 --- app/controllers/course/room_requests.php | 5 +- app/controllers/resources/export.php | 6 +-- app/controllers/resources/statistics.php | 4 +- app/controllers/room_management/planning.php | 6 +-- .../resources/ResourceBooking.class.php | 37 +++---------- .../resources/ResourceRequest.class.php | 44 ++++----------- lib/resources/RoomManager.class.php | 54 ++----------------- 7 files changed, 23 insertions(+), 133 deletions(-) diff --git a/app/controllers/course/room_requests.php b/app/controllers/course/room_requests.php index 100dad5cdb3..8747e9b4ab5 100644 --- a/app/controllers/course/room_requests.php +++ b/app/controllers/course/room_requests.php @@ -630,10 +630,7 @@ class Course_RoomRequestsController extends AuthenticatedController $request_dates_booked = 0; foreach ($request_time_intervals as $interval) { $booked = ResourceBookingInterval::countBySql( - 'resource_id = :room_id - AND - (begin BETWEEN :begin AND :end - OR end BETWEEN :begin AND :end)', + 'resource_id = :room_id AND begin < :end AND end > :begin', [ 'room_id' => $room->id, 'begin' => $interval['begin'], diff --git a/app/controllers/resources/export.php b/app/controllers/resources/export.php index 87d6d8a0df0..299cd3a706d 100644 --- a/app/controllers/resources/export.php +++ b/app/controllers/resources/export.php @@ -325,11 +325,7 @@ class Resources_ExportController extends AuthenticatedController foreach ($resources as $resource) { //Retrieve the bookings in the specified time range: $intervals = ResourceBookingInterval::findBySql( - '`resource_id` = :resource_id - AND - (`begin` BETWEEN :begin AND :end - OR `end` BETWEEN :begin AND :end) - ORDER BY `begin` ASC, `end` ASC', + 'resource_id = :resource_id AND begin < :end AND end > :begin ORDER BY begin, end', [ 'resource_id' => $resource->id, 'begin' => $this->begin->getTimestamp(), diff --git a/app/controllers/resources/statistics.php b/app/controllers/resources/statistics.php index 5c8b1744085..6ae55e11d2d 100644 --- a/app/controllers/resources/statistics.php +++ b/app/controllers/resources/statistics.php @@ -55,9 +55,7 @@ class Resources_StatisticsController extends AuthenticatedController WHERE rb.booking_type IN ( :types ) AND - (rbi.begin BETWEEN :begin AND :end) - OR - (rbi.end BETWEEN :begin AND :end);" + rbi.begin < :end AND rbi.end > :begin" ); $sum_stmt->execute( diff --git a/app/controllers/room_management/planning.php b/app/controllers/room_management/planning.php index ecfba9ee74e..06a460b00b4 100644 --- a/app/controllers/room_management/planning.php +++ b/app/controllers/room_management/planning.php @@ -1197,11 +1197,7 @@ class RoomManagement_PlanningController extends AuthenticatedController ON resource_booking_intervals.booking_id = rb.id WHERE rb.internal_comment <> '' AND rb.resource_id IN ( :room_ids ) - AND ( - resource_booking_intervals.begin BETWEEN :begin AND :end - OR - resource_booking_intervals.end BETWEEN :begin AND :end - ) + AND resource_booking_intervals.begin < :end AND resource_booking_intervals.end > :begin ORDER BY resource_booking_intervals.begin ASC, resource_booking_intervals.end ASC", [ 'room_ids' => $this->room_ids, diff --git a/lib/models/resources/ResourceBooking.class.php b/lib/models/resources/ResourceBooking.class.php index e12ce922d95..4534afc35b0 100644 --- a/lib/models/resources/ResourceBooking.class.php +++ b/lib/models/resources/ResourceBooking.class.php @@ -730,8 +730,7 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen if ($derived_resource->userHasPermission($this->booking_user, 'tutor', [$current_begin, $current_end])) { //Sufficient permissions to delete bookings //in the time frame. - $delete_sql = 'begin < :end AND end > :begin - AND resource_id = :resource_id '; + $delete_sql = 'begin < :end AND end > :begin AND resource_id = :resource_id '; $sql_params = [ 'begin' => $current_begin->getTimestamp(), 'end' => $current_end->getTimestamp(), @@ -763,8 +762,7 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen } else { $derived_resource = $this->resource->getDerivedClassInstance(); if ($derived_resource->userHasPermission($this->booking_user, 'autor', [$real_begin, $end])) { - $delete_sql = 'begin < :end AND end > :begin - AND resource_id = :resource_id '; + $delete_sql = 'begin < :end AND end > :begin AND resource_id = :resource_id '; $sql_params = [ 'begin' => $real_begin->getTimestamp(), 'end' => $end->getTimestamp(), @@ -959,27 +957,11 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen public function isRepetitionInTimeframe(DateTime $begin, DateTime $end) { return ResourceBookingInterval::countBySql( - "booking_id = :booking_id - AND ( - (begin BETWEEN :begin AND :end) - OR - (end BETWEEN :begin AND :end) - OR - (begin < :begin AND end > :end) - ) - AND NOT ( - (begin BETWEEN :booking_begin AND :booking_end) - OR - (end BETWEEN :booking_begin AND :booking_end) - OR - (begin < :booking_begin AND end > :booking_end) - )", + 'booking_id = :booking_id AND begin < :end AND end > :begin', [ 'booking_id' => $this->id, 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp(), - 'booking_begin' => $this->begin, - 'booking_end' => $this->end + 'end' => $end->getTimestamp() ] ) > 0; } @@ -1313,14 +1295,7 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen } return ResourceBookingInterval::findBySql( - 'booking_id = :booking_id - AND - ( - (begin >= :begin AND begin <= :end) - OR - (end >= :begin AND end <= :end) - ) - ORDER BY begin ASC, end ASC', + 'booking_id = :booking_id AND begin < :end AND end > :begin ORDER BY begin, end', [ 'booking_id' => $this->id, 'begin' => $begin->getTimestamp(), @@ -1798,7 +1773,7 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen if ($end instanceof DateTime) { $end = $end->getTimestamp(); } - $sql .= "AND begin <= :end AND :begin <= end"; + $sql .= "AND begin < :end AND :begin < end"; $sql_array['begin'] = $begin; $sql_array['end'] = $end; } diff --git a/lib/models/resources/ResourceRequest.class.php b/lib/models/resources/ResourceRequest.class.php index 9782b59636a..9ac498342b3 100644 --- a/lib/models/resources/ResourceRequest.class.php +++ b/lib/models/resources/ResourceRequest.class.php @@ -247,18 +247,9 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen //Now we build the SQL snippet for the time intervals. //These are repeated four times in the query below. - //First we use one template ($time_sql_template) and - //replace NUMBER with our counting variable $i. //BEGIN and END are replaced below since the columns for //BEGIN and END are different in the four cases where we //repeat the SQL snippet for the time intervals. - $time_sql_template = '( - BEGIN BETWEEN :beginNUMBER AND :endNUMBER - OR - END BETWEEN :beginNUMBER AND :endNUMBER - OR - BEGIN <= :beginNUMBER AND END >= :endNUMBER - ) '; $time_sql = ''; if ($time_ranges) { @@ -269,11 +260,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen if ($i > 1) { $time_sql .= ' OR '; } - $time_sql .= str_replace( - 'NUMBER', - $i, - $time_sql_template - ); + $time_sql .= sprintf('BEGIN < :end%d AND END > :begin%d ', $i, $i); $sql_params[('begin' . $i)] = $time_range['begin']; $sql_params[('end' . $i)] = $time_range['end']; @@ -288,6 +275,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen //to a date, a metadate or a course. //This is done in the rest of the SQL query: + // FIXME this subselect looks unnecessarily complex $whole_sql = 'resource_requests.id IN ( SELECT id FROM resource_requests WHERE @@ -298,11 +286,8 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ['(CAST(begin AS SIGNED) - preparation_time)', 'end'], $time_sql ) - . ( - $closed_status_sql - ? $closed_status_sql - : '' - ) . ' + . $closed_status_sql + . ' UNION SELECT id FROM resource_requests INNER JOIN termine USING (termin_id) @@ -317,11 +302,8 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ], $time_sql ) - . ( - $closed_status_sql - ? $closed_status_sql - : '' - ) . ' + . $closed_status_sql + . ' UNION SELECT id FROM resource_requests INNER JOIN termine USING (metadate_id) @@ -336,11 +318,8 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ], $time_sql ) - . ( - $closed_status_sql - ? $closed_status_sql - : '' - ) . ' + . $closed_status_sql + . ' UNION SELECT id FROM resource_requests INNER JOIN termine @@ -356,11 +335,8 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen ], $time_sql ) - . ( - $closed_status_sql - ? $closed_status_sql - : '' - ) . ' + . $closed_status_sql + . ' GROUP BY id ) ' . $excluded_request_ids_sql; diff --git a/lib/resources/RoomManager.class.php b/lib/resources/RoomManager.class.php index 0932d453cee..f1a71a82353 100644 --- a/lib/resources/RoomManager.class.php +++ b/lib/resources/RoomManager.class.php @@ -408,20 +408,7 @@ class RoomManager //Build the SQL query and the SQL parameters: $sql = "INNER JOIN resource_bookings ON resource_booking_intervals.booking_id = resource_bookings.id - WHERE - ( - ( - resource_booking_intervals.begin >= :begin - AND - resource_booking_intervals.begin <= :end - ) - OR - ( - resource_booking_intervals.end >= :begin - AND - resource_booking_intervals.end <= :end - ) - ) "; + WHERE resource_booking_intervals.begin < :end AND resource_booking_intervals.end > :begin "; $sql_array = [ 'begin' => $begin->getTimestamp(), 'end' => $end->getTimestamp(), @@ -746,44 +733,9 @@ class RoomManager INNER JOIN resource_property_definitions rpd ON resource_properties.property_id = rpd.property_id WHERE TRUE" - /* - INNER JOIN seminare - ON resource_bookings.range_id = seminare.seminar_id - WHERE - TRUE" - /* - (resource_categories.class_name = 'Room' OR TRUE) - AND - ( - ( - resource_bookings.begin >= :begin - AND - resource_bookings.repeat_end <= :end - ) - OR - ( - resource_bookings.begin >= :begin - AND - resource_bookings.end <= :end - ) - OR TRUE - ) - AND - (rpd.name = 'seats' OR TRUE) - AND - (resource_properties.state < ( - SELECT COUNT(user_id) FROM seminar_user - WHERE seminar_user.seminar_id = seminare.seminar_id - ) OR TRUE) ORDER BY name ASC", - [ - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp() - ] - */ ); return $found_bookings; - //SimpleORMapCollection::createFromArray($found_bookings); } @@ -1011,8 +963,8 @@ class RoomManager if ($i > 1) { $sql .= 'AND '; } - $sql .= "(rbi.`begin` NOT BETWEEN :begin$i AND :end$i - AND rbi.`end` NOT BETWEEN :begin$i AND :end$i)"; + // FIXME this checks looks bogus to me + $sql .= "(rbi.begin >= :end$i OR rbi.end <= :begin$i)"; $sql_params["begin$i"] = $begin; $sql_params["end$i"] = $end; -- GitLab