Location: PHPKode > projects > ConPortal > conportal/inc/shifts/db.php
<?php
/*
 *  ConPortal - Pomona College ITS scheduling appplication
 *  Copyright (C) 2005-2008  Pomona College & Bucknell University
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of version 2 of the GNU General Public License
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/*
 * Functions in this file:
 *   cancel_shift
 *   checkShiftCovered
 *   checkShiftsOverlap
 *   checkShowShiftDropButton
 *   checkShowShiftTakeButton
 *   checkUserCanDropShift
 *   checkUserCanTakeShift
 *   createShift
 *   copyShifts
 *   getAllShiftDetails
 *   getPositionDetails
 *   getPositions
 *   getShiftDetails
 *   getShiftDetailsForArray
 *   getShiftDetailsHumanReadable
 *   getShiftForTimeAndPosition
 *   getShifts
 *   getShiftsForDateRangeAndUser
 *   getShiftsForDayAndPosition
 *   getShiftsForDayAndUser
 *   getShiftsForShiftTable
 *   getShiftsForTime
 *   getShiftsForUser
 *   getShiftsForUserIncludingDropped
 *   getShiftStaffingStatus
 *   internalCancelSplit
 *   internalDropShift
 *   internalPermSplit
 *   internalShiftSplit
 *   internalTakeShift
 *   internalTempSplit
 *   isShiftTimeValid
 *   perm_drop_shift
 *   perm_take_shift
 *   temp_drop_shift
 *   temp_take_shift
 *   removeShift
 *   xlate_shiftdate
 */

// Cancel the given shift on the given day.
function cancel_shift ($shiftPid, $timestamp)
{
    // No need to check whether user can drop this shift, since this function
    // is only called from a "priveleged" page
    
    // Perform the database mechanics
	start_transaction();
    internalCancelSplit($shiftPid, $timestamp);
	commit_transaction();
}

function checkShiftCovered ($shiftPid)
{
    $data = getShiftDetails($shiftPid);
    return (isset($data['owner']) && $data['owner'] != 0);
}

/*
 * Check if any shifts overlap with the (potential) shift specified
 * by the startDate through positionPid parameters.
 * Returns one of the following:
 *   - NULL if no shifts overlap
 *   - an array of the PIDs of overlapping shifts if any were found.
 *
 * If $shiftPid is set (i.e. not NULL), then that PID is specifically _excluded_
 * from the check. So, if we are checking for overlapping shifts on a shift
 * that is already in the database, set $shiftPid to that shifts' PID and we won't
 * think that it's overlapping itself!
 *
 * A shift is defined as 'overlapping' if it occurs on the same date and
 * shift 2 starts before shift 1 ends and shift 2 ends after shift 1 starts
 */



function checkShiftsOverlap ($shiftPid, $startDate, $endDate, $startTime, $endTime, $dow, $positionPid)
{
	$query = sprintf("select pid from shifts where " .
		"day_of_week = '%s' and " .
		"position = %d and " .
		"start_date <= FROM_UNIXTIME(%d) and end_date >= FROM_UNIXTIME(%d) and " .
		"TIME_TO_SEC(start_time) < %d and TIME_TO_SEC(end_time) > %d",
		mysql_real_escape_string($dow),
		$positionPid,
		$endDate, $startDate,
		time_part($endTime), time_part($startTime));
	if ($shiftPid)
		$query .= " and pid != " . intval($shiftPid);
	$result = safeQuery($query);
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		//if ($row['pid'] != $shiftPid)
			$a[] = $row['pid'];
	return $a;
}

/*
 * Sam made this function to allow us to check to see if this person 
 * is working elsewhere at the same time. (Elsewhere means in another
 * "position")
 */

