/**
  * Tests saving a sfGuardUserSubredditMembership that identifies a User as
  * "blocked" for a particular Subreddit.  When this occurs, all existing
  * future EpisodeAssignments should be deleted because blocked users cannot
  * participate with the Subreddit.
  */
 public function testSavingBlockedUser()
 {
     // Establish fake Subreddit
     $subreddit = new Subreddit();
     $subreddit->setName(rand(0, 1000));
     $subreddit->setDomain(rand(0, 1000));
     $subreddit->save();
     // Establish User
     $user = new sfGuardUser();
     $user->setEmailAddress(rand(0, 100000));
     $user->setUsername(rand(0, 10000));
     $user->setIsValidated(1);
     $user->save();
     $user_id = $user->getIncremented();
     $this->assertNotEquals(0, $user_id);
     // Establish Episode for Subreddit
     $episode = new Episode();
     $episode->setSubreddit($subreddit);
     $episode->setReleaseDate(date('Y-m-d H:i:s', time() + 34000));
     $episode->save();
     $author_type = AuthorTypeTable::getInstance()->findOneBy('type', 'squid');
     $deadline = new Deadline();
     $deadline->setSubreddit($subreddit);
     $deadline->setAuthorType($author_type);
     $deadline->setSeconds(0);
     $deadline->save();
     $episode_assignment = new EpisodeAssignment();
     $episode_assignment->setSfGuardUser($user);
     $episode_assignment->setEpisode($episode);
     $episode_assignment->setAuthorType($author_type);
     $episode_assignment->save();
     $number_of_episodes = EpisodeAssignmentTable::getInstance()->createQuery()->select('COUNT(EpisodeAssignment.id)')->leftJoin('Episode')->where('subreddit_id = ?', $subreddit->getIncremented())->andWhere('EpisodeAssignment.sf_guard_user_id = ?', $user_id)->andWhere('Episode.release_date > NOW()')->groupBy('EpisodeAssignment.id')->count();
     $this->assertEquals(1, $number_of_episodes);
     // Establish User Membership as Blocked
     $blocked = MembershipTable::getInstance()->findOneBy('type', 'blocked');
     $user_membership = new sfGuardUserSubredditMembership();
     $user_membership->setSubreddit($subreddit);
     $user_membership->setSfGuardUser($user);
     $user_membership->setMembership($blocked);
     // Save Membership
     $user_membership->save();
     // Asert that User has zero Episodes
     $number_of_episodes = EpisodeAssignmentTable::getInstance()->createQuery()->select('COUNT(EpisodeAssignment.id)')->leftJoin('Episode')->where('subreddit_id = ?', $subreddit->getIncremented())->andWhere('EpisodeAssignment.sf_guard_user_id = ?', $user_id)->andWhere('Episode.release_date > NOW()')->groupBy('EpisodeAssignment.id');
     $sql = $number_of_episodes->getSqlQuery();
     $number_of_episodes = $number_of_episodes->count();
     $this->assertTrue(0 == $number_of_episodes, $sql . "\n" . $subreddit->getIncremented() . "\n" . $user_id);
     // Remove User Membership
     $user_membership->delete();
     // Delete User
     $user->delete();
     // Delete Episode
     $episode->delete();
     // Delete Deadline
     $deadline->delete();
     // Delete Subreddit
     $subreddit->delete();
 }
 public function setIdHashIfNotSet()
 {
     if ($this->getIdHash()) {
         return;
     }
     $hash = '';
     do {
         $hash = md5(rand(0, 10) . microtime() . $this->getAuthorTypeId() . $this->getSfGuardUserId() . $this->getEpisodeId());
         // Since the hash is meant for uses such as phone call recording, we need to make sure it's only numbers.
         $hash = str_replace(array('a', 'b', 'c', 'd', 'e', 'f'), array(0, 1, 2, 3, 4, 5), $hash);
         $hash = substr($hash, 0, ProjectConfiguration::getTropoHashLength());
     } while (EpisodeAssignmentTable::getInstance()->getByIdHash($hash, $this->getEpisode()->getSubredditId()));
     $this->setIdHash($hash);
 }
 /**
  * Creates a token referring to an sfGuardUser object
  * @param   sfWebRequest   $request a request object
  * @return  string
  */
 public function executeValidhash(sfWebRequest $request)
 {
     $this->forward404Unless($request->isMethod(sfRequest::GET));
     $params = $request->getParameterHolder()->getAll();
     // notify an event before the action's body starts
     $this->dispatcher->notify(new sfEvent($this, 'sfDoctrineRestGenerator.get.pre', array('params' => $params)));
     $request->setRequestFormat('html');
     $this->setTemplate('index');
     $params = $this->cleanupParameters($params);
     $is_valid = false;
     try {
         $format = $this->getFormat();
         if (!array_key_exists('subreddit_id', $params) && !array_key_exists('id_hash', $params)) {
             throw new sfException('Missing reference to subreddit_id and id_hash!', 400);
         }
         if (!array_key_exists('subreddit_id', $params)) {
             throw new sfException('Missing reference to subreddit_id!', 400);
         }
         if (!array_key_exists('id_hash', $params)) {
             throw new sfException('Missing reference to id_hash!', 400);
         }
         $check = EpisodeAssignmentTable::getInstance()->getByIdHash($params['id_hash'], $params['subreddit_id']);
         if ($check) {
             $is_valid = true;
         }
     } catch (Exception $e) {
         $this->getResponse()->setStatusCode($e->getCode() ? $e->getCode() : 406);
         $serializer = $this->getSerializer();
         $this->getResponse()->setContentType($serializer->getContentType());
         $error = $e->getMessage();
         // event filter to enable customisation of the error message.
         $result = $this->dispatcher->filter(new sfEvent($this, 'sfDoctrineRestGenerator.filter_error_output'), $error)->getReturnValue();
         if ($error === $result) {
             $error = array(array('message' => $error));
             $this->output = $serializer->serialize($error, 'error');
         } else {
             $this->output = $serializer->serialize($result);
         }
         return sfView::SUCCESS;
     }
     $serializer = $this->getSerializer();
     $this->getResponse()->setContentType($serializer->getContentType());
     $this->output = $serializer->serialize(array('is_valid' => $is_valid), $this->model, false);
 }
 public function advanceEpisodeAssignments()
 {
     $subreddit_first_deadlines = array();
     $subreddit_deadline_rules = array();
     // We establish the pool of emails we'll be sending.
     // First to those who pass their deadline
     $passed_deadline_assignments = array();
     // And to the new episode assignments that are reassigned
     $newly_assigned_assignments = array();
     // Now we can start on the assignments that are misassigned
     $assignments = EpisodeAssignmentTable::getInstance()->getMisassignedEpisodes();
     $episodes = new Doctrine_Collection('Episode');
     $e = -1;
     for ($i = 0; $i < count($assignments); $i++) {
         $passed_deadline_assignments[] = $assignments[$i];
         $assignments[$i]->setMissedDeadline(true);
         $episodes[++$e] = $assignments[$i]->getEpisode();
         // Clean up the Episode for any new user to use.
         $episodes[$e]->setEpisodeAssignmentId(null);
         $audio_file = $episodes[$e]->getAudioFile();
         $nice_filename = $episodes[$e]->getNiceFilename();
         $graphic_file = $episodes[$e]->getGraphicFile();
         $episodes[$e]->setAudioFile(null);
         $episodes[$e]->setNiceFilename(null);
         $episodes[$e]->setGraphicFile(null);
         $episodes[$e]->setIsNsfw(false);
         $episodes[$e]->setTitle(null);
         $episodes[$e]->setDescription(null);
         $episodes[$e]->setIsSubmitted(false);
         $episodes[$e]->setSubmittedAt(null);
         $episodes[$e]->setFileIsRemote(null);
         $episodes[$e]->setRemoteUrl(null);
         $episodes[$e]->setRedditPostUrl(null);
     }
     $episodes->save();
     $assignments->save();
     /* Now we make sure that all assignments past deadline are marked as
      * such.  If the assignment is here, however, then it hasn't ever
      * actually BEEN assigned and isn't added to the list of emails to send
      * out. */
     $assignments = EpisodeAssignmentTable::getInstance()->getUnmarkedEpisodesThatMissedDeadlines();
     for ($i = 0; $i < count($assignments); $i++) {
         $assignments[$i]->setMissedDeadline(true);
     }
     $assignments->save();
     /* Now all episodes are cleared and we need to see if they need to be
      * reassigned to an existing asignment. */
     /* Returns assignments closest to the front for each unassigned episode,
      * in order of closeness. */
     $assignments = EpisodeAssignmentTable::getInstance()->getEpisodesPossiblyNeedingAssignment();
     $subreddit_ids = EpisodeAssignmentTable::getInstance()->getSubrbedditsOfEpisodesPossiblyNeedingAssignment();
     $deadlines = DeadlineTable::getInstance()->getDeadlinesForGivenSubreddits($subreddit_ids);
     $subreddit_first_authortypes = array();
     $subreddit_deadline_rules = array();
     $begun = false;
     $prev_subreddit_id = null;
     foreach ($deadlines as $deadline) {
         $subreddit_id = $deadline['subreddit_id'];
         if ($prev_subreddit_id != $subreddit_id && $begun) {
             $begun = false;
             $prev_subreddit_id = $subreddit_id;
         }
         if (!$begun) {
             $subreddit_deadline_rules[$subreddit_id] = array($deadline['author_type_id'] => $deadline['seconds']);
             $subreddit_first_authortypes[$subreddit_id] = $deadline['author_type_id'];
             $begun = true;
         } else {
             $author_type_id = $deadline['author_type_id'];
             $subreddit_deadline_rules[$subreddit_id][$author_type_id] = $deadline['seconds'];
         }
     }
     $episodes_affected = array();
     // Things used from assignment: episode_id, epsiode, author_type_id, id, sf_guard_user_id
     // Things used from episode: subreddit_id, surbeddit, release_date,
     // Things used from subreddit: getFirstDeadlineId(), getDeadlineRules()
     foreach ($assignments as $assignment) {
         if (!in_array($assignment['episode_id'], $episodes_affected)) {
             /* Ignore all subsequent assignments for an episode after the
              * first!  We should only be dealing with assignments that have
              * not missed their deadlines! */
             $episodes_affected[] = $assignment['episode_id'];
             $assign_to_episode = false;
             $subreddit_id = $assignment['subreddit_id'];
             $subreddit = SubredditTable::getInstance()->find($subreddit_id);
             /* If the *first* assignment is in the first spot, then assign
              * it. */
             $deadline_rules = $subreddit_deadline_rules[$subreddit_id];
             $author_type_id = $assignment['author_type_id'];
             if ($author_type_id == $subreddit_first_authortypes[$subreddit_id]) {
                 $assign_to_episode = true;
             } else {
                 /* Otherwise, check if we are past the deadline for the
                  * previous deadline. */
                 /*$previous_author_type_id = DeadlineTable::getInstance()
                   ->getFirstAuthorTypeIdBySubredditWhereDeadlineIsGreaterThan(
                   $deadline_rules[$author_type_id],
                   $subreddit_id);*/
                 $inverse_deadline_rules = array_reverse($deadline_rules, true);
                 $previous_author_type_id = null;
                 foreach ($inverse_deadline_rules as $author_type => $seconds) {
                     if ($seconds > $deadline_rules[$author_type_id]) {
                         $previous_author_type_id = $author_type;
                         break;
                     }
                 }
                 $past_deadline_for_previous = strtotime($assignment['release_date']) - $deadline_rules[$previous_author_type_id] <= time();
                 if ($past_deadline_for_previous) {
                     $assign_to_episode = true;
                 }
             }
             if ($assign_to_episode) {
                 $saved_episode = EpisodeTable::getInstance()->find($assignment['episode_id']);
                 $saved_episode->setEpisodeAssignmentId($assignment['id']);
                 $saved_episode->save();
                 $newly_assigned_assignments[] = $assignment;
             }
         }
     }
     // We send the emails for the current deadline we're checking.
     foreach ($passed_deadline_assignments as $assignment) {
         $this->sendEmailAboutPassedDeadline($assignment['sf_guard_user_id'], $assignment['episode_id']);
     }
     foreach ($newly_assigned_assignments as $assignment) {
         $release_date = strtotime($assignment['release_date']);
         $author_type_id = $assignment['author_type_id'];
         $seconds = $deadline_rules[$author_type_id];
         $deadline = $release_date - $seconds;
         $this->sendEmailAboutNewAssignment($assignment['sf_guard_user_id'], $assignment['episode_id'], $deadline);
     }
 }
 public function advanceEpisodeAssignments()
 {
     // We grab the Deadlines in descending order for the Subreddit;
     $deadline_rules = $this->getDeadlineRules();
     $first_deadline_id = $this->getFirstDeadlineId();
     $first_deadline = DeadlineTable::getInstance()->find($first_deadline_id);
     // We establish the pool of emails we'll be sending.
     // First to those who pass their deadline
     $passed_deadline_assignments = array();
     // And to the new episode assignments that are reassigned
     $newly_assigned_assignments = array();
     // Now we can start on the assignments that are misassigned
     $assignments = EpisodeAssignmentTable::getInstance()->getMisassignedEpisodes($this->getIncremented());
     $episodes = new Doctrine_Collection('Episode');
     $e = -1;
     for ($i = 0; $i < count($assignments); $i++) {
         $passed_deadline_assignments[] = $assignments[$i];
         $assignments[$i]->setMissedDeadline(true);
         $episodes[++$e] = $assignments[$i]->getEpisode();
         // Clean up the Episode for any new user to use.
         $episodes[$e]->setEpisodeAssignmentId(null);
         $audio_file = $episodes[$e]->getAudioFile();
         $nice_filename = $episodes[$e]->getNiceFilename();
         $graphic_file = $episodes[$e]->getGraphicFile();
         $episodes[$e]->setAudioFile(null);
         $episodes[$e]->setNiceFilename(null);
         $episodes[$e]->setGraphicFile(null);
         $episodes[$e]->setIsNsfw(false);
         $episodes[$e]->setTitle(null);
         $episodes[$e]->setDescription(null);
         $episodes[$e]->setIsSubmitted(false);
         $episodes[$e]->setSubmittedAt(null);
         $episodes[$e]->setFileIsRemote(null);
         $episodes[$e]->setRemoteUrl(null);
         $episodes[$e]->setRedditPostUrl(null);
     }
     $episodes->save();
     $assignments->save();
     /* Now we make sure that all assignments past deadline are marked as
      * such.  If the assignment is here, however, then it hasn't ever
      * actually BEEN assigned and isn't added to the list of emails to send
      * out. */
     $assignments = EpisodeAssignmentTable::getInstance()->getUnmarkedEpisodesThatMissedDeadlines($this->getIncremented());
     for ($i = 0; $i < count($assignments); $i++) {
         $assignments[$i]->setMissedDeadline(true);
     }
     $assignments->save();
     /* Now all episodes are cleared and we need to see if they need to be
      * reassigned to an existing asignment. */
     /* Returns assignments closest to the front for each unassigned episode,
      * in order of closeness. */
     $assignments = EpisodeAssignmentTable::getInstance()->getEpisodesPossiblyNeedingAssignment($this->getIncremented());
     $episodes_affected = array();
     foreach ($assignments as $assignment) {
         if (!in_array($assignment->getEpisodeId(), $episodes_affected)) {
             /* Ignore all subsequent assignments for an episode after the
              * first!  We should only be dealing with assignments that have
              * not missed their deadlines! */
             $episodes_affected[] = $assignment->getEpisodeId();
             $episode = $assignment->getEpisode();
             $assign_to_episode = false;
             /* If the *first* assignment is in the first spot, then assign
              * it. */
             if ($assignment->getAuthorTypeId() == $first_deadline->getAuthorTypeId()) {
                 $assign_to_episode = true;
             } else {
                 /* Otherwise, check if we are past the deadline for the
                  * previous deadline. */
                 $previous_author_type_id = DeadlineTable::getInstance()->getFirstAuthorTypeIdBySubredditWhereDeadlineIsGreaterThan($deadline_rules[$assignment->getAuthorTypeId()], $episode->getSubredditId());
                 $past_deadline_for_previous = strtotime($episode->getReleaseDate()) - $deadline_rules[$previous_author_type_id] <= time();
                 if ($past_deadline_for_previous) {
                     $assign_to_episode = true;
                 }
             }
             if ($assign_to_episode) {
                 $episode->setEpisodeAssignmentId($assignment->getIncremented());
                 $episode->save();
                 $newly_assigned_assignments[] = $assignment;
             }
         }
     }
     // We send the emails for the current deadline we're checking.
     foreach ($passed_deadline_assignments as $assignment) {
         $this->sendEmailAboutPassedDeadline($assignment->getSfGuardUserId(), $assignment->getEpisodeId());
     }
     foreach ($newly_assigned_assignments as $assignment) {
         $episode = $assignment->getEpisode();
         $release_date = strtotime($episode->getReleaseDate());
         $seconds = $deadline_rules[$assignment->getAuthorTypeId()];
         $deadline = $release_date - $seconds;
         $this->sendEmailAboutNewAssignment($assignment->getSfGuardUserId(), $episode->getIncremented(), $deadline);
     }
 }
 /**
  * This tests whether the
  * EpisodeAssignmentTable::getFirstByUserAuthorTypeAndSubreddit() function
  * retrieves the correct EpisodeAssignment for a particular User in a
  * Subreddit based on the AuthorType used in the EpisodeAssignment.  Users
  * can sign up for one Episode per AuthorType in each Subreddit, which means
  * future Episodes (sicne we don't want the existence of past episode to
  * disqualify Users from ever signing up again).
  */
 public function testGetFirstByUserAuthorTypeAndSubreddit()
 {
     // Create two episode assignments: one for a past Episode, one for a future
     $subreddit = new Subreddit();
     $subreddit->setName(rand(0, 10000));
     $subreddit->setDomain(rand(0, 10000));
     $subreddit->save();
     $user = new sfGuardUser();
     $user->setUsername(rand(0, 10000));
     $user->setEmailAddress(rand(0, 10000));
     $user->setisValidated(1);
     $user->save();
     $first = AuthorTypeTable::getInstance()->findOneBy('type', 'squid');
     $understudy = AuthorTypeTable::getInstance()->findOneBy('type', 'shark');
     $this->assertTrue($first instanceof AuthorType);
     $this->assertNotEquals(null, $first->getIncremented());
     $this->assertTrue($understudy instanceof AuthorType);
     $this->assertNotEquals(null, $understudy->getIncremented());
     $deadline_one = new Deadline();
     $deadline_one->setSeconds(100);
     $deadline_one->setAuthorType($first);
     $deadline_one->setSubreddit($subreddit);
     $deadline_one->save();
     $deadline_two = new Deadline();
     $deadline_two->setSeconds(0);
     $deadline_two->setAuthorType($understudy);
     $deadline_two->setSubreddit($subreddit);
     $deadline_two->save();
     $episode_one = new Episode();
     $episode_one->setReleaseDate(date('Y-m-d H:i:s', time() + 200000));
     $episode_one->setSubreddit($subreddit);
     $episode_one->save();
     $episode_two = new Episode();
     $episode_two->setReleaseDate(date('Y-m-d H:i:s', time() + 100000));
     $episode_two->setSubreddit($subreddit);
     $episode_two->save();
     $episode_three = new Episode();
     $episode_three->setReleaseDate(date('Y-m-d H:i:s', time() + 300000));
     $episode_three->setSubreddit($subreddit);
     $episode_three->save();
     $assignment_one = new EpisodeAssignment();
     $assignment_one->setEpisode($episode_one);
     $assignment_one->setSfGuardUser($user);
     $assignment_one->setAuthorType($first);
     $assignment_one->save();
     $assignment_two = new EpisodeAssignment();
     $assignment_two->setEpisode($episode_two);
     $assignment_two->setSfGuardUser($user);
     $assignment_two->setAuthorType($understudy);
     $assignment_two->save();
     /* There should only be one Episode Assignment for future episodes per 
      * authortype per subreddit, so saving the third assignment should fail
      * --- this is covered more in EpisodeAssignmentTest.phop
      */
     $exception_thrown = false;
     $assignment_three = new EpisodeAssignment();
     $assignment_three->setEpisode($episode_three);
     $assignment_three->setSfGuardUser($user);
     $assignment_three->setAuthorType($first);
     try {
         $assignment_three->save();
     } catch (Exception $exception) {
         $exception_thrown = true;
         $this->assertEquals(102, $exception->getCode());
         unset($exception);
     }
     $this->assertTrue($exception_thrown);
     /* Since we can trust that only one assignment per authortype per user
      * per subreddit exists for future episodes (based on the failure to
      * save $assignment_three), we check now to ensure that the
      * getFirstByUserAuthorTypeAndSubreddit() function returns a valid
      * EpisodeAssignment.
      */
     $test_one = EpisodeAssignmentTable::getInstance()->getFirstByUserAuthorTypeAndSubreddit($assignment_one->getAuthorTypeId(), $assignment_one->getSfGuardUserId(), $assignment_one->getEpisode()->getSubredditId());
     $test_two = EpisodeAssignmentTable::getInstance()->getFirstByUserAuthorTypeAndSubreddit($assignment_two->getAuthorTypeId(), $assignment_two->getSfGuardUserId(), $assignment_two->getEpisode()->getSubredditId());
     $this->assertEquals($test_one->getIncremented(), $assignment_one->getIncremented());
     $this->assertEquals($test_two->getIncremented(), $assignment_two->getIncremented());
     $assignment_one->delete();
     $assignment_two->delete();
     $episode_one->delete();
     $episode_two->delete();
     $episode_three->delete();
     $deadline_one->delete();
     $deadline_two->delete();
     $user->delete();
     $subreddit->delete();
 }
 public function getEpisodeAssignments()
 {
     return EpisodeAssignmentTable::getInstance()->getAllByEpisodeId($this->getIncremented());
 }
 public function validateUpload($payload, sfWebRequest $request = null)
 {
     if (!$request->hasParameter('id_hash')) {
         throw new sfException('No "id_hash" argument found.', 400);
     }
     if (!$request->hasParameter('subreddit_id')) {
         throw new sfException('No "subreddit_id" argument found.', 400);
     }
     $content_file = $request->getFiles('filename');
     $this->_temporary_file_location = array_key_exists('tmp_name', $content_file) ? $content_file['tmp_name'] : null;
     $this->_nice_filename = array_key_exists('name', $content_file) ? $content_file['name'] : null;
     $id_hash = $request->getParameter('id_hash');
     $subreddit_id = $request->getParameter('subreddit_id');
     $episode_assignment = EpisodeAssignmentTable::getInstance()->getByIdHash($id_hash, $subreddit_id);
     if (!$episode_assignment) {
         throw new sfException('No assignment found for given id hash in the subreddit', 404);
     }
     /* Check that the Episode is assigned to the episode_assignment and that
      * the current user is the user of the EpisodeAssignment or otherwise
      * has permission to upload. */
     if (!$this->getUser()->isSuperAdmin() && $episode_assignment->getIncremented() != $episode_assignment->getEpisode()->getEpisodeAssignmentId()) {
         throw new sfException('Your user does not have permissions to ' . 'upload audio for this Episode.', 403);
     }
     $this->object = $episode_assignment->getEpisode();
 }