Index: trunk/extensions/Contest/specials/SpecialContestant.php |
— | — | @@ -246,7 +246,7 @@ |
247 | 247 | |
248 | 248 | $out->addHTML( Html::element( 'p', array(), $message ) ); |
249 | 249 | |
250 | | - foreach ( ContestSettings::get( 'votevalues' ) as $value ) { |
| 250 | + foreach ( ContestSettings::get( 'voteValues' ) as $value ) { |
251 | 251 | $attribs = array( |
252 | 252 | 'type' => 'radio', |
253 | 253 | 'value' => $value, |
Index: trunk/extensions/Contest/Contest.settings.php |
— | — | @@ -28,9 +28,10 @@ |
29 | 29 | */ |
30 | 30 | protected static function getDefaultSettings() { |
31 | 31 | return array( |
32 | | - 'votevalues' => range( 0, 5 ), |
| 32 | + 'voteValues' => range( 0, 5 ), |
33 | 33 | 'enableTopLink' => true, |
34 | 34 | 'submissionDomains' => array( 'github.com', 'gitorious.org' ), |
| 35 | + 'reminderJobSize' => 50 |
35 | 36 | ); |
36 | 37 | } |
37 | 38 | |
Index: trunk/extensions/Contest/Contest.php |
— | — | @@ -63,6 +63,7 @@ |
64 | 64 | $wgAutoloadClasses['ContestComment'] = dirname( __FILE__ ) . '/includes/ContestComment.php'; |
65 | 65 | $wgAutoloadClasses['ContestContestant'] = dirname( __FILE__ ) . '/includes/ContestContestant.php'; |
66 | 66 | $wgAutoloadClasses['ContestDBObject'] = dirname( __FILE__ ) . '/includes/ContestDBObject.php'; |
| 67 | +$wgAutoloadClasses['ContestReminderJob'] = dirname( __FILE__ ) . '/includes/ContestReminderJob.php'; |
67 | 68 | $wgAutoloadClasses['ContestUtils'] = dirname( __FILE__ ) . '/includes/ContestUtils.php'; |
68 | 69 | $wgAutoloadClasses['ContestVote'] = dirname( __FILE__ ) . '/includes/ContestVote.php'; |
69 | 70 | |
Index: trunk/extensions/Contest/INSTALL |
— | — | @@ -40,3 +40,25 @@ |
41 | 41 | You should NOT modify the settings file, but can have a look at it to get an idea of |
42 | 42 | how to use the settings, in case the below descriptions do not suffice. |
43 | 43 | |
| 44 | +{| class="wikitable sortable" |
| 45 | +! Name |
| 46 | +! Type |
| 47 | +! Default |
| 48 | +! Description |
| 49 | +|- |
| 50 | +| votevalues |
| 51 | +| array of integer |
| 52 | +| range( 0, 5 ) |
| 53 | +| Values that can be voted by judges on a participant |
| 54 | +|- |
| 55 | +| enableTopLink |
| 56 | +| boolean |
| 57 | +| True |
| 58 | +| Enable display of the top link to Special:MyContests |
| 59 | +|- |
| 60 | +| submissionDomains |
| 61 | +| array of string |
| 62 | +| array( 'github.com', 'gitorious.org' ) |
| 63 | +| Domains on which submissions can be placed |
| 64 | +|} |
| 65 | + |
Index: trunk/extensions/Contest/RELEASE-NOTES |
— | — | @@ -5,8 +5,13 @@ |
6 | 6 | |
7 | 7 | |
8 | 8 | === Version 0.1 === |
9 | | -2011-xx-xx |
| 9 | +2011-10-xx |
10 | 10 | |
11 | 11 | Initial release with these features: |
12 | 12 | |
13 | | -* |
\ No newline at end of file |
| 13 | +* Admin interface for managing contests and their challenges. |
| 14 | +* Landing and signup pages for each contest. |
| 15 | +* Personal contest list and submission interface for each user. |
| 16 | +* Summary pages per contest listing contestants, which can be filtered and sorted. |
| 17 | +* Judging interface that allows for rating and commenting on each participant. |
| 18 | +* All contests, challenges, contestants, comments and votes can be queried and exported via the API. |
\ No newline at end of file |
Index: trunk/extensions/Contest/includes/ContestReminderJob.php |
— | — | @@ -0,0 +1,45 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Contest reminder job for email reminders. |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file ContestReminderJob.php |
| 10 | + * @ingroup Contest |
| 11 | + * |
| 12 | + * @licence GNU GPL v3 or later |
| 13 | + * @author Jeroen De Dauw < jeroendedauw@gmail.com > |
| 14 | + */ |
| 15 | +class ContestReminderJob extends Job { |
| 16 | + |
| 17 | + /** |
| 18 | + * Constructor. |
| 19 | + * |
| 20 | + * @param Title $title |
| 21 | + * @param array $params |
| 22 | + * * contestants, array of ContestContestant, required |
| 23 | + * * contest, Contest, required |
| 24 | + */ |
| 25 | + public function __construct( Title $title, array $params ) { |
| 26 | + parent::__construct( 'ContestReminderJob', $title, $params ); |
| 27 | + $this->params['emailText'] = ContestUtils::getParsedArticleContent( $this->params['reminder_email'] ); |
| 28 | + $this->params['daysLeft'] = $this->params['contest']->getDaysLeft(); |
| 29 | + } |
| 30 | + |
| 31 | + /** |
| 32 | + * Execute the job. |
| 33 | + * |
| 34 | + * @return bool |
| 35 | + */ |
| 36 | + public function run() { |
| 37 | + foreach ( $this->params['contestants'] as /* ContestContestant */ $contestant ) { |
| 38 | + $contestant->sendReminderEmail( $this->params['emailText'], array( |
| 39 | + 'daysLeft' => $this->params['daysLeft'], |
| 40 | + ) ); |
| 41 | + } |
| 42 | + |
| 43 | + return true; |
| 44 | + } |
| 45 | + |
| 46 | +} |
Index: trunk/extensions/Contest/includes/ContestContestant.php |
— | — | @@ -515,11 +515,14 @@ |
516 | 516 | * |
517 | 517 | * @return Status |
518 | 518 | */ |
519 | | - public function sendReminderEmail() { |
| 519 | + public function sendReminderEmail( $emailText, array $params = array() ) { |
520 | 520 | global $wgPasswordSender, $wgPasswordSenderName; |
521 | 521 | |
522 | | - $title = wfMsgExt( 'contest-email-reminder-title', 'parsemag', $this->getContest()->getDaysLeft() ); |
523 | | - $emailText = ContestUtils::getParsedArticleContent( $this->getContest()->getField( 'reminder_email' ) ); |
| 522 | + if ( !array_key_exists( 'daysLeft', $params ) ) { |
| 523 | + $params['daysLeft'] = $this->getContest()->getDaysLeft(); |
| 524 | + } |
| 525 | + |
| 526 | + $title = wfMsgExt( 'contest-email-reminder-title', 'parsemag', $params['daysLeft'] ); |
524 | 527 | $user = $this->getUser(); |
525 | 528 | $sender = $wgPasswordSender; |
526 | 529 | $senderName = $wgPasswordSenderName; |
Index: trunk/extensions/Contest/api/ApiMailContestants.php |
— | — | @@ -60,34 +60,29 @@ |
61 | 61 | $conditions = array(); |
62 | 62 | |
63 | 63 | if ( count( $contestIds ) > 0 ) { |
64 | | - $conditions[] = array( 'contest_id' => $contestIds ); |
| 64 | + $conditions['contest_id'] = $contestIds; |
65 | 65 | } |
66 | 66 | |
67 | 67 | if ( count( $challengeIds ) > 0 ) { |
68 | | - $conditions[] = array( 'challenge_id' => $challengeIds ); |
| 68 | + $conditions['challenge_id'] = $challengeIds; |
69 | 69 | } |
70 | 70 | |
71 | 71 | if ( !is_null( $params['ids'] ) && count( $params['ids'] ) > 0 ) { |
72 | | - $conditions[] = array( 'id' => $params['ids'] ); |
| 72 | + $conditions['id'] = $params['ids']; |
73 | 73 | } |
74 | 74 | |
75 | 75 | $contestants = ContestContestant::s()->select( 'email', $conditions ); |
76 | 76 | |
77 | 77 | if ( $contestants !== false && count( $contestants ) > 0 ) { |
78 | | - $recipients = array(); |
| 78 | + $setSize = ContestSettings::get( 'reminderJobSize' ); |
| 79 | + $limit = count( $contestants ) - $setSize; |
79 | 80 | |
80 | | - foreach ( $contestants as /* ContestContestant */ $contestant ) { |
81 | | - $recipients[] = new MailAddress( $contestant->getField( 'email' ) ); |
| 81 | + for ( $i = 0; $i <= $limit; $i += $setSize ) { |
| 82 | + $this->createReminderJob( array_splice( $contestants, $i, $setSize ) ); |
82 | 83 | } |
83 | | - |
84 | | - $everythingOk = $this->sendReminderEmail( |
85 | | - ContestUtils::getParsedArticleContent( $params['page'] ), // TODO: have some magic here for params such as daysleft |
86 | | - $recipients, |
87 | | - array( 'daysleft' => $this->getContest()->getDaysLeft() ) |
88 | | - ); |
89 | 84 | } |
90 | 85 | else { |
91 | | - // TODO: error |
| 86 | + $everythingOk = false; |
92 | 87 | } |
93 | 88 | |
94 | 89 | $this->getResult()->addValue( |
— | — | @@ -95,58 +90,42 @@ |
96 | 91 | 'success', |
97 | 92 | $everythingOk |
98 | 93 | ); |
| 94 | + |
| 95 | + if ( $everythingOk ) { |
| 96 | + $this->getResult()->addValue( |
| 97 | + null, |
| 98 | + 'contestantcount', |
| 99 | + count( $contestants ) |
| 100 | + ); |
| 101 | + } |
99 | 102 | } |
100 | 103 | |
101 | | - /** |
102 | | - * Send a reminder email. |
103 | | - * |
104 | | - * @since 0.1 |
105 | | - * |
106 | | - * @param string $emailText |
107 | | - * @param array $recipients |
108 | | - * @param array $params |
109 | | - * |
110 | | - * @return Status |
111 | | - */ |
112 | | - public function sendReminderEmail( $emailText, array /* of MailAddress */ $recipients, array $params ) { |
113 | | - global $wgPasswordSender, $wgPasswordSenderName; |
114 | | - |
115 | | - $title = wfMsgExt( 'contest-email-reminder-title', 'parsemag', $params['daysleft'] ); |
116 | | - $sender = $wgPasswordSender; |
117 | | - $senderName = $wgPasswordSenderName; |
118 | | - |
119 | | - wfRunHooks( 'ContestBeforeReminderEmail', array( &$this, &$title, &$emailText, &$recipients, &$sender, &$senderName ) ); |
120 | | - |
121 | | - return UserMailer::send( |
122 | | - $recipients, |
123 | | - new MailAddress( $sender, $senderName ), |
124 | | - $title, |
125 | | - $emailText, |
126 | | - null, |
127 | | - 'text/html; charset=ISO-8859-1' |
| 104 | + protected function createReminderJob( array /* of ContestContestant */ $contestants ) { |
| 105 | + $job = new ContestReminderJob( |
| 106 | + Title::newMainPage(), // WTF does this require a title for?? |
| 107 | + array( |
| 108 | + 'contest' => $contestants[0]->getContest(), |
| 109 | + 'contestants' => $contestants |
| 110 | + ) |
128 | 111 | ); |
| 112 | + $job->insert(); |
129 | 113 | } |
130 | | - /* |
| 114 | + |
131 | 115 | public function needsToken() { |
132 | 116 | return true; |
133 | 117 | } |
134 | 118 | |
135 | | - public function getTokenSalt() { |
136 | | - $params = $this->extractRequestParams(); |
137 | | - return 'deletecontest' . implode( '|', $params['ids'] ); // TODO |
138 | | - } |
139 | | - |
140 | 119 | public function mustBePosted() { |
141 | 120 | return true; |
142 | 121 | } |
143 | | - */ |
| 122 | + |
144 | 123 | public function getAllowedParams() { |
145 | 124 | return array( |
146 | | - 'page' => array( |
147 | | - ApiBase::PARAM_TYPE => 'string', |
148 | | - ApiBase::PARAM_REQUIRED => true, |
149 | | - ApiBase::PARAM_ISMULTI => false, |
150 | | - ), |
| 125 | +// 'page' => array( |
| 126 | +// ApiBase::PARAM_TYPE => 'string', |
| 127 | +// ApiBase::PARAM_REQUIRED => true, |
| 128 | +// ApiBase::PARAM_ISMULTI => false, |
| 129 | +// ), |
151 | 130 | 'ids' => array( |
152 | 131 | ApiBase::PARAM_TYPE => 'integer', |
153 | 132 | ApiBase::PARAM_REQUIRED => false, |
— | — | @@ -158,7 +137,7 @@ |
159 | 138 | ApiBase::PARAM_ISMULTI => true, |
160 | 139 | ), |
161 | 140 | 'contestnames' => array( |
162 | | - ApiBase::PARAM_TYPE => 'integer', |
| 141 | + ApiBase::PARAM_TYPE => 'string', |
163 | 142 | ApiBase::PARAM_REQUIRED => false, |
164 | 143 | ApiBase::PARAM_ISMULTI => true, |
165 | 144 | ), |
— | — | @@ -168,7 +147,7 @@ |
169 | 148 | ApiBase::PARAM_ISMULTI => true, |
170 | 149 | ), |
171 | 150 | 'challengetitles' => array( |
172 | | - ApiBase::PARAM_TYPE => 'integer', |
| 151 | + ApiBase::PARAM_TYPE => 'string', |
173 | 152 | ApiBase::PARAM_REQUIRED => false, |
174 | 153 | ApiBase::PARAM_ISMULTI => true, |
175 | 154 | ), |
— | — | @@ -178,7 +157,7 @@ |
179 | 158 | |
180 | 159 | public function getParamDescription() { |
181 | 160 | return array( |
182 | | - 'page' => 'Name of the page from which to pull content for the email body', |
| 161 | +// 'page' => 'Name of the page from which to pull content for the email body', |
183 | 162 | 'ids' => 'The IDs of the contestants to mail', |
184 | 163 | 'contestids' => 'The IDs of the contests where of the contestants should be mailed', |
185 | 164 | 'contestnames' => 'The names of the contests where of the contestants should be mailed', |