function checkShiftsOverlapAnyPosition ($shiftPid, $startDate, $endDate, $startTime, $endTime, $dow)
{
	$query = sprintf("select pid from shifts where " .
		"day_of_week = '%s' and " .
		"start_date <= FROM_UNIXTIME(%d) and end_date >= FROM_UNIXTIME(%d) and " .
		"TIME_TO_SEC(start_time) < %d and TIME_TO_SEC(end_time) > %d",
		mysql_real_escape_string($dow),
		$endDate, $startDate,
		time_part($endTime), time_part($startTime));
	if ($shiftPid)
		$query .= " and pid != " . intval($shiftPid);
	$result = safeQuery($query);
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		//if ($row['pid'] != $shiftPid)
			$a[] = $row['pid'];
	return $a;
}
/*
 * Determine whether to show a shift-drop button for this shift.
 */
function checkShowShiftDropButton ($shiftPid, $timestamp)
{
	if (checkPerm($_SESSION, "shifts"))
		return isShiftTimeValid($shiftPid, $timestamp);

	return checkUserCanDropShift($_SESSION['pid'], $shiftPid, $timestamp);
}

/*
 * Determine whether to show a shift-take button for this shift.
 */
function checkShowShiftTakeButton ($shiftPid, $timestamp)
{
	if (checkPerm($_SESSION, "shifts"))
		return isShiftTimeValid($shiftPid, $timestamp);
	
	return checkUserCanTakeShift($_SESSION['pid'], $shiftPid, $timestamp);
}

function checkUserCanDropShift ($userPid, $shiftPid, $timestamp)
{
	$shift = getShiftDetails($shiftPid);
	
	// Shift timestamp sanity checks
	if (!isShiftTimeValid($shiftPid, $timestamp))
		return false;
		
	// Allow users with "shifts" permission to short-circuit the remaining checks
	if (checkPerm($_SESSION, "shifts"))
		return true;

	// Check that the user owns this shift
	if (!isset($shift['owner']) or $shift['owner'] != $userPid)
		return false;
	
	return true;
}

/*
 * Run a number of tests to determine whether the user is allowed to 
 * take the specified shift (on the specified day).
 */
function checkUserCanTakeShift ($userPid, $shiftPid, $timestamp)
{
	
	$shift = getShiftDetails($shiftPid);

    // If the shift is already taken, then this person can't take it
    if (isset($shift['owner']))
        return false;
	
	// Ensure this timestamp really falls within the shift, on the
	// right day of the week, etc (basic sanity checks)
    if (!isShiftTimeValid($shiftPid, $timestamp))
        return false;


	//added by George and modified by sam to make sure people don't take the same hour twice
	if(!(notAlreadyTakenTheseHours($userPid, $shiftPid)))
		return false;

		
	// Allow users with "shifts" permission to short-circuit the remaining checks
	if (checkPerm($_SESSION, "shifts"))
		return true;
	
	// Determine if the user who is being staffed has enough time to take this shift
    if (!drawCheckRemainingTime($userPid, $shiftPid, $timestamp))
		return false;
	 
	// If there are no restrictions on the position of this shift (signaled
	// by there being no entries in position_group for it), then any users can take it
    $position_groups = getGroupsForPosition($shift['position']);
	if (count($position_groups) == 0)
		return true;

	// Otherwise, check that the user is in one of the position groups
    $user_groups = getGroupsForUser($_SESSION['pid']);
    $user_groups[] = getPrimaryGroupForUser($userPid);
    return count(array_intersect($user_groups, $position_groups)) > 0; 
}

/*
 * Creates a new shift. The start and end dates are inherited from the
 * specified shiftgroup if $startDate and $endDate are NULL.
 *
 * Returns NULL on error or the PID of the newly created shift otherwise.
 * owner, dropper, time_taken, and time_dropped are all left as NULL.
 *
 * Since overlapping shifts are a big NO-NO, this function does include
 * checking to ensure that the newly created shift does not overlap with any
 * other shift (based on (start|end)_date, (start|end)_time, $dow, and
 * $position).
 */
