changelog for 9.12.08-1
[iserv-mod-room-reservation.git] / inc / mod_roomReservationBookingsManager.inc
1 <?php
2 /**
3 * @file mod_roomReservationBookingsManager.inc
4 * Class to manage a set of bookings
5 * @author Roland Hieber (roland.hieber@wilhelm-gym.net)
6 * @date 23.11.2007
7 *
8 * Copyright © 2007 Roland Hieber
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 */
28
29 require_once("sec/secure.inc");
30 require_once("functions.inc");
31 require_once("mod_room-reservation/mod_roomReservationConfig.inc");
32 require_once("mod_room-reservation/mod_roomReservationBooking.inc");
33 require_once("format.inc");
34
35 db_query("SET DATESTYLE = ISO;");
36
37 /**
38 * Management of a set of bookings
39 * @todo finish, document
40 */
41 class mod_roomReservationBookingsManager {
42
43 /** (mod_roomReservationConfig) Reference to the configuration object */
44 protected $oCfg;
45
46 /***************************************************************************/
47 /**
48 * @name Constructor
49 * @{
50 * Constructor.
51 * @param $oCfg (mod_roomReservationConfig) Reference to the configuration
52 * @return mod_roomReservationBookingsManager
53 */
54 function __construct(mod_roomReservationConfig &$oCfg) {
55 $this->oCfg = $oCfg;
56 }
57
58 /***************************************************************************/
59 /**
60 * @}
61 * @name Retrieving bookings
62 * @{
63 */
64
65 /**
66 * Fetch a booking with the given unique ID from the SQL table
67 * @param $nUid (int) Unique ID of the booking
68 * @return mod_roomReservationBooking
69 */
70 public static function getBookingByUid($nUid) {
71 $h = db_query("SELECT * FROM mod_roomreservation_bookings WHERE rrb_uid = $1;", $nUid);
72 $a = pg_fetch_array($h);
73 $o = new mod_roomReservationBooking($a["rrb_room"], strtotime($a["rrb_date"]),
74 intval($a["rrb_tsfirst"]), intval($a["rrb_tslast"]), $a["rrb_act"],
75 $a["rrb_reason"], intval($a["rrb_interval"]));
76 $o->setUid(intval($a["rrb_uid"]));
77 return $o;
78 }
79
80 /**
81 * Test if there is a booking which takes place on the specified position at
82 * the specified date.
83 * @param $strRoom (string) Name of the room
84 * @param $tsDate (timestamp) The date
85 * @param $nTimeslice (int) The number of the timeslice
86 * @return mod_roomReservationBooking The booking which takes place on the
87 * specified time or <tt>null</tt> if no booking could be found.
88 */
89 public static function getBookingByTimeslice($strRoom, $tsDate,
90 $nTimeslice) {
91 $a = mod_roomReservationBookingsManager::getOverlappingBookings(
92 new mod_roomReservationBooking($strRoom, $tsDate, $nTimeslice,
93 $nTimeslice, null, null));
94 return isset($a[0]) ? $a[0] : null;
95 }
96
97 /**
98 * Get all bookings in database which overlap with the given booking.
99 * @param $ob (mod_roomReservationBooking) New booking that should be tested
100 * if it overlaps
101 * @param $bUnblocks (bool) If true, consider $ob as a unblock of a specific
102 * booking. In this case, you have to specify the Unique ID of the original
103 * booking in $ob->
104 * @return array with elements of type mod_roomReservationBooking
105 */
106 public static function getOverlappingBookings(
107 mod_roomReservationBooking $ob, $bUnblocks = false) {
108 // TODO: Test for bookings that only take place every n.th week (modulo n)
109
110 // Two bookings overlap, when they are on the same day and if
111 // old beginning < new ending AND old ending > new beginning
112 $hQuery = db_query("SELECT * FROM mod_roomreservation_bookings WHERE ".
113 "rrb_room = $1 AND ((rrb_interval > 0 AND EXTRACT(DOW FROM rrb_date) ".
114 "= $2) OR (rrb_interval = 0 AND rrb_date = $3)) AND rrb_tsfirst <= ".
115 "$4 AND rrb_tslast >= $5 ORDER BY rrb_tsfirst;", $ob->getRoom(),
116 date("w", $ob->getDate()), date("Y-m-d", $ob->getDate()),
117 intval($ob->getTsLast()), intval($ob->getTsFirst()));
118 $aoReturn = array();
119 while($aResult = pg_fetch_array($hQuery)) {
120 $aoReturn[] = mod_roomReservationBookingsManager::getBookingByUid(
121 $aResult["rrb_uid"]);
122 }
123 return $aoReturn;
124 }
125
126 /***************************************************************************/
127 /**
128 * @}
129 * @name Management of bookings
130 * @{
131 */
132
133 /**
134 * Insert or update a booking in the database.
135 * The function throws an AccessException if the user was not allowed to
136 * write the booking, or an SQLException if there was an error while trying
137 * to insert or update the booking into the database.
138 * @param $ob (mod_roomReservationBooking) Booking to write to the database
139 * @return (int) The UID of the written booking
140 * @throws SQLException, AccessException
141 */
142 function write(mod_roomReservationBooking $ob) {
143 // protect access
144 if(($ob->getUid() != null and !$this->oCfg->userIsAdmin() and
145 !$this->userIsOwner($ob->nUid)) or
146 ($ob->getUid() == null and !$this->oCfg->userCanBook())) {
147 throw new AccessException(MOD_ROOM_RESERVATION_ERROR_ACCESS_DENIED);
148 }
149
150 // test if room is whitelisted
151 if(!$this->oCfg->isRoomWhitelisted($ob->getRoom())) {
152 throw new Exception(MOD_ROOM_RESERVATION_ERROR_ROOM_NOT_WHITELISTED);
153 }
154
155 $strWhere = null;
156 $strLog = "";
157
158 // check if everything is right and throw exceptions
159 if(trim($ob->getAct()) == "") {
160 $ob->setAct($SESSION["act"]);
161 } elseif(!isAct($ob->getAct())) {
162 throw new Exception(MOD_ROOM_RESERVATION_ERROR_NO_SUCH_ACCOUNT);
163 return false;
164 }
165 if($ob->getTsFirst() > $ob->getTsLast()) {
166 throw new SQLException(MOD_ROOM_RESERVATION_ERROR_END_BEFORE_BEGIN);
167 return false;
168 }
169 if(trim($ob->getReason()) == "") {
170 throw new SQLException(MOD_ROOM_RESERVATION_ERROR_NO_REASON);
171 return false;
172 }
173
174 // Test for overlapping bookings
175 if($this->getOverlappingBookings($ob) != array()) {
176 throw new SQLException(MOD_ROOM_RESERVATION_ERROR_BOOKING_OVERLAPS);
177 return false;
178 }
179
180 // Show real times in log, but don't use the user's locale!
181 $oTsB = $this->oCfg->getTimesliceBeginnings(false);
182 $oTsE = $this->oCfg->getTimesliceEndings(false);
183
184 // Update or insert?
185 if($ob->getUid() == null) {
186 // No UID yet, insert new booking
187 // @todo write interval and user if interval > 0
188 $strLog = sprintf("Raum „%s“ am %s von %s bis %s gebucht ".
189 "(Begründung: %s)", $ob->getRoom(), date("d\.m\.Y", $ob->getDate()),
190 gmdate("G:i", $oTsB[$ob->getTsFirst()]), gmdate("G:i",
191 $oTsE[$ob->getTsLast()]), $ob->getReason());
192 } else {
193 // Update an existing booking
194 // @todo write old and new times into log
195 $strWhere = "rs_uid = ".qdb(intval($ob->getUid()));
196 $strLog = sprintf("Buchung im Raum „%s“ auf %s von %s bis %s ".
197 "geändert (Begründung: „%s“)", $ob->getRoom(), date("d\.m\.Y",
198 $ob->getDate()), gmdate("G:i", $oTsB[$ob->getTsFirst()]), gmdate("G:i",
199 $oTsE[$ob->getTsLast()]), $ob->getReason());
200 }
201 $aPut["rrb_room"] = $ob->getRoom();
202 $aPut["rrb_date"] = date("Y\-m\-d", $ob->getDate());
203 $aPut["rrb_tsfirst"] = intval($ob->getTsFirst());
204 $aPut["rrb_tslast"] = intval($ob->getTsLast());
205 $aPut["rrb_act"] = $ob->getAct();
206 $aPut["rrb_reason"] = $ob->getReason();
207 $aPut["rrb_interval"] = intval($ob->getInterval());
208
209 // @todo test if the foreign keys are being violated and throw an error
210 // message if neccessary
211 db_store("mod_roomreservation_bookings", $aPut, $strWhere);
212
213 $hQuery = db_query("SELECT currval('mod_roomreservation_bookings_rrb_uid_seq');");
214 $nNewUid = pg_fetch_result($hQuery, 0, "currval");
215
216 rrInsertLog($strLog);
217
218 // Return new UID
219 return $nNewUid;
220 }
221
222 /**
223 * Delete a booking from the database
224 * @param $nUid (int) Unique ID of the booking
225 * @return (bool) <tt>true</tt> on success, otherwise <tt>false</tt>.
226 */
227 public function delete($nUid) {
228 // Only administrators and owners are allowed to delete bookings
229 if(!($this->oCfg->userIsAdmin() or $this->userIsOwner($nUid))) {
230 throw new AccessException(MOD_ROOM_RESERVATION_ERROR_ACCESS_DENIED);
231 return false;
232 }
233
234 // Don't use the user's locale!
235 $oTsB = $this->oCfg->getTimesliceBeginnings(false);
236 $oTsE = $this->oCfg->getTimesliceEndings(false);
237 $ob = $this->getBookingByUid($nUid);
238 $strLog = sprintf("Buchung in Raum „%s“ am %s von %s bis %s ".
239 "gelöscht (Begründung war: %s)", $ob->getRoom(), date("d\.m\.Y",
240 $ob->getDate()), gmdate("G:i", $oTsB[$ob->getTsFirst()]), gmdate("G:i",
241 $oTsE[$ob->getTsLast()]), $ob->getReason());
242 // Delete it from the database
243 if(!db_query("DELETE FROM mod_roomreservation_bookings WHERE ".
244 "rrb_uid = $1;", $nUid)) {
245 throw new SQLException(MOD_ROOM_RESERVATION_ERROR_SQL);
246 return false;
247 } else {
248 rrInsertLog($strLog);
249 return true;
250 }
251 }
252
253 /**
254 * Unblocks a booking for a specific time. Useful to release a room for a
255 * specific time if it has been blocked by a recurring booking
256 * @param $nUid Unique ID of the booking to be unblocked
257 * @param $tsStart The timestamp when the unblock starts
258 * @param $tsEnd The timestamp when the unblock ends
259 * @return bool
260 * @todo implement this
261 */
262 function unblock($nUid, $tsStart, $tsEnd) {
263 // unblocking only allowed to owners and admins
264 if(!$this->userIsOwner($nUid) || !$this->cfg->userIsAdmin()) {
265 throw new AccessException(MOD_ROOM_RESERVATION_ERROR_ACCESS_DENIED);
266 }
267 return false;
268 }
269
270 /**
271 * Re-blocks a booking that has been unblocked by unblock().
272 * @param $nUid Unique ID of the booking to be unblocked
273 * @return bool
274 * @todo implement this
275 */
276 function reblock($nUid, $tsStart, $tsEnd) {
277 // re-blocking only allowed to owners and admins
278 if(!$this->userIsOwner($nUid) || !$this->cfg->userIsAdmin()) {
279 throw new AccessException(MOD_ROOM_RESERVATION_ERROR_ACCESS_DENIED);
280 }
281 return false;
282 }
283
284 /**
285 * Determine if the current user is the owner of a specified error report.
286 * If this function fails, call getLastError() to get more information.
287 * @param $nID (int) Unique ID of the error report
288 * @throws SQLException
289 * @return bool
290 */
291 public static function userIsOwner($nID) {
292 if(!isset($_SESSION["act"])) {
293 return false; // user is not logged in
294 } else {
295 $hQuery = db_query("SELECT rrb_act FROM mod_roomreservation_bookings WHERE ".
296 "rrb_uid = $1;", intval($nID));
297 if(!is_resource($hQuery)) {
298 throw new SQLException(MOD_ROOM_RESERVATION_ERROR_SQL);
299 return false;
300 }
301 $arResult = pg_fetch_array($hQuery);
302 return ($arResult["rrb_act"] == $_SESSION["act"]);
303 }
304 }
305 }
306 ?>
This page took 0.054201 seconds and 5 git commands to generate.