1 | <?php |
||
2 | // This file is part of BOINC. |
||
3 | // http://boinc.berkeley.edu |
||
4 | // Copyright (C) 2015 University of California |
||
5 | // |
||
6 | // BOINC is free software; you can redistribute it and/or modify it |
||
7 | // under the terms of the GNU Lesser General Public License |
||
8 | // as published by the Free Software Foundation, |
||
9 | // either version 3 of the License, or (at your option) any later version. |
||
10 | // |
||
11 | // BOINC is distributed in the hope that it will be useful, |
||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
14 | // See the GNU Lesser General Public License for more details. |
||
15 | // |
||
16 | // You should have received a copy of the GNU Lesser General Public License |
||
17 | // along with BOINC. If not, see <http://www.gnu.org/licenses/>. |
||
18 | |||
19 | require_once('../inc/boinc_db.inc'); |
||
20 | require_once('../inc/email.inc'); |
||
21 | require_once('../inc/profile.inc'); |
||
22 | |||
23 | if (!defined('UOTD_THRESHOLD')) { |
||
24 | define('UOTD_THRESHOLD', 7); |
||
25 | // email sysadmin if # of UOTD candidates falls below this |
||
26 | } |
||
27 | |||
28 | function uotd_thumbnail($profile, $user) { |
||
29 | if ($profile->has_picture) { |
||
30 | return "<a href=\"".url_base()."view_profile.php?userid=$user->id\"><img border=0 vspace=4 hspace=8 align=left src=\"".profile_thumb_url($user->id)."\" alt=\"".tra("User profile")."\"></a>"; |
||
31 | } else { |
||
32 | return ""; |
||
33 | } |
||
34 | } |
||
35 | |||
36 | // show UOTD in a small box |
||
37 | // |
||
38 | function show_uotd($profile) { |
||
39 | $user = BoincUser::lookup_id($profile->userid); |
||
40 | echo uotd_thumbnail($profile, $user); |
||
41 | echo user_links($user, BADGE_HEIGHT_MEDIUM)."<br>"; |
||
42 | $x = output_transform($profile->response1); |
||
43 | $x = sanitize_tags($x); |
||
44 | echo sub_sentence($x, ' ', 150, true); |
||
45 | } |
||
46 | |||
47 | // return the last UOTD profile, or null |
||
48 | // |
||
49 | function get_current_uotd() { |
||
50 | $profiles = BoincProfile::enum("uotd_time is not NULL and uotd_time>0", "ORDER BY uotd_time DESC LIMIT 1"); |
||
51 | if (sizeof($profiles)) { |
||
52 | return $profiles[0]; |
||
53 | } |
||
54 | return null; |
||
55 | } |
||
56 | |||
57 | // Select a (possibly new) UOTD |
||
58 | // |
||
59 | function select_uotd($force_new = false) { |
||
60 | echo gmdate("F d Y", time())." UTC: Starting\n"; |
||
61 | $current_uotd = get_current_uotd(); |
||
62 | if ($current_uotd && !$force_new) { |
||
63 | $assigned = getdate($current_uotd->uotd_time); |
||
64 | $now = getdate(time()); |
||
65 | if ($assigned['mday'] == $now['mday']) { |
||
66 | $user = BoincUser::lookup_id($current_uotd->userid); |
||
67 | echo "Already have UOTD for today\n"; |
||
68 | generate_uotd_gadget($current_uotd, $user); |
||
69 | exit(); |
||
0 ignored issues
–
show
|
|||
70 | } |
||
71 | } |
||
72 | if ($force_new) { |
||
73 | echo "Forcing new UOTD\n"; |
||
74 | } |
||
75 | |||
76 | // get a list of profiles that have been 'approved' for UOTD, |
||
77 | // using a project-specific query if supplied in project.inc |
||
78 | // |
||
79 | if (function_exists('uotd_candidates_query')) { |
||
80 | $query = uotd_candidates_query(); |
||
81 | echo "using project supplied candidates_query\n"; |
||
82 | } else { |
||
83 | $query = default_uotd_candidates_query(); |
||
84 | echo "using default candidates_query\n"; |
||
85 | } |
||
86 | $db = BoincDb::get(); |
||
87 | $result = $db->do_query($query); |
||
88 | |||
89 | // If the number of approved profiles dips below a threshold, |
||
90 | // email the sys admin every time we pick a new one. |
||
91 | // |
||
92 | if (defined('UOTD_ADMIN_EMAIL') |
||
93 | && $result |
||
94 | && $result->num_rows < UOTD_THRESHOLD |
||
95 | ) { |
||
96 | echo "approved candidates for UOTD under UOTD_THRESHOLD\n"; |
||
97 | $u = new BoincUser; |
||
98 | $u->email_addr = UOTD_ADMIN_EMAIL; |
||
99 | $u->name = "UOTD admin"; |
||
100 | send_email($u, |
||
101 | PROJECT . ": User of the Day pool is running low!", |
||
102 | "The pool of approved candidates for User of the Day has". |
||
103 | " reached your assigned threshold: there are now only " . $result->num_rows . " approved users.\n\n". |
||
104 | "To approve more candidates for User of the Day,". |
||
105 | " go to the " . PROJECT . " administration page and click \"Screen user profiles\"" |
||
106 | ); |
||
107 | } |
||
108 | |||
109 | if ($result && $result->num_rows == 0) { |
||
110 | echo "no new verified profile found, selecting old UOTD that was shown least recently\n"; |
||
111 | $result->free(); |
||
112 | // If all verified profiles have been selected as UOTD, |
||
113 | // reshow a random one of the 100 least recently shown profiles. |
||
114 | // |
||
115 | $inner = "SELECT profile.userid FROM profile,user WHERE profile.userid=user.id AND verification=1 AND uotd_time>0 ORDER BY uotd_time ASC LIMIT 100"; |
||
116 | $result = $db->do_query("SELECT * from ($inner) as t ORDER BY RAND() LIMIT 1"); |
||
117 | } |
||
118 | |||
119 | if (!$result || $result->num_rows == 0) { |
||
120 | // No valid users of the day - do something. |
||
121 | echo "No screened users found\n"; |
||
122 | exit(); |
||
0 ignored issues
–
show
|
|||
123 | } |
||
124 | $candidate = $result->fetch_object(); |
||
125 | $result->free(); |
||
126 | |||
127 | // depending on the candidates query the profile must not exist |
||
128 | // |
||
129 | $profile = BoincProfile::lookup_userid($candidate->userid); |
||
130 | if (!$profile) { |
||
131 | echo "Could not find profile returned from candidates query.\n"; |
||
132 | exit(); |
||
0 ignored issues
–
show
|
|||
133 | } |
||
134 | |||
135 | // "orphaned" profiles can only be detected if the candidate query doesn't join profile and user table |
||
136 | // if this happens, delete the profile and try again |
||
137 | // |
||
138 | $user = BoincUser::lookup_id($candidate->userid); |
||
139 | if (!$user) { |
||
140 | echo "Profile for user $candidate->userid is orphaned and will be deleted\n"; |
||
141 | $profile->delete(); |
||
142 | select_uotd($force_new); |
||
143 | exit(); |
||
0 ignored issues
–
show
|
|||
144 | } |
||
145 | |||
146 | $profile->uotd_time = time(); |
||
147 | $profile->update("uotd_time = ".time()); |
||
148 | |||
149 | send_email($user, |
||
150 | "You're the " . PROJECT . " user of the day!", |
||
151 | "Congratulations!\n\nYou've been chosen as the " |
||
152 | . PROJECT . " user of the day! |
||
153 | Your profile will be featured on the " . PROJECT . " website for the next 24 hours." |
||
154 | ); |
||
155 | echo "Chose user $user->id as UOTD\n"; |
||
156 | |||
157 | generate_uotd_gadget($profile, $user); |
||
158 | } |
||
159 | |||
160 | // This query defines the set of users eligible to be UOTD. |
||
161 | // To override this with your own policy, create a similar function in |
||
162 | // your own project.inc called uotd_candidates_query() |
||
163 | // |
||
164 | function default_uotd_candidates_query(){ |
||
165 | $query = "SELECT * FROM profile,user WHERE profile.userid=user.id "; |
||
166 | $query .= " AND verification=1 "; |
||
167 | $query .= " AND expavg_credit>1 "; |
||
168 | $query .= " AND (uotd_time IS NULL or uotd_time=0) "; |
||
169 | $query .= "ORDER BY RAND()"; |
||
170 | return $query; |
||
171 | } |
||
172 | |||
173 | // get a list of profiles that have been 'approved' for UOTD, |
||
174 | // using a project-specific query if supplied in project.inc |
||
175 | // |
||
176 | function count_uotd_candidates(){ |
||
177 | $n = -1; // negative value returned on error |
||
178 | if (function_exists('uotd_candidates_query')) { |
||
179 | $query = uotd_candidates_query(); |
||
180 | } else { |
||
181 | $query = default_uotd_candidates_query(); |
||
182 | } |
||
183 | |||
184 | $db = BoincDb::get(); |
||
185 | $result = $db->do_query($query); |
||
186 | if($result) { |
||
187 | $n = $result->num_rows; |
||
188 | } |
||
189 | $result->free(); |
||
190 | |||
191 | return $n; |
||
192 | } |
||
193 | |||
194 | // iGoogle gadget - generate the gadget content page |
||
195 | // |
||
196 | function generate_uotd_gadget($profile, $user) { |
||
197 | $x = "<font size='2'>\n"; |
||
198 | $gadget = PROFILE_PATH."uotd_gadget.html"; |
||
0 ignored issues
–
show
|
|||
199 | if( $h = fopen($gadget, "w") ){ |
||
200 | $age = time()-$profile->uotd_time; |
||
201 | echo "age: $age"; |
||
202 | if($age <= 86400+3600) { // allow for slop |
||
203 | $x .= uotd_thumbnail($profile, $user); |
||
204 | $x .= user_links($user, BADGE_HEIGHT_MEDIUM); |
||
205 | $resp = sanitize_tags(output_transform($profile->response1)); |
||
206 | $x .= " ". sub_sentence($resp, ' ', 250, true); |
||
207 | } |
||
208 | else { |
||
209 | $x .= "<font color='fuscia'> |
||
210 | There is no User of the Day today. |
||
211 | Only volunteers who have created a Profile |
||
212 | (with a picture), and have recent credit, |
||
213 | are eligible to be chosen as User of the Day. |
||
214 | We have run out of these, so there isn't a |
||
215 | User of the Day. |
||
216 | </font>"; |
||
217 | } |
||
218 | $x .= "\n</font>\n"; |
||
219 | fwrite($h, $x); |
||
220 | fclose($h); |
||
221 | } |
||
222 | } |
||
223 | |||
224 | ?> |
||
225 |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.