function createShift ($shiftgroupPid, $dow, $positionPid, $startTime, $endTime,
	$startDate = NULL, $endDate = NULL)
{
    // get the shiftgroup information
    $shiftgroup = getShiftgroupDetails($shiftgroupPid);
    if (!$shiftgroup)
	{
		error("Unknown shift group '$shiftgroupPid'");
        return NULL;
    }

	if (!$startDate)
	    $startDate = $shiftgroup['start_date'];
	if (!$endDate)
	    $endDate   = $shiftgroup['end_date'];

    // Check for overlapping shifts like we promised in the function desc...
    $overlapping = checkShiftsOverlap(NULL, $startDate, $endDate,
                                      $startTime, $endTime, $dow,
                                      $positionPid);
	if ($overlapping)
	{
        // non-NULL indicates that we found some overlapping shifts :-(
		error("Found some overlapping shifts: " . implode(", ", $overlapping));
        return NULL;
    }

	// All clear, create the shift!
	safeQuery("insert into shifts set " .
		"shift_group = %d, " .
		"start_date = FROM_UNIXTIME(%d), " .
		"end_date = FROM_UNIXTIME(%d), " .
		"start_time = SEC_TO_TIME(%d), " .
		"end_time = SEC_TO_TIME(%d), " .
		"day_of_week = '%s', " .
		"position = %d",
		$shiftgroupPid,
		$startDate, $endDate,
		time_part($startTime), time_part($endTime),
		mysql_real_escape_string($dow),
		$positionPid);
    return mysql_insert_id();
}

/*
 * Copies the whole set of shifts from a day of the week in one shift group
 * to another day of the week in (possibly the same) shiftgroup
 *
 * Since overlapping shits are a big NO-NO, this function does include checking
 * to ensure that no shifts already existed for the shift group and day
 * being copied to... YAY!
 *
 * Ownership information *IS NOT COPIED*
 */
function copyShifts ($fromShiftgroup, $fromDOW, $toShiftgroup, $toDOW)
{
    // make sure that no shifts exist on the 'to' day
	$result = safeQuery("select pid from shifts where shift_group = %d and day_of_week = '%s'",
		$toShiftgroup, mysql_real_escape_string($toDOW));
    if (mysql_num_rows($result) > 0)
	{
		error("Error copying a whole day of shifts: there are already shifts " .
			"for shift group $toShiftgroup on $toDOW.");
        return false;
    }
	
	// get shiftgroup info
	$fromSGDetails = getShiftgroupDetails($fromShiftgroup);
	$toSGDetails = getShiftgroupDetails($toShiftgroup);

    // tell the DB to make the transfer
	// NOTE! if we're copying from a shiftgroup that has shift splits and so forth,
	// we're at risk of creating overlaps because the start/end dates are all reset
	// in the destination.  SO, only copy those shifts whose start date is identical
	// to the start date of the originating shift group.  This should extract only
	// one non-overlapping set of shifts.
	$result = safeQuery("insert into shifts select " .
		"NULL as pid, " .
		"%d as shift_group, " .
		"FROM_UNIXTIME(%d) as start_date, FROM_UNIXTIME(%d) as end_date, " . 
		"start_time, end_time, " .
		"'%s' as day_of_week, " . 
		"position, " .
		"NULL as owner, NULL as dropper, NULL as time_taken, NULL as time_dropped " .
		"from shifts where shift_group = %d and day_of_week = '%s' and start_date = FROM_UNIXTIME(%d)",
		$toShiftgroup,
		$toSGDetails["start_date"], $toSGDetails["end_date"],
		mysql_real_escape_string($toDOW),
		$fromShiftgroup,
		mysql_real_escape_string($fromDOW),
		$fromSGDetails["start_date"]);

    return true;
}

function getAllShiftDetails ()
{
	return getShiftDetailsForArray(getShifts());
}

function getPositionDetails ($pid)
{
	$result = safeQuery("select * from positions where pid = %d", $pid);
	return mysql_fetch_assoc($result);
}

/*
 * Array of pids of all positions 
 */
function getPositions ()
{
	$result = safeQuery("select pid from positions order by display_order asc");
	$array = array();
	while ($row = mysql_fetch_assoc($result))
		$array[] = $row['pid'];
	return $array;
}

/*
 * master shifts query, doing all the necessary translations of date/time values
 * all other functions should use this (or getShiftDetailsForArray, below) to
 * retrieve shift data.  NEVER, NEVER write "select * from shifts"!
 */
function getShiftDetails ($shiftPid)
{
	//added ORDER BY stuff for revision 252, 7/11/07
	$result = safeQuery("select pid, shift_group, day_of_week, position, owner, dropper, " .
		"UNIX_TIMESTAMP(start_date) as start_date, " .
		"UNIX_TIMESTAMP(end_date) as end_date, " .
		"(UNIX_TIMESTAMP(start_date) + TIME_TO_SEC(start_time)) as start_time, " .
		"(UNIX_TIMESTAMP(start_date) + TIME_TO_SEC(end_time)) as end_time, " .
		"UNIX_TIMESTAMP(time_taken) as time_taken, " .
		"UNIX_TIMESTAMP(time_dropped) as time_dropped " .
		"from shifts where pid = %d ORDER BY end_time DESC", $shiftPid);
	return mysql_fetch_assoc($result);
}

/*
 * getShiftDetailsForArray - returns details for each in an array of shift PIDs.
 */
function getShiftDetailsForArray ($array)
{
	$a = array();
	foreach ($array as $pid)
		$a[] = getShiftDetails($pid);
	return $a;
}

/*
 * Return shift details in human readable format (e.g. person's name
 * instead of user pid, date strings instead of timestamps, etc...)
 */
function getShiftDetailsHumanReadable ($shiftPid)
{
	$shiftData = getShiftDetails($shiftPid);
	if (!$shiftData)
		return NULL;

	$shiftgroup = getShiftgroupDetails($shiftData['shift_group']);
	$shiftData['shift_group'] = $shiftgroup['name'];

	list($shiftData['start_date'], $shiftData['end_date']) =
		xlate_shiftdate($shiftData['day_of_week'], $shiftData['start_date'], $shiftData['end_date'], $shiftData['pid']);
	$shiftData['start_date'] = date("n/j", $shiftData['start_date']);
	$shiftData['end_date']   = date("n/j", $shiftData['end_date']);

	$shiftData['start_time'] = date("g:i a", $shiftData['start_time']);
	$shiftData['end_time']   = date("g:i a", $shiftData['end_time']);
	
	$shiftData['day_of_week'] = ucfirst($shiftData['day_of_week']);

	$position = getPositionDetails($shiftData['position']);
	$shiftData['position'] = $position['name'];
	
	if (isset($shiftData['owner']))
		$shiftData['owner']   = getNameForUser($shiftData['owner']);
	if (isset($shiftData['dropper']))
		$shiftData['dropper'] = getNameForUser($shiftData['dropper']);
		
	if (isset($shiftData['time_taken']))
		$shiftData['time_taken']   = date("n/j g:ia", $shiftData['time_taken']);
	if (isset($shiftData['time_dropped']))
		$shiftData['time_dropped'] = date("n/j g:ia", $shiftData['time_dropped']);
	
	return $shiftData;
}

/*
 * Returns single PID of shift at a given time for a particular position
 */
function getShiftForTimeAndPosition ($timestamp, $positionPid)
{
	$result = safeQuery("select pid from shifts where " .
		"day_of_week = '%s' and position = %d and " .
		"start_date <= FROM_UNIXTIME(%d) and " .
		"end_date >= FROM_UNIXTIME(%d) and " .
		"TIME_TO_SEC(start_time) <= %d and " .
		"TIME_TO_SEC(end_time) > %d",
		strtolower(date('l', $timestamp)), $positionPid,
		$timestamp, $timestamp,
		time_part($timestamp), time_part($timestamp));
	if (mysql_num_rows($result) == 0)
		return NULL;
	$row = mysql_fetch_assoc($result);
	return $row['pid'];
}

/*
 * All shift pids
 */
function getShifts ()
{
	$result = safeQuery("select pid from shifts");
	$array = array();
	while ($row = mysql_fetch_assoc($result))
		$array[] = $row['pid'];
	return $array;
}

/*
 * Find the shifts taken by the specified user on the days between
 * start_date and end_date (inclusive).  Returns array of PIDs.
 *
 * Does not return temp-dropped shifts.
 */
//Updated by George for Revision 250 on 7/12/07 to add sorting 
function getShiftsForDateRangeAndUser ($userPid, $startDate, $endDate)
{
	$result = safeQuery("select pid, day_of_week, " . 
		"UNIX_TIMESTAMP(start_date) as start_date, " .
		"UNIX_TIMESTAMP(end_date) as end_date " .
		"from shifts where owner = %d and " .
		"start_date <= FROM_UNIXTIME(%d) and end_date >= FROM_UNIXTIME(%d) ORDER BY end_time",
		$userPid, $endDate, $startDate);
		
	$a = array();
	while ($row = mysql_fetch_assoc($result))
	{
		// Use xlate_shiftdate to get real shift start and end dates, and filter
		// based on the same condition as in the query
		list($start, $end) = xlate_shiftdate($row['day_of_week'], $row['start_date'], $row['end_date'], $row['pid']);
		if ($start <= $endDate and $end >= $startDate)
			$a[] = $row['pid'];
	}
	return $a;
}

/* getShiftsForDayAndPosition ($date, $positionPid)
 *   retrieves array of PIDs of shifts occuring on the date and
 *   assigned to the given position
 */
function getShiftsForDayAndPosition ($date, $positionPid)
{
	$result = safeQuery("select pid from shifts where " .
		"start_date <= FROM_UNIXTIME(%d) and end_date >= FROM_UNIXTIME(%d) " .
		"and position = %d and day_of_week = '%s'",
		date_part($date), date_part($date), $positionPid,
		strtolower(date('l', $date)));
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		$a[] = $row['pid'];
	return $a;
}

/* getShiftsForDayAndUser ($userPid, $date)
 *   retrieves PIDS of shifts worked by that user on that date
 */
function getShiftsForDayAndUser ($userPid, $date)
{
	$result = safeQuery("select pid from shifts where " .
		"start_date <= FROM_UNIXTIME(%d) and end_date >= FROM_UNIXTIME(%d) " .
		"and owner = %d and day_of_week = '%s'",
		date_part($date), date_part($date), $userPid,
		strtolower(date('l', $date)));
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		$a[] = $row['pid'];
	return $a;	
}

/* getShiftsForShiftTable ($date)
 *   retrieves all the data for all shifts occuring on the specified date.
 *   returned in an array format:
 *      array(position_pids => array(0,1,... => shiftDetails))
 */
function getShiftsForShiftTable ($date)
{
    $positions = getPositions();
    $shifts_today = array();
    foreach ($positions as $positionPid)
	{
		$pids = getShiftsForDayAndPosition($date, $positionPid);
		$shifts_today[$positionPid] = sortShiftsByTime(getShiftDetailsForArray($pids));
    }
    return $shifts_today;
}

/*
 * Get array of PIDs of all shifts occurring at the specified date/time.
 */
function getShiftsForTime ($timestamp)
{
	$result = safeQuery("select pid from shifts where " .
		"day_of_week = '%s' and " .
		"start_date <= FROM_UNIXTIME(%d) and " .
		"end_date >= FROM_UNIXTIME(%d) and " .
		"TIME_TO_SEC(start_time) <= %d and " .
		"TIME_TO_SEC(end_time) > %d",
		strtolower(date('l', $timestamp)),
		$timestamp, $timestamp,
		time_part($timestamp), time_part($timestamp));
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		$a[] = $row['pid'];
	return $a;
}

/*
 * Get pids of shifts owned by this user (not including temp-dropped)
 */
function getShiftsForUser ($userPid)
{
	$result = safeQuery("select pid from shifts where owner = %d", $userPid);
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		$a[] = $row['pid'];
	return $a;
}

/*
 * Get pids of shifts owned or previously owned by this user,
 * including shifts they dropped that no one has yet picked up.
 */
function getShiftsForUserIncludingDropped ($userPid)
{
	$result = safeQuery("select pid from shifts where " .
		"owner = %d or (dropper = %d and owner is null)", $userPid, $userPid);
	$a = array();
	while ($row = mysql_fetch_assoc($result))
		$a[] = $row['pid'];
	return $a;
}

/*
 * Get status of the given shift PID, returns one of the following enums:
 */
define('STATUS_PERM_OPEN',  0);
define('STATUS_PERM_TAKEN', 1);
define('STATUS_TEMP_OPEN',  2);
define('STATUS_TEMP_TAKEN', 3);

function getShiftStaffingStatus ($shiftPid)
{
	$shift = getShiftDetails($shiftPid);
    if (isset($shift['owner']))
	{
        // Taken shift; if it occurs only once, consider it a temp shift;
		// otherwise, a perm shift.
        if ($shift['end_date'] < strtotime("+1 week", $shift['start_date']))
            return STATUS_TEMP_TAKEN;
        else
            return STATUS_PERM_TAKEN;
    }
	else
	{
        // Open shift; if it occurs only once AND has a dropper,
		// consider it a temp shift; otherwise, a perm shift.
        if ($shift['end_date'] < strtotime("+1 week", $shift['start_date']) and isset($shift['dropper']))
            return STATUS_TEMP_OPEN;
        else
            return STATUS_PERM_OPEN;
    }
}

/*
 * Split the shift into *before this day* and *after this day*, thus
 * appearing to cancel it for the given day only.  Works properly if the
 * given timestamp is in fact the first or last day of the shift.
 */
function internalCancelSplit ($shiftPid, $timestamp)
{
	// Create the before, this, and after segments
	$newShift = internalTempSplit($shiftPid, $timestamp);

    // Now we can be assured that $newShift occurs only once, on
    // the day we want to cancel it.  So delete it from the DB.
    if (!removeShift($newShift))
    {
    	error("internalCancelSplit($shiftPid, $timestamp): Unable to delete shift $newShift: did not exist");
        return NULL;
    }

    return $newShift;
}

/*
 * Set owner and time_taken to NULL. Set dropper and time_dropped.
 */
function internalDropShift ($shiftPid, $userPid)
{
	safeQuery("update shifts set owner = NULL, time_taken = NULL, " .
		"dropper = %d, time_dropped = NOW() where pid = %d",
		$userPid, $shiftPid);
}

/*
 * Split the shift into *before this day* and *this day and after this day*.
 * Works properly if timestamp represents the first date of the shift.
 * Returns the PID of the "this day and after" shift.
 */
function internalPermSplit ($shiftPid, $timestamp)
{
    $newShift = internalSplitShift($shiftPid, $timestamp);

    if (!$newShift)
        $newShift = $shiftPid;

    return $newShift;
}

/* internalSplitShift(shift PID, date (timestamp))
 *
 * Take a shift and split it around splitDate. The new shift starts on
 * $splitDate and the old shift is shortened to end one day before $splitDate.
 *
 * Returns NULL if splitDate is the first day of the shift, or the PID of the
 * new shift otherwise.
 */
function internalSplitShift ($oldPid, $splitDate)
{
    // Check whether this is the first date of the shift
    $data = getShiftDetails($oldPid);
    if (strtotime("-7 days", date_part($splitDate)) < $data['start_date'])
        // If this is the first shift
        return NULL;

    // Create the new shift (starts at $splitDate, but copies all other fields
    // from the original shift)
    safeQuery("INSERT INTO shifts (shift_group, start_date, end_date, " .
              "  start_time, end_time, day_of_week, position, owner, dropper, " .
              "  time_taken, time_dropped) " .
              "SELECT shift_group, FROM_UNIXTIME(%d) as start_date, end_date, start_time, " .
              "  end_time, day_of_week, position, owner, dropper, time_taken, " .
              "  time_dropped FROM shifts WHERE pid = %d",
	          date_part($splitDate), $oldPid);
    $newPid = mysql_insert_id();

    // Resize the old shift (goes from start_date to $splitDate - 1)
    safeQuery("UPDATE shifts SET end_date = (FROM_UNIXTIME(%d) - INTERVAL 1 DAY) " .
              "WHERE pid = %d", date_part($splitDate), $oldPid);

    return $newPid;
}

/*
 * Set the owner of the shift to user and set time_taken.
 */
function internalTakeShift ($shiftPid, $userPid)
{
    safeQuery("UPDATE shifts SET owner = %d, time_taken = NOW() " .
              "WHERE pid = %d", $userPid, $shiftPid);
}

/*
 * Split the shift into *before this day*, *this day*, and *after this day*.
 * Works properly if timestamp represents the first day of the shift.
 * Returns the PID of the *this day* shift.
 */
function internalTempSplit ($shiftPid, $timestamp)
{
    $newShift = internalSplitShift($shiftPid, $timestamp);

    if (!$newShift)
        $newShift = $shiftPid;

	// Check if this is the last day of the shift
    $data = getShiftDetails($newShift);
    $nextTimestamp = strtotime("+7 days", $timestamp);
    if (date_part($nextTimestamp) <= $data['end_date']) {
        $temp = internalSplitShift($newShift, $nextTimestamp);
    }

    return $newShift;
}

/*
 * Determine if timestamp is a day on which shift occurs (basic sanity check
 * for taking/dropping), and if timestamp is within the agreed upon future
 * time limit of 1 month (people can't take/drop shifts further than that
 * in advance).
 */
function isShiftTimeValid ($shiftPid, $timestamp)
{
	$shift = getShiftDetails($shiftPid);
    $start = $shift['start_date'];
    $end   = $shift['end_date'];
    // Within the shift's bounds.
    $date  = ($start <= $timestamp and $timestamp <= $end);
    // Date in the agreed upon time (between today and one month from today)
    //NOTE George changed this from 1 month to 2; may change later.  
    $time  = ($timestamp >= date_part(time())) &&
             ($timestamp <  strtotime("+2 month"));
    // Correct day-of-week
    $dow   = (!strcasecmp(date('l', $timestamp), $shift['day_of_week']));
    // Timestamp represents midnight
    $mid   = (time_part($timestamp) == 0);
	
    return ($date && $time && $dow && $mid);
}

function perm_drop_shift ($shiftPid, $timestamp, $userPid, $email_message)
{
    // Do checks to ensure that this user can perm-drop this shift
    $shift_data = getShiftDetails($shiftPid);
	if (!$shift_data)
	{
		error("Shift $shiftPid does not exist.");
		return NULL;
	}
    if (!checkUserCanDropShift($userPid, $shiftPid, $timestamp))
	{
        error('You are not allowed to drop this shift.');
		return NULL;
    }

    // Doing this as transaction so that nobody could ever possibly see the
    // database in an inconsistent state.
	start_transaction();

    // Split the shift on today
    $newShift = internalPermSplit($shiftPid, $timestamp);

    // Update the information of the new shift
    $result = internalDropShift($newShift, $userPid);

    // commit transaction
    commit_transaction();
	
	//check to see if we shouldn't send email  
	$someRow = getShiftDetails($shiftPid);

	if(checkIfShouldSendEmail($someRow['shift_group']))
   		email_cons_perm_drop($newShift, $shift_data['owner'], $email_message);
   		
    return $newShift;
}

function perm_take_shift ($shiftPid, $timestamp, $userPid, $email_message)
{
    // Do checks to ensure that this is a valid action
    $shift_data = getShiftDetails($shiftPid);
	if (!$shift_data)
	{
		error("Shift $shiftPid does not exist.");
		return NULL;
	}
    if (!checkUserCanTakeShift($userPid, $shiftPid, $timestamp))
	{
        error('You are not allowed to take this shift.');
		return NULL;
    }

    // Doing this as transaction so that nobody could ever possibly see the
    // database in an inconsistent state.
    start_transaction();

    // Split the shift on this day
    $newShift = internalPermSplit($shiftPid, $timestamp);

    // Update the information of the new shift
    $result = internalTakeShift($newShift, $userPid);

    // commit transaction
    commit_transaction();
	
	
	//check to see if we shouldn't send email  
	$someRow = getShiftDetails($shiftPid);

	if(checkIfShouldSendEmail($someRow['shift_group']))
   		 email_cons_perm_take($newShift, $userPid, $email_message);
   		
    return $newShift;
}

function temp_drop_shift ($shiftPid, $timestamp, $userPid, $email_message)
{
    // Do checks to ensure that this user can temp-drop this shift
    $shift_data = getShiftDetails($shiftPid);
	if (!$shift_data)
	{
		error("Shift $shiftPid does not exist.");
		return NULL;
	}
    if (!checkUserCanDropShift($userPid, $shiftPid, $timestamp))
	{
        error('You are not allowed to drop this shift.');
		return NULL;
    }

    // Doing this as transaction so that nobody could ever possibly see the
    // database in an inconsistent state.
    start_transaction();

    // Split the shift on this day, then, if this day isn't the last day of the
    // shift, split this shift on +7 days.
    $newShift = internalTempSplit($shiftPid, $timestamp);

    // Update the information of the new shift
    $result = internalDropShift($newShift, $userPid);

    // commit transaction
    commit_transaction();

	
	//check to see if we shouldn't send email  
	$someRow = getShiftDetails($shiftPid);
	if(checkIfShouldSendEmail($someRow['shift_group']))
    		email_cons_temp_drop($newShift, $shift_data['owner'], $email_message);
    		
    return;
}

function temp_take_shift ($shiftPid, $timestamp, $userPid, $email_message)
{
    // Do checks to ensure that this user can temp-take this shift
    $shift_data = getShiftDetails($shiftPid);
	if (!$shift_data)
	{
		error("Shift $shiftPid does not exist.");
		return NULL;
	}
    if (!checkUserCanTakeShift($userPid, $shiftPid, $timestamp))
	{
        error('You are not allowed to take this shift.');
		return NULL;
    }

    // Doing this as transaction so that nobody could ever possibly see the
    // database in an inconsistent state.
	start_transaction();

    // Splits it on this day and then this day + 7 (so we end
    // up with *before this day*, *this day*, and *after this day*)
    $newShift = internalTempSplit($shiftPid, $timestamp);

    // Update the information of the new shift
    $result = internalTakeShift($newShift, $userPid);

    // commit transaction
    commit_transaction();

  	//check to see if we shouldn't send email  
	$someRow = getShiftDetails($shiftPid);

	if(checkIfShouldSendEmail($someRow['shift_group']))
    		email_cons_temp_take($newShift, $userPid, $email_message);
    		
    return $newShift;
}

function removeShift ($pid)
{
	safeQuery("delete from shifts where pid = %d", $pid);
	return (mysql_affected_rows() == 1);
}

/* Given a day_of_week, the start date, and the end date of a shift, return
 * the actual start and end date of the shift (i.e. the returned start and end
 * dates wiil both fall on the appropriate day of the week.
 *
 * $start_date and $end_date are timestamps.
 *
 * DO NOT DO NOT DO NOT DO NOT DO NOT remove the dual strtotime()
 * calls (strtotime('12AM', strtotime('stuff...)))!!!!!!!!
 *
 * Hacking around a bug with the 'this ...' and 'last ...' and
 * strtotime() in PHP and Daylight Saving Time:
print date('r', strtotime('last thursday', strtotime("00:00:00 April 3, 2006")));
outputs
Wed, 29 Mar 2006 23:00:00 -0800
 */
function xlate_shiftdate($day_of_week, $start_date, $end_date, $shift_pid = 0)
{
	if (strcasecmp(date("l", $start_date), $day_of_week) == 0)
		$new_start = $start_date;
	else
		$new_start = strtotime('12AM', strtotime("12PM this $day_of_week", $start_date));

	if (strcasecmp(date("l", $end_date), $day_of_week) == 0)
		$new_end = $end_date;
	else
		$new_end = strtotime('12AM', strtotime("12PM last $day_of_week", $end_date));

	if ($new_start > $end_date or $new_end < $start_date)
		exit("Xlate exception: this shift never actually occurs " .
			"($new_start > $end_date or $new_end < $start_date). Please contact supers immediately.  Shift pid is $shift_pid");

	return array($new_start, $new_end);
}

?>
Return current item: ConPortal