|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Code required only when rendering the available updates report. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Page callback: Generates a page about the update status of projects. |
|
10 * |
|
11 * @see update_menu() |
|
12 */ |
|
13 function update_status() { |
|
14 if ($available = update_get_available(TRUE)) { |
|
15 module_load_include('inc', 'update', 'update.compare'); |
|
16 $data = update_calculate_project_data($available); |
|
17 return theme('update_report', array('data' => $data)); |
|
18 } |
|
19 else { |
|
20 return theme('update_report', array('data' => _update_no_data())); |
|
21 } |
|
22 } |
|
23 |
|
24 /** |
|
25 * Returns HTML for the project status report. |
|
26 * |
|
27 * @param array $variables |
|
28 * An associative array containing: |
|
29 * - data: An array of data about each project's status. |
|
30 * |
|
31 * @ingroup themeable |
|
32 */ |
|
33 function theme_update_report($variables) { |
|
34 $data = $variables['data']; |
|
35 |
|
36 $last = variable_get('update_last_check', 0); |
|
37 $output = theme('update_last_check', array('last' => $last)); |
|
38 |
|
39 if (!is_array($data)) { |
|
40 $output .= '<p>' . $data . '</p>'; |
|
41 return $output; |
|
42 } |
|
43 |
|
44 $header = array(); |
|
45 $rows = array(); |
|
46 |
|
47 $notification_level = variable_get('update_notification_threshold', 'all'); |
|
48 |
|
49 // Create an array of status values keyed by module or theme name, since |
|
50 // we'll need this while generating the report if we have to cross reference |
|
51 // anything (e.g. subthemes which have base themes missing an update). |
|
52 foreach ($data as $project) { |
|
53 foreach ($project['includes'] as $key => $name) { |
|
54 $status[$key] = $project['status']; |
|
55 } |
|
56 } |
|
57 |
|
58 foreach ($data as $project) { |
|
59 switch ($project['status']) { |
|
60 case UPDATE_CURRENT: |
|
61 $class = 'ok'; |
|
62 $icon = theme('image', array('path' => 'misc/watchdog-ok.png', 'width' => 18, 'height' => 18, 'alt' => t('ok'), 'title' => t('ok'))); |
|
63 break; |
|
64 case UPDATE_UNKNOWN: |
|
65 case UPDATE_FETCH_PENDING: |
|
66 case UPDATE_NOT_FETCHED: |
|
67 $class = 'unknown'; |
|
68 $icon = theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('warning'), 'title' => t('warning'))); |
|
69 break; |
|
70 case UPDATE_NOT_SECURE: |
|
71 case UPDATE_REVOKED: |
|
72 case UPDATE_NOT_SUPPORTED: |
|
73 $class = 'error'; |
|
74 $icon = theme('image', array('path' => 'misc/watchdog-error.png', 'width' => 18, 'height' => 18, 'alt' => t('error'), 'title' => t('error'))); |
|
75 break; |
|
76 case UPDATE_NOT_CHECKED: |
|
77 case UPDATE_NOT_CURRENT: |
|
78 default: |
|
79 $class = 'warning'; |
|
80 $icon = theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('warning'), 'title' => t('warning'))); |
|
81 break; |
|
82 } |
|
83 |
|
84 $row = '<div class="version-status">'; |
|
85 $status_label = theme('update_status_label', array('status' => $project['status'])); |
|
86 $row .= !empty($status_label) ? $status_label : check_plain($project['reason']); |
|
87 $row .= '<span class="icon">' . $icon . '</span>'; |
|
88 $row .= "</div>\n"; |
|
89 |
|
90 $row .= '<div class="project">'; |
|
91 if (isset($project['title'])) { |
|
92 if (isset($project['link'])) { |
|
93 $row .= l($project['title'], $project['link']); |
|
94 } |
|
95 else { |
|
96 $row .= check_plain($project['title']); |
|
97 } |
|
98 } |
|
99 else { |
|
100 $row .= check_plain($project['name']); |
|
101 } |
|
102 $row .= ' ' . check_plain($project['existing_version']); |
|
103 if ($project['install_type'] == 'dev' && !empty($project['datestamp'])) { |
|
104 $row .= ' <span class="version-date">(' . format_date($project['datestamp'], 'custom', 'Y-M-d') . ')</span>'; |
|
105 } |
|
106 $row .= "</div>\n"; |
|
107 |
|
108 $versions_inner = ''; |
|
109 $security_class = array(); |
|
110 $version_class = array(); |
|
111 if (isset($project['recommended'])) { |
|
112 if ($project['status'] != UPDATE_CURRENT || $project['existing_version'] !== $project['recommended']) { |
|
113 |
|
114 // First, figure out what to recommend. |
|
115 // If there's only 1 security update and it has the same version we're |
|
116 // recommending, give it the same CSS class as if it was recommended, |
|
117 // but don't print out a separate "Recommended" line for this project. |
|
118 if (!empty($project['security updates']) && count($project['security updates']) == 1 && $project['security updates'][0]['version'] === $project['recommended']) { |
|
119 $security_class[] = 'version-recommended'; |
|
120 $security_class[] = 'version-recommended-strong'; |
|
121 } |
|
122 else { |
|
123 $version_class[] = 'version-recommended'; |
|
124 // Apply an extra class if we're displaying both a recommended |
|
125 // version and anything else for an extra visual hint. |
|
126 if ($project['recommended'] !== $project['latest_version'] |
|
127 || !empty($project['also']) |
|
128 || ($project['install_type'] == 'dev' |
|
129 && isset($project['dev_version']) |
|
130 && $project['latest_version'] !== $project['dev_version'] |
|
131 && $project['recommended'] !== $project['dev_version']) |
|
132 || (isset($project['security updates'][0]) |
|
133 && $project['recommended'] !== $project['security updates'][0]) |
|
134 ) { |
|
135 $version_class[] = 'version-recommended-strong'; |
|
136 } |
|
137 $versions_inner .= theme('update_version', array('version' => $project['releases'][$project['recommended']], 'tag' => t('Recommended version:'), 'class' => $version_class)); |
|
138 } |
|
139 |
|
140 // Now, print any security updates. |
|
141 if (!empty($project['security updates'])) { |
|
142 $security_class[] = 'version-security'; |
|
143 foreach ($project['security updates'] as $security_update) { |
|
144 $versions_inner .= theme('update_version', array('version' => $security_update, 'tag' => t('Security update:'), 'class' => $security_class)); |
|
145 } |
|
146 } |
|
147 } |
|
148 |
|
149 if ($project['recommended'] !== $project['latest_version']) { |
|
150 $versions_inner .= theme('update_version', array('version' => $project['releases'][$project['latest_version']], 'tag' => t('Latest version:'), 'class' => array('version-latest'))); |
|
151 } |
|
152 if ($project['install_type'] == 'dev' |
|
153 && $project['status'] != UPDATE_CURRENT |
|
154 && isset($project['dev_version']) |
|
155 && $project['recommended'] !== $project['dev_version']) { |
|
156 $versions_inner .= theme('update_version', array('version' => $project['releases'][$project['dev_version']], 'tag' => t('Development version:'), 'class' => array('version-latest'))); |
|
157 } |
|
158 } |
|
159 |
|
160 if (isset($project['also'])) { |
|
161 foreach ($project['also'] as $also) { |
|
162 $versions_inner .= theme('update_version', array('version' => $project['releases'][$also], 'tag' => t('Also available:'), 'class' => array('version-also-available'))); |
|
163 } |
|
164 } |
|
165 |
|
166 if (!empty($versions_inner)) { |
|
167 $row .= "<div class=\"versions\">\n" . $versions_inner . "</div>\n"; |
|
168 } |
|
169 $row .= "<div class=\"info\">\n"; |
|
170 if (!empty($project['extra'])) { |
|
171 $row .= '<div class="extra">' . "\n"; |
|
172 foreach ($project['extra'] as $key => $value) { |
|
173 $row .= '<div class="' . implode(' ', $value['class']) . '">'; |
|
174 $row .= check_plain($value['label']) . ': '; |
|
175 $row .= drupal_placeholder($value['data']); |
|
176 $row .= "</div>\n"; |
|
177 } |
|
178 $row .= "</div>\n"; // extra div. |
|
179 } |
|
180 |
|
181 $row .= '<div class="includes">'; |
|
182 sort($project['includes']); |
|
183 if (!empty($project['disabled'])) { |
|
184 sort($project['disabled']); |
|
185 // Make sure we start with a clean slate for each project in the report. |
|
186 $includes_items = array(); |
|
187 $row .= t('Includes:'); |
|
188 $includes_items[] = t('Enabled: %includes', array('%includes' => implode(', ', $project['includes']))); |
|
189 $includes_items[] = t('Disabled: %disabled', array('%disabled' => implode(', ', $project['disabled']))); |
|
190 $row .= theme('item_list', array('items' => $includes_items)); |
|
191 } |
|
192 else { |
|
193 $row .= t('Includes: %includes', array('%includes' => implode(', ', $project['includes']))); |
|
194 } |
|
195 $row .= "</div>\n"; |
|
196 |
|
197 if (!empty($project['base_themes'])) { |
|
198 $row .= '<div class="basethemes">'; |
|
199 asort($project['base_themes']); |
|
200 $base_themes = array(); |
|
201 foreach ($project['base_themes'] as $base_key => $base_theme) { |
|
202 switch ($status[$base_key]) { |
|
203 case UPDATE_NOT_SECURE: |
|
204 case UPDATE_REVOKED: |
|
205 case UPDATE_NOT_SUPPORTED: |
|
206 $base_themes[] = t('%base_theme (!base_label)', array('%base_theme' => $base_theme, '!base_label' => theme('update_status_label', array('status' => $status[$base_key])))); |
|
207 break; |
|
208 |
|
209 default: |
|
210 $base_themes[] = drupal_placeholder($base_theme); |
|
211 } |
|
212 } |
|
213 $row .= t('Depends on: !basethemes', array('!basethemes' => implode(', ', $base_themes))); |
|
214 $row .= "</div>\n"; |
|
215 } |
|
216 |
|
217 if (!empty($project['sub_themes'])) { |
|
218 $row .= '<div class="subthemes">'; |
|
219 sort($project['sub_themes']); |
|
220 $row .= t('Required by: %subthemes', array('%subthemes' => implode(', ', $project['sub_themes']))); |
|
221 $row .= "</div>\n"; |
|
222 } |
|
223 |
|
224 $row .= "</div>\n"; // info div. |
|
225 |
|
226 if (!isset($rows[$project['project_type']])) { |
|
227 $rows[$project['project_type']] = array(); |
|
228 } |
|
229 $row_key = isset($project['title']) ? drupal_strtolower($project['title']) : drupal_strtolower($project['name']); |
|
230 $rows[$project['project_type']][$row_key] = array( |
|
231 'class' => array($class), |
|
232 'data' => array($row), |
|
233 ); |
|
234 } |
|
235 |
|
236 $project_types = array( |
|
237 'core' => t('Drupal core'), |
|
238 'module' => t('Modules'), |
|
239 'theme' => t('Themes'), |
|
240 'module-disabled' => t('Disabled modules'), |
|
241 'theme-disabled' => t('Disabled themes'), |
|
242 ); |
|
243 foreach ($project_types as $type_name => $type_label) { |
|
244 if (!empty($rows[$type_name])) { |
|
245 ksort($rows[$type_name]); |
|
246 $output .= "\n<h3>" . $type_label . "</h3>\n"; |
|
247 $output .= theme('table', array('header' => $header, 'rows' => $rows[$type_name], 'attributes' => array('class' => array('update')))); |
|
248 } |
|
249 } |
|
250 drupal_add_css(drupal_get_path('module', 'update') . '/update.css'); |
|
251 return $output; |
|
252 } |
|
253 |
|
254 /** |
|
255 * Returns HTML for a label to display for a project's update status. |
|
256 * |
|
257 * @param array $variables |
|
258 * An associative array containing: |
|
259 * - status: The integer code for a project's current update status. |
|
260 * |
|
261 * @see update_calculate_project_data() |
|
262 * @ingroup themeable |
|
263 */ |
|
264 function theme_update_status_label($variables) { |
|
265 switch ($variables['status']) { |
|
266 case UPDATE_NOT_SECURE: |
|
267 return '<span class="security-error">' . t('Security update required!') . '</span>'; |
|
268 |
|
269 case UPDATE_REVOKED: |
|
270 return '<span class="revoked">' . t('Revoked!') . '</span>'; |
|
271 |
|
272 case UPDATE_NOT_SUPPORTED: |
|
273 return '<span class="not-supported">' . t('Not supported!') . '</span>'; |
|
274 |
|
275 case UPDATE_NOT_CURRENT: |
|
276 return '<span class="not-current">' . t('Update available') . '</span>'; |
|
277 |
|
278 case UPDATE_CURRENT: |
|
279 return '<span class="current">' . t('Up to date') . '</span>'; |
|
280 |
|
281 } |
|
282 } |
|
283 |
|
284 /** |
|
285 * Returns HTML for the version display of a project. |
|
286 * |
|
287 * @param array $variables |
|
288 * An associative array containing: |
|
289 * - version: An array of data about the latest released version, containing: |
|
290 * - version: The version number. |
|
291 * - release_link: The URL for the release notes. |
|
292 * - date: The date of the release. |
|
293 * - download_link: The URL for the downloadable file. |
|
294 * - tag: The title of the project. |
|
295 * - class: A string containing extra classes for the wrapping table. |
|
296 * |
|
297 * @ingroup themeable |
|
298 */ |
|
299 function theme_update_version($variables) { |
|
300 $version = $variables['version']; |
|
301 $tag = $variables['tag']; |
|
302 $class = implode(' ', $variables['class']); |
|
303 |
|
304 $output = ''; |
|
305 $output .= '<table class="version ' . $class . '">'; |
|
306 $output .= '<tr>'; |
|
307 $output .= '<td class="version-title">' . $tag . "</td>\n"; |
|
308 $output .= '<td class="version-details">'; |
|
309 $output .= l($version['version'], $version['release_link']); |
|
310 $output .= ' <span class="version-date">(' . format_date($version['date'], 'custom', 'Y-M-d') . ')</span>'; |
|
311 $output .= "</td>\n"; |
|
312 $output .= '<td class="version-links">'; |
|
313 $links = array(); |
|
314 $links['update-download'] = array( |
|
315 'title' => t('Download'), |
|
316 'href' => $version['download_link'], |
|
317 ); |
|
318 $links['update-release-notes'] = array( |
|
319 'title' => t('Release notes'), |
|
320 'href' => $version['release_link'], |
|
321 ); |
|
322 $output .= theme('links__update_version', array('links' => $links)); |
|
323 $output .= '</td>'; |
|
324 $output .= '</tr>'; |
|
325 $output .= "</table>\n"; |
|
326 return $output; |
|
327 } |