AppStateESS/homestead

View on GitHub
class/HMS_Lottery.php

Summary

Maintainability
F
1 wk
Test Coverage
<?php

namespace Homestead;

use \Homestead\Exception\DatabaseException;
use \PHPWS_Error;
use \PHPWS_DB;
define('MAX_INVITES_PER_BATCH', 500);
define('INVITE_TTL_HRS', 48);


class HMS_Lottery {

    /**
     * Looks for an entry with the 'magic_winner' flag set and returns it, otherwise it returns null
     */
    public static function check_magic_winner($term)
    {
        $now = time();

        $query = "SELECT * FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                    LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term) as foo ON hms_new_application.username = foo.asu_username
                    WHERE foo.asu_username IS NULL AND (hms_lottery_application.invite_expires_on < $now OR hms_lottery_application.invite_expires_on IS NULL)
                    AND hms_new_application.term = $term
                    AND hms_lottery_application.magic_winner = 1";

        $result = PHPWS_DB::getRow($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return null;
        }

        if (!isset($result) || empty($result)) {
            return null;
        } else {
            return $result;
        }
    }

    /**
     * Returns the number of lottery entries currently outstanding (i.e.
     * non-winners)
     */
    public static function count_remaining_entries($term)
    {
        $now = time();

        $sql = "SELECT count(*) FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE hms_assignment.term=$term) as foo ON hms_new_application.username = foo.asu_username
                WHERE foo.asu_username IS NULL AND (hms_lottery_application.invite_expires_on < $now OR hms_lottery_application.invite_expires_on IS NULL)
                AND hms_new_application.term = $term
                AND special_interest IS NULL";

        $num_remaining_entries = PHPWS_DB::getOne($sql);

        if (\PEAR::isError($num_remaining_entries)) {
            PHPWS_Error::log($num_remaining_entries);
            return false;
        }

        return $num_remaining_entries;
    }

    public static function count_outstanding_invites($term, $gender = null)
    {
        $now = time();
        $query = "select count(*) FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term AND lottery = 1) as foo ON hms_new_application.username = foo.asu_username
                WHERE foo.asu_username IS NULL
                AND hms_lottery_application.invite_expires_on > $now
                AND hms_new_application.term = $term";
        if (isset($gender)) {
            $query .= ' AND hms_new_application.gender = ' . $gender;
        }

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    /*
     * Returns the number of outstanding *roommate* invites
    */
    public static function count_outstanding_roommate_invites($term)
    {
        $now = time();
        $query = "select count(*) FROM hms_lottery_reservation
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term AND lottery = 1) as foo ON hms_lottery_reservation.asu_username = foo.asu_username
                WHERE foo.asu_username IS NULL
                AND hms_lottery_reservation.expires_on > $now
                AND hms_lottery_reservation.term = $term";

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    /*
     * Returns the number of invites sent (confirmed or outstanding) for the given class
    */
    public static function count_invites_by_class($term, $class)
    {
        $now = time();
        $term_year = Term::getTermYear($term);

        $query = "SELECT count(*) FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term AND lottery = 1) as foo ON hms_new_application.username = foo.asu_username
                WHERE ((foo.asu_username IS NULL AND hms_lottery_application.invite_expires_on > $now) OR (foo.asu_username IS NOT NULL AND hms_lottery_application.invite_expires_on IS NOT NULL))
                AND hms_new_application.term = $term ";

        if ($class == CLASS_SOPHOMORE) {
            $query .= 'AND (application_term = ' . ($term_year - 1) . '20';
            $query .= ' OR application_term = ' . ($term_year - 1) . '30';
            $query .= ' OR application_term = ' . ($term_year - 1) . '40';
            $query .= ' OR application_term = ' . ($term_year) . '10';
            $query .= ')';
        } else if ($class == CLASS_JUNIOR) {
            $query .= 'AND (application_term = ' . ($term_year - 2) . '20';
            $query .= ' OR application_term = ' . ($term_year - 2) . '30';
            $query .= ' OR application_term = ' . ($term_year - 2) . '40';
            $query .= ' OR application_term = ' . ($term_year - 1) . '10';
            $query .= ')';
        } else {
            $query .= 'AND application_term <= ' . ($term_year - 2) . '10';
        }

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    public static function count_remaining_entries_by_class($term, $class)
    {
        $now = time();
        $term_year = Term::getTermYear($term);

        $query = "SELECT count(*) FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                    LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term) as foo ON hms_new_application.username = foo.asu_username
                    WHERE foo.asu_username IS NULL AND (hms_lottery_application.invite_expires_on < $now OR hms_lottery_application.invite_expires_on IS NULL)
                    AND hms_new_application.term = $term
                    AND special_interest IS NULL ";

        if ($class == CLASS_SOPHOMORE) {
            $query .= 'AND (application_term = ' . ($term_year - 1) . '20';
            $query .= ' OR application_term = ' . ($term_year - 1) . '30';
            $query .= ' OR application_term = ' . ($term_year - 1) . '40';
            $query .= ' OR application_term = ' . ($term_year) . '10';
            $query .= ')';
        } else if ($class == CLASS_JUNIOR) {
            $query .= 'AND (application_term = ' . ($term_year - 2) . '20';
            $query .= ' OR application_term = ' . ($term_year - 2) . '30';
            $query .= ' OR application_term = ' . ($term_year - 2) . '40';
            $query .= ' OR application_term = ' . ($term_year - 1) . '10';
            $query .= ')';
        } else {
            $query .= 'AND application_term <= ' . ($term_year - 2) . '10';
        }

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    public static function count_outstanding_invites_by_class($term, $class)
    {
        $now = time();
        $term_year = Term::getTermYear($term);

        $query = "SELECT count(*) from hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                    LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term) as foo ON hms_new_application.username = foo.asu_username
                    WHERE foo.asu_username IS NULL
                    AND hms_lottery_application.invite_expires_on > $now
                    AND hms_new_application.term = $term ";

        if ($class == CLASS_SOPHOMORE) {
            $query .= 'AND (application_term = ' . ($term_year - 1) . '20';
            $query .= ' OR application_term = ' . ($term_year - 1) . '30';
            $query .= ' OR application_term = ' . ($term_year - 1) . '40';
            $query .= ' OR application_term = ' . ($term_year) . '10';
            $query .= ')';
        } else if ($class == CLASS_JUNIOR) {
            $query .= 'AND (application_term = ' . ($term_year - 2) . '20';
            $query .= ' OR application_term = ' . ($term_year - 2) . '30';
            $query .= ' OR application_term = ' . ($term_year - 2) . '40';
            $query .= ' OR application_term = ' . ($term_year - 1) . '10';
            $query .= ')';
        } else {
            $query .= 'AND application_term <= ' . ($term_year - 2) . '10';
        }

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    public static function count_applications_by_class($term, $class)
    {
        $term_year = Term::getTermYear($term);

        $query = "SELECT count(*) from hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                    WHERE term = $term
                    AND special_interest IS NULL ";

        if ($class == CLASS_SOPHOMORE) {
            $query .= 'AND (application_term = ' . ($term_year - 1) . '20';
            $query .= ' OR application_term = ' . ($term_year - 1) . '30';
            $query .= ' OR application_term = ' . ($term_year - 1) . '40';
            $query .= ' OR application_term = ' . ($term_year) . '10';
            $query .= ')';
        } else if ($class == CLASS_JUNIOR) {
            $query .= 'AND (application_term = ' . ($term_year - 2) . '20';
            $query .= ' OR application_term = ' . ($term_year - 2) . '30';
            $query .= ' OR application_term = ' . ($term_year - 2) . '40';
            $query .= ' OR application_term = ' . ($term_year - 1) . '10';
            $query .= ')';
        } else {
            $query .= 'AND application_term <= ' . ($term_year - 2) . '10';
        }

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    public static function count_assignments_by_class($term, $class)
    {
        $term_year = Term::getTermYear($term);

        $query = "SELECT count(*) from hms_assignment
                    JOIN hms_new_application ON hms_assignment.asu_username = hms_new_application.username
                    JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                    WHERE hms_assignment.term = $term
                    AND hms_assignment.lottery = 1
                    AND hms_new_application.term = $term ";

        if ($class == CLASS_SOPHOMORE) {
            $query .= 'AND (application_term = ' . ($term_year - 1) . '20';
            $query .= ' OR application_term = ' . ($term_year - 1) . '30';
            $query .= ' OR application_term = ' . ($term_year - 1) . '40';
            $query .= ' OR application_term = ' . ($term_year) . '10';
            $query .= ')';
        } else if ($class == CLASS_JUNIOR) {
            $query .= 'AND (application_term = ' . ($term_year - 2) . '20';
            $query .= ' OR application_term = ' . ($term_year - 2) . '30';
            $query .= ' OR application_term = ' . ($term_year - 2) . '40';
            $query .= ' OR application_term = ' . ($term_year - 1) . '10';
            $query .= ')';
        } else {
            $query .= 'AND application_term <= ' . ($term_year - 2) . '10';
        }

        $result = PHPWS_DB::getOne($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            return false;
        } else {
            return $result;
        }
    }

    public static function send_winning_reminder_emails($term)
    {
        // Get a list of lottery winners who have not chosen a room yet, send them reminder emails
        $query = "select hms_new_application.username, hms_lottery_application.invite_expires_on FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term AND lottery = 1) as foo ON hms_new_application.username = foo.asu_username
                WHERE foo.asu_username IS NULL
                AND hms_lottery_application.invite_expires_on > " . time();

        $result = PHPWS_DB::getAll($query);

        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            test($result, 1);
        }

        $year = Term::toString($term) . ' - ' . Term::toString(Term::getNextTerm($term));

        foreach ($result as $row) {
            $student = StudentFactory::getStudentByUsername($row['username'], $term);
            HMS_Email::send_lottery_invite_reminder($student, $student->getName(), $row['invite_expires_on'], $year);
            HMS_Activity_Log::log_activity($row['username'], ACTIVITY_LOTTERY_REMINDED, 'hms');
        }
    }

    public static function send_roommate_reminder_emails($term)
    {
        // Get a list of outstanding roommate requests, send them reminder emails
        $query = "select hms_lottery_reservation.* FROM hms_lottery_reservation
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE term=$term AND lottery = 1) as foo ON hms_lottery_reservation.asu_username = foo.asu_username
                WHERE foo.asu_username IS NULL
                AND hms_lottery_reservation.expires_on > " . time();

        $result = PHPWS_DB::getAll($query);
        if (\PEAR::isError($result)) {
            PHPWS_Error::log($result);
            test($result, 1);
        }

        $year = Term::toString($term) . ' - ' . Term::toString(Term::getNextTerm($term));

        foreach ($result as $row) {
            $student = StudentFactory::getStudentByUsername($row['asu_username'], $term);
            $requestor = StudentFactory::getStudentByUsername($row['requestor'], $term);

            $bed = new Bed($row['bed_id']);
            $hall_room = $bed->where_am_i();
            HMS_Email::send_lottery_roommate_reminder($student, $student->getName(), $row['expires_on'], $requestor->getName(), $hall_room, $year);
            HMS_Activity_Log::log_activity($row['asu_username'], ACTIVITY_LOTTERY_ROOMMATE_REMINDED, 'hms');
        }
    }

    public static function lottery_complete($status, $log, $unschedule = false)
    {
        echo "Lottery complete, status: $status<br />\n";

        $email = "";

        // Output the logging info, transform for email
        foreach ($log as $line) {
            echo $line . "<br />\n";
            $email .= $line . "\n";
        }

        // TODO: unschedule from pulse here, if true

        HMS_Email::send_lottery_status_report($status, $email);
        exit();
    }

    /**
     * Retuns an array of lottery roommate invites
     */
    public static function get_lottery_roommate_invites($username, $term)
    {
        $db = new PHPWS_DB('hms_lottery_reservation');

        $db->addWhere('asu_username', $username);
        $db->addWhere('term', $term);
        $db->addWhere('expires_on', time(), '>'); // make sure the request hasn't expired

        $result = $db->select();

        if (!$result || PHPWS_Error::logIfError($result)) {
            return false;
        }

        return $result;
    }

    public static function get_lottery_roommate_invite_by_id($id)
    {
        if($id === null || $id === ''){
            throw new \InvalidArgumentException('Missing roommate invite id parameter');
        }

        $db = PdoFactory::getPdoInstance();

        $query = "SELECT hms_lottery_reservation.*
                    FROM hms_lottery_reservation
                    WHERE
                        hms_lottery_reservation.expires_on > :expiresOn
                        AND hms_lottery_reservation.id = :id";

        $stmt = $db->prepare($query);
        $stmt->execute(array(
                'id' => $id,
                'expiresOn' => time()
        ));

        $result = $stmt->fetch(\PDO::FETCH_ASSOC);

        if (!$result || PHPWS_Error::logIfError($result)) {
            return false;
        }

        return $result;
    }

    public static function confirm_roommate_request($username, $requestId)
    {
        $term = \PHPWS_Settings::get('hms', 'lottery_term');

        // Get the roommate invite
        $invite = HMS_Lottery::get_lottery_roommate_invite_by_id($requestId);

        // If the invite wasn't found, show an error
        if ($invite === false) {
            return E_LOTTERY_ROOMMATE_INVITE_NOT_FOUND;
        }

        // Check that the reserved bed is still empty
        $bed = new Bed($invite['bed_id']);
        if (!$bed->has_vacancy()) {
            return E_ASSIGN_BED_NOT_EMPTY;
        }

        // Make sure the student isn't assigned anywhere else
        if (HMS_Assignment::checkForAssignment($username, $term)) {
            return E_ASSIGN_ALREADY_ASSIGNED;
        }

        $student = StudentFactory::getStudentByUsername($username, $term);
        $requestor = StudentFactory::getStudentByUsername($invite['requestor'], $term);

        // Actually make the assignment
        HMS_Assignment::assignStudent($student, $term, null, $invite['bed_id'], 'Confirmed roommate invite', true, ASSIGN_LOTTERY);

        // return successfully
        HMS_Email::send_roommate_confirmation($student, $requestor);
        return E_SUCCESS;
    }

    public static function denyRoommateRequest($requestId)
    {
        // Delete the invite
        $db = new PHPWS_DB('hms_lottery_reservation');
        $db->addWhere('id', $requestId);
        $result = $db->delete();

        if (PHPWS_Error::logIfError($result)) {
            throw new DatabaseException($result->toString());
        }

        return true;
    }

    /*
     * Returns true if the student is assigned in the current term
    * or if the student has an eligibility waiver.
    */
    public static function determineEligibility($username)
    {
        // First, check for an assignment in the current term
        if (HMS_Assignment::checkForAssignment($username, Term::getCurrentTerm())) {
            return true;
            // If that didn't work, check for a waiver in the lottery term
        } elseif (HMS_Eligibility_Waiver::checkForWaiver($username, \PHPWS_Settings::get('hms', 'lottery_term'))) {
            return true;
            // If that didn't work either, then the student is not elibible, so return false
        } else {
            return false;
        }
    }

    // Translates an application term into a class (fr, soph, etc) based on the term given
    public static function application_term_to_class($curr_term, $application_term)
    {
        // Break up the term and year
        $yr = floor($application_term / 100);
        $sem = $application_term - ($yr * 100);

        $curr_year = floor($curr_term / 100);
        $curr_sem = $curr_term - ($curr_year * 100);

        if ($curr_sem == 10) {
            $curr_year -= 1;
            $curr_sem = 40;
        }

        if (is_null($application_term) || !isset($application_term)) {
            // If there's no application term, just return null
            return null;
        } else if ($application_term >= $curr_term) {
            // The application term is greater than the current term, then they're certainly a freshmen
            return CLASS_FRESHMEN;
        } else if (($yr == $curr_year + 1 && $sem = 10) || ($yr == $curr_year && $sem >= 20 && $sem <= 40)) {
            // freshmen
            return CLASS_FRESHMEN;
        } else if (($yr == $curr_year && $sem == 10) || ($yr + 1 == $curr_year && $sem >= 20 && $sem <= 40)) {
            // soph
            return CLASS_SOPHOMORE;
        } else if (($yr + 1 == $curr_year && $sem == 10) || ($yr + 2 == $curr_year && $sem >= 20 && $sem <= 40)) {
            // jr
            return CLASS_JUNIOR;
        } else {
            // senior
            return CLASS_SENIOR;
        }
    }

    public static function getSpecialInterestGroupsMap()
    {
        $special_interests = array();

        $special_interests['none'] = 'None';
        $special_interests['honors'] = 'The Honors College';
        $special_interests['watauga_global'] = 'Watauga Global Community';
        $special_interests['teaching'] = 'Teaching Fellows';
        $special_interests['sorority_adp'] = 'Alpha Delta Pi Sorority';
        $special_interests['sorority_ap'] = 'Aplha Phi Sorority';
        $special_interests['sorority_co'] = 'Chi Omega Sorority';
        $special_interests['sorority_dz'] = 'Delta Zeta Sorority';
        $special_interests['sorority_kd'] = 'Kappa Delta Sorority';
        $special_interests['sorority_pm'] = 'Phi Mu Sorority';
        $special_interests['sorority_sk'] = 'Sigma Kappa Sorority';
        $special_interests['sorority_aop'] = 'Alpha Omicron Pi Sorority';
        $special_interests['sorority_zta'] = 'Zeta Tau Alpha';

        return $special_interests;
    }

    public static function getSororities()
    {
        $sororities = array();

        $sororities['sorority_adp'] = 'Alpha Delta Pi Sorority';
        $sororities['sorority_ap'] = 'Aplha Phi Sorority';
        $sororities['sorority_co'] = 'Chi Omega Sorority';
        $sororities['sorority_dz'] = 'Delta Zeta Sorority';
        $sororities['sorority_kd'] = 'Kappa Delta Sorority';
        $sororities['sorority_pm'] = 'Phi Mu Sorority';
        $sororities['sorority_sk'] = 'Sigma Kappa Sorority';
        $sororities['sorority_aop'] = 'Alpha Omicron Pi Sorority';
        $sororities['sorority_zta'] = 'Zeta Tau Alpha';

        return $sororities;
    }

    /**
     *
     * @deprecated
     *
     * @throws DatabaseException
     * @return unknown
     */
    public static function getSizeOfOnCampusWaitList()
    {
        $term = \PHPWS_Settings::get('hms', 'lottery_term');

        // Get the list of user names still on the waiting list, sorted by ID (first come, first served)
        $sql = "SELECT count(*) FROM hms_new_application JOIN hms_lottery_application ON hms_new_application.id = hms_lottery_application.id
                LEFT OUTER JOIN (SELECT asu_username FROM hms_assignment WHERE hms_assignment.term=$term) as foo ON hms_new_application.username = foo.asu_username
                WHERE foo.asu_username IS NULL
                AND hms_new_application.term = $term
                AND special_interest IS NULL
                AND waiting_list_hide = 0";

        $count = PHPWS_DB::getOne($sql);

        if (PHPWS_Error::logIfError($count)) {
            throw new DatabaseException($count->toString());
        }

        return $count;
    }
}