/**
  * @see Form::readParameters()
  */
 public function readParameters()
 {
     parent::readParameters();
     // get contest
     if (!$this->solutionObj->isCommentable()) {
         throw new PermissionDeniedException();
     }
 }
 /**
  * @see Form::assignVariables()
  */
 public function assignVariables()
 {
     parent::assignVariables();
     // display branding
     require_once WCF_DIR . 'lib/util/ContestUtil.class.php';
     ContestUtil::assignVariablesBranding();
     // save ratings
     if ($this->solutionObj->isRateable()) {
         require_once WCF_DIR . 'lib/form/ContestSolutionRatingUpdateForm.class.php';
         new ContestSolutionRatingUpdateForm($this->solutionObj);
     }
     // init form
     if ($this->action == 'edit') {
         require_once WCF_DIR . 'lib/form/ContestSolutionCommentEditForm.class.php';
         new ContestSolutionCommentEditForm($this->solutionObj);
     } else {
         if ($this->entry->isCommentable()) {
             require_once WCF_DIR . 'lib/form/ContestSolutionCommentAddForm.class.php';
             new ContestSolutionCommentAddForm($this->solutionObj);
         }
     }
     if (!$this->entry->enableOpenSolution && $this->entry->state != 'closed' && ($this->entry->state != 'scheduled' || !($this->entry->fromTime < TIME_NOW && TIME_NOW < $this->entry->untilTime))) {
         WCF::getTPL()->append('userMessages', '<p class="info">' . WCF::getLanguage()->get('wcf.contest.enableOpenSolution.info') . '</p>');
     }
     if ($this->entry->enableParticipantCheck) {
         WCF::getTPL()->append('userMessages', '<p class="info">' . WCF::getLanguage()->get('wcf.contest.enableParticipantCheck.info') . '</p>');
     }
     $this->sidebar->assignVariables();
     WCF::getTPL()->assign(array('entry' => $this->entry, 'solutionObj' => $this->solutionObj, 'contestID' => $this->contestID, 'solutionID' => $this->solutionID, 'userID' => $this->entry->userID, 'comments' => $this->commentList->getObjects(), 'ratings' => $this->ratingList->getObjects(), 'todos' => $this->todoList ? $this->todoList->getObjects() : array(), 'templateName' => $this->templateName, 'allowSpidersToIndexThisPage' => true, 'attachments' => $this->attachments, 'contestmenu' => ContestMenu::getInstance()));
 }
 /**
  * @see DatabaseObjectList::readObjects()
  */
 public function readObjects()
 {
     $userID = WCF::getUser()->userID;
     $userID = $userID ? $userID : -1;
     $sql = "SELECT\t\t" . (!empty($this->sqlSelects) ? $this->sqlSelects . ',' : '') . "\n\t\t\t\t\tavatar_table.*,\n\t\t\t\t\tcontest_participant.*,\n\t\t\t\t\tcontest_solution.*,\n\t\t\t\t\tcontest_price.priceID,\n\t\t\t\t\tgroup_table.groupName,\n\t\t\t\t\tuser_table.username,\n\t\t\t\t\tscore,\n\t\t\t\t\tcount,\n\t\t\t\t\tjuryscore,\n\t\t\t\t\tjurycount,\n\t\t\t\t\tmyscore\n\t\t\tFROM\t\twcf" . WCF_N . "_contest_solution contest_solution\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_contest_participant contest_participant\n\t\t\tON\t\tcontest_participant.participantID = contest_solution.participantID\n\t\t\t\n\t\t\tLEFT JOIN (\n\t\t\t\tSELECT\t\tpriceID,\n\t\t\t\t\t\tsolutionID\n\t\t\t\tFROM\t\twcf" . WCF_N . "_contest_price contest_solution\n\t\t\t\t" . (!empty($this->sqlConditions) ? "WHERE " . $this->sqlConditions : '') . "\n\t\t\t\t\n\t\t\t) contest_price\tON (contest_price.solutionID = contest_solution.solutionID)\n\t\t\t\n\t\t\tLEFT JOIN (\n\t\t\t\t-- total score\n\t\t\t\tSELECT\t\tcontest_solution.solutionID,\n\t\t\t\t\t\tAVG(IF(score > 5, 5, score)) AS score,\n\t\t\t\t\t\tAVG(score) AS realscore,\n\t\t\t\t\t\tCOUNT(DISTINCT contest_solution_rating.userID) AS count\n\t\t\t\tFROM\t\twcf" . WCF_N . "_contest_solution contest_solution\n\t\t\t\tINNER JOIN\twcf" . WCF_N . "_contest_solution_rating contest_solution_rating\n\t\t\t\tON\t\tcontest_solution.solutionID = contest_solution_rating.solutionID\n\t\t\t\t" . (!empty($this->sqlConditions) ? "WHERE " . $this->sqlConditions : '') . "\n\t\t\t\tGROUP BY\tcontest_solution.solutionID\n\t\t\t\tHAVING\t\tNOT ISNULL(contest_solution.solutionID)\n\t\t\t) x ON contest_solution.solutionID = x.solutionID\n\t\t\t\n\t\t\tLEFT JOIN (\n\t\t\t\t-- jury score\n\t\t\t\tSELECT\t\tcontest_solution.solutionID,\n\t\t\t\t\t\tAVG(IF(score > 5, 5, score)) AS juryscore,\n\t\t\t\t\t\tAVG(score) AS juryrealscore,\n\t\t\t\t\t\tCOUNT(DISTINCT contest_solution_rating.userID) AS jurycount\n\t\t\t\tFROM\t\twcf" . WCF_N . "_contest_solution contest_solution\n\t\t\t\tINNER JOIN\twcf" . WCF_N . "_contest_solution_rating contest_solution_rating\n\t\t\t\tON\t\tcontest_solution.solutionID = contest_solution_rating.solutionID\n\t\t\t\tINNER JOIN (\n\t\t\t\t\tSELECT\t\tcontestID,\n\t\t\t\t\t\t\tIF(contest_jury.userID > 0, contest_jury.userID, user_to_groups.userID) AS userID\n\t\t\t\t\tFROM\t\twcf" . WCF_N . "_contest_jury contest_jury\n\t\t\t\t\tLEFT JOIN\twcf" . WCF_N . "_user_to_groups user_to_groups USING(groupID)\n\t\t\t\t\tWHERE\t\tcontest_jury.userID > 0\n\t\t\t\t\tAND\t\tcontest_jury.state = 'accepted'\n\t\t\t\t) contest_jury\n\t\t\t\tON\t\tcontest_jury.contestID = contest_solution.contestID\n\t\t\t\tAND\t\tcontest_jury.userID = contest_solution_rating.userID\n\t\t\t\t" . (!empty($this->sqlConditions) ? "WHERE (" . $this->sqlConditions . ')' : '') . "\n\t\t\t\tGROUP BY\tcontest_solution.solutionID\n\t\t\t\tHAVING\t\tNOT ISNULL(contest_solution.solutionID)\n\t\t\t) y ON contest_solution.solutionID = y.solutionID\n\t\t\t\n\t\t\tLEFT JOIN (\n\t\t\t\t-- my score\n\t\t\t\tSELECT\t\tcontest_solution.solutionID,\n\t\t\t\t\t\tAVG(IF(score > 5, 5, score)) AS myscore,\n\t\t\t\t\t\tAVG(score) AS myrealscore\n\t\t\t\tFROM\t\twcf" . WCF_N . "_contest_solution contest_solution\n\t\t\t\tINNER JOIN\twcf" . WCF_N . "_contest_solution_rating contest_solution_rating\n\t\t\t\tON\t\tcontest_solution.solutionID = contest_solution_rating.solutionID\n\t\t\t\tWHERE \t\tcontest_solution_rating.userID = " . $userID . "\n\t\t\t\t" . (!empty($this->sqlConditions) ? "AND (" . $this->sqlConditions . ')' : '') . "\n\t\t\t\tGROUP BY\tcontest_solution.solutionID\n\t\t\t\tHAVING\t\tNOT ISNULL(contest_solution.solutionID)\n\t\t\t) z ON contest_solution.solutionID = z.solutionID\n\t\t\t\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_user user_table\n\t\t\tON\t\t(user_table.userID = contest_participant.userID)\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_avatar avatar_table\n\t\t\tON\t\t(avatar_table.avatarID = user_table.avatarID)\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_group group_table\n\t\t\tON\t\t(group_table.groupID = contest_participant.groupID)\n\t\t\t" . $this->sqlJoins . "\n\n\t\t\tWHERE\t\t(" . ContestSolution::getStateConditions() . ")\n\t\t\t" . (!empty($this->sqlConditions) ? "AND " . $this->sqlConditions : '') . "\n\t\t\t" . (!empty($this->sqlOrderBy) ? "ORDER BY " . $this->sqlOrderBy : '');
     $result = WCF::getDB()->sendQuery($sql, $this->sqlLimit, $this->sqlOffset);
     while ($row = WCF::getDB()->fetchArray($result)) {
         $this->solutions[] = new ViewableContestSolution(null, $row);
     }
 }
 /**
  * @see ContestNotificationInterface::getRecipients()
  */
 public function getRecipients()
 {
     // TODO: read all contest solutions which do not have price yet, and where the prices did not expire
     return;
     $ids = array();
     require_once WCF_DIR . 'lib/data/contest/solution/ContestSolution.class.php';
     $winners = ContestSolution::getWinners($this->contestID);
     foreach ($winners as $solution) {
         if ($solution->hasPrice() == false) {
             if ($solution->isPriceExpired() && $solution->isOwner() == false) {
                 continue;
             }
             $ids = array_merge($ids, $this->getInstance()->getOwner()->getUserIDs());
         }
     }
     return array_unique($ids);
 }
 /**
  * by which solution/winner is this price pickable
  *
  * @return 	ContestSolution|null		$solution
  */
 public function pickableByWinner()
 {
     if (WCF::getUser()->userID == 0 || $this->hasWinner()) {
         return null;
     }
     $contest = Contest::getInstance($this->contestID);
     if ($contest->state != 'closed') {
         return null;
     }
     require_once WCF_DIR . 'lib/data/contest/solution/ContestSolution.class.php';
     $winners = ContestSolution::getWinners($this->contestID);
     foreach ($winners as $solution) {
         if ($solution->hasPrice() == false) {
             if ($solution->pickTime < TIME_NOW && $solution->isOwner() == false) {
                 continue;
             }
             return $solution->isOwner() ? $solution : null;
         }
     }
     return null;
 }
 /**
  * @see DatabaseObject::handleData()
  */
 protected function handleData($data)
 {
     parent::handleData($data);
     $this->owner = new ContestOwner($data, $this->userID, $this->groupID);
 }
    /**
     * if priceExpireSeconds is set, the solution will have a maximum time to choose a price
     * if no price is chosen in this period, the next winner can take a price
     */
    public function updatePickTimes()
    {
        require_once WCF_DIR . 'lib/data/contest/solution/ContestSolution.class.php';
        // get first + latest pick
        $firstPick = $lastPick = 0;
        // update cache
        ContestSolution::resetWinners($this->contestID);
        foreach (ContestSolution::getWinners($this->contestID) as $solution) {
            if ($solution->hasPrice()) {
                $lastPick = max($lastPick, $solution->pickTime);
            } else {
                $firstPick = min($firstPick, $solution->pickTime);
            }
        }
        $timestamp = 0;
        // first run? then start from the current date
        if ($firstPick == 0) {
            $firstPick = TIME_NOW;
        }
        // no price was picked yet, so start from the beginning
        if ($lastPick == 0) {
            $timestamp = $firstPick;
        } else {
            $timestamp = $lastPick;
        }
        $nextSolution = null;
        foreach (ContestSolution::getWinners($this->contestID) as $solution) {
            // contest already has price?
            // pick time has passed since the winner did not choose a price in time
            if ($solution->hasPrice() || $solution->pickTime && $solution->pickTime < TIME_NOW) {
                continue;
            }
            // remember first valid solution
            if ($nextSolution === null) {
                $nextSolution = $solution;
            }
            // no change, skip database update
            $save = $this->priceExpireSeconds == 0 ? 0 : $timestamp;
            // user will have xx hours from now on
            $timestamp += $this->priceExpireSeconds;
            // database update, if needed
            if ($solution->pickTime != $save) {
                $solution->getEditor()->updatePickTime($save);
            }
        }
        // notify next winner
        if ($nextSolution) {
            // use notification api
            if (false) {
                require_once WCF_DIR . 'lib/data/contest/event/ContestEventEditor.class.php';
                $owner = $nextSolution->getOwner();
                ContestEventEditor::create($contestID, $owner->userID, $owner->groupID, 'ContestPriceExpire', array('priceID' => $priceID, 'owner' => $owner->getName()));
            }
            // use mail if participant is single user
            // TODO: remove after notification api is implemented
            // TODO: missing translation
            if ($nextSolution->getOwner()->userID) {
                $mail = new Mail($nextSolution->getOwner()->email, 'easy-coding Gewinnspiel - du hast gewonnen', 'Hallo ' . $nextSolution->getOwner()->getName() . ',
du gehörst zu den glücklichen Gewinnern beim easy-coding Gewinnspiel.
Bitte suche dir innerhalb von 24h auf folgender Seite einen Preis aus: ' . PAGE_URL . '/index.php?page=ContestPrice&contestID=' . $this->contestID . '

Vielen Dank für die Teilnahme beim Gewinnspiel,

Torben Brodt');
                $mail->addBCC(MAIL_ADMIN_ADDRESS);
                $mail->send();
            }
        }
        return $nextSolution;
    }