/[drupal]/contributions/modules/versioncontrol/versioncontrol.pages.inc
ViewVC logotype

Contents of /contributions/modules/versioncontrol/versioncontrol.pages.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.26 - (show annotations) (download) (as text)
Fri Oct 16 14:15:26 2009 UTC (5 weeks, 6 days ago) by sdboyer
Branch: MAIN
CVS Tags: HEAD
Changes since 1.25: +51 -31 lines
File MIME type: text/x-php
Merging in work from git by marvil07 for his GSOC project to OO-ify vcsapi. From this commit forward, HEAD is OO.
1 <?php
2 // $Id$
3 /**
4 * @file
5 * Version Control API - An interface to version control systems
6 * whose functionality is provided by pluggable back-end modules.
7 *
8 * This file contains the user interface for non-admin tasks.
9 *
10 * Copyright 2006, 2007 Derek Wright ("dww" , http://drupal.org/user/46549)
11 * Copyright 2007, 2009 by Jakob Petsovits ("jpetso", http://drupal.org/user/56020)
12 */
13
14 // The account registration form has a special demo mode to show the admin how
15 // account registration will look like in the general case, mainly in order to
16 // demonstrate how the various registration messages are being used.
17 define('VERSIONCONTROL_REGISTER_DEMO', -1);
18
19 //TODO: define if we want to do the load each time, per use, or all-in-one like views.inc
20 require_once drupal_get_path('module', 'versioncontrol') .'/includes/VersioncontrolAccount.php';
21 require_once drupal_get_path('module', 'versioncontrol') .'/includes/VersioncontrolRepository.php';
22
23 /**
24 * Form callback for "versioncontrol/register[/$register_uid[/$register_at_repo_id]]":
25 * Provide an indirection that leads to an account registration form.
26 */
27 function versioncontrol_account_register_page($register_uid = FALSE, $register_at_repo_id = FALSE) {
28 global $user;
29
30 if ($user->uid == 0 || !versioncontrol_user_access()) {
31 $presets = _versioncontrol_get_string_presets();
32
33 return variable_get(
34 'versioncontrol_registration_message_unauthorized',
35 $presets['versioncontrol_registration_message_unauthorized']
36 );
37 }
38
39 if ($register_uid == 'demo') {
40 $register_uid = VERSIONCONTROL_REGISTER_DEMO;
41 }
42 else {
43 $register_uid = is_numeric($register_uid) ? $register_uid : $user->uid;
44 }
45
46 $admin_access = versioncontrol_admin_access();
47
48 if (!$admin_access && $register_uid != $user->uid) {
49 drupal_access_denied();
50 return;
51 }
52
53 $accounts = VersioncontrolAccountCache::getInstance()->getAccounts(array('uids' => array($register_uid)), TRUE);
54 $repositories = VersioncontrolRepositoryCache::getInstance()->getAllRepositories();
55
56 // Construct the '#options' array.
57 $account_usernames = array();
58 foreach ($accounts as $uid => $usernames_by_repository) {
59 foreach ($usernames_by_repository as $repo_id => $account) {
60 $account_usernames[$repo_id][] = $account->vcs_username;
61 }
62 }
63
64 if ($register_uid == VERSIONCONTROL_REGISTER_DEMO) {
65 $account_usernames = array();
66 }
67
68 $repository_names = array();
69 foreach ($repositories as $repo_id => $repository) {
70 if (isset($account_usernames[$repo_id])
71 && $repository->isAccountAuthorized($register_uid)) {
72 // We only want repositories in the list of repositories that are open
73 // for registrations where no (authorized) account exists yet.
74 continue;
75 }
76 if (!isset($first_repo_id)) {
77 $first_repo_id = $repo_id;
78 }
79 $repository_names[$repo_id] = check_plain($repository['name']);
80 }
81
82 // Filter (and possibly change the caption of) the list of repositories to
83 // select. The admin has all the permissions and gets the uncensored list.
84 if (!$admin_access) {
85 foreach (module_implements('versioncontrol_alter_repository_selection') as $module) {
86 $function = $module .'_versioncontrol_alter_repository_selection';
87 $function($repository_names, $repositories);
88 }
89 }
90
91 // If there's just one repository on the site, redirect directly to this one.
92 if (count($repository_names) == 1) {
93 $only_repo_id = $first_repo_id;
94 }
95 elseif (count($repositories) == 1) {
96 $only_repo_id = reset(array_keys($repositories));
97 }
98
99 if ($register_uid == VERSIONCONTROL_REGISTER_DEMO) {
100 unset($only_repo_id);
101 }
102
103 if (is_numeric($register_at_repo_id) || isset($only_repo_id)) {
104 // If there is only one repository left to register, it doesn't matter
105 // whether or not the URL contains a repository (and which one), we always
106 // redirect to the remaining possible one. Otherwise, we try to register
107 // at the given repository.
108 $repo_id = isset($only_repo_id) ? $only_repo_id : $register_at_repo_id;
109
110 if (isset($account_usernames[$repo_id])) {
111 drupal_set_message(t('You already have a registered account.'));
112 drupal_goto('user/'. $user->uid .'/edit/versioncontrol/'. $repo_id
113 .'/'. reset($account_usernames[$repo_id]));
114 // drupal_goto() calls exit() so script execution ends right here
115 }
116 elseif (isset($repository_names[$repo_id])) {
117 return drupal_get_form('versioncontrol_account_edit_form',
118 $register_uid, $repositories[$repo_id], VERSIONCONTROL_FORM_CREATE
119 );
120 }
121 }
122
123 if (!isset($first_repo_id)) {
124 // when there are no repos, this var is not set
125 $first_repo_id = NULL;
126 }
127
128 return drupal_get_form('versioncontrol_account_register_form',
129 $register_uid, $repository_names, $first_repo_id
130 );
131 }
132
133 /**
134 * Implementation of hook_versioncontrol_alter_repository_selection():
135 * Alter the list of repositories that are available for user registration
136 * and editing. This hook is called for all users except those with
137 * "administer version control systems" permissions.
138 *
139 * @param $repository_names
140 * The list of repository names as it is shown in the select box
141 * at 'versioncontrol/register'. Array keys are the repository ids,
142 * and array elements are the captions in the select box.
143 * There's two things that can be done with this array:
144 * - Change (amend) the caption, in order to provide more information
145 * for the user. (E.g. note that an application is necessary.)
146 * - Unset any number of array elements. If you do so, the user will not
147 * be able to register a new account for this repository.
148 * @param $repositories
149 * A list of repositories (with the repository ids as array keys) that
150 * includes at least all of the repositories that correspond to the
151 * repository ids of the @p $repository_names array.
152 */
153 function versioncontrol_versioncontrol_alter_repository_selection(&$repository_names, $repositories) {
154 foreach ($repository_names as $repo_id => $caption) {
155 if ($repositories[$repo_id]['authorization_method'] == 'versioncontrol_admin') {
156 unset($repository_names[$repo_id]);
157 }
158 }
159 }
160
161 /**
162 * The actual form for "versioncontrol/register[/$register_uid]".
163 */
164 function versioncontrol_account_register_form(&$form_state, $register_uid, $repository_names, $first_repo_id) {
165 $form = array();
166
167 if (empty($repository_names)) {
168 drupal_set_title(t('No more registrations possible'));
169 $form['no_registration'] = array(
170 '#type' => 'markup',
171 '#value' => t('You already have an account for all the repositories where you can register. Go to your !user-account-page to configure repository account settings.',
172 array('!user-account-page' => l(t('user account page'), 'user/'. $register_uid .'/edit/versioncontrol'))
173 ),
174 '#prefix' => '<p>',
175 '#suffix' => '</p>',
176 );
177 return $form;
178 }
179
180 $form['#id'] = 'vcs-account-indirection-form';
181
182 $message = variable_get('versioncontrol_registration_message_authorized', FALSE);
183 if ($message == FALSE) {
184 $presets = _versioncontrol_get_string_presets();
185 $message = $presets['versioncontrol_registration_message_authorized'];
186 }
187 if (!empty($message)) {
188 $form['overview'] = array(
189 '#type' => 'fieldset',
190 '#title' => t('Overview'),
191 '#weight' => -100,
192 );
193 $form['overview']['overview'] = array(
194 '#type' => 'markup',
195 '#value' => $message,
196 );
197 }
198
199 $form['#uid'] = $register_uid;
200
201 $form['repository'] = array(
202 '#type' => 'fieldset',
203 '#title' => t('Select repository'),
204 '#weight' => 10,
205 );
206 $form['repository']['repo_id'] = array(
207 '#type' => 'select',
208 '#title' => t('Create user account in'),
209 '#options' => $repository_names,
210 '#default_value' => $first_repo_id,
211 );
212
213 if ($register_uid != VERSIONCONTROL_REGISTER_DEMO) {
214 $form['repository']['submit'] = array(
215 '#type' => 'submit',
216 '#value' => t('Create account'),
217 '#weight' => 100,
218 );
219 }
220 return $form;
221 }
222
223 /**
224 * Submit handler for the indirection form.
225 * Surprisingly, all it does is redirect to the appropriate registration form.
226 */
227 function versioncontrol_account_register_form_submit($form, &$form_state) {
228 $form_state['redirect'] = 'versioncontrol/register/'. $form['#uid'] .'/'. $form_state['values']['repo_id'];
229 }
230
231
232 /**
233 * Form callback for 'user/%versioncontrol_user_accounts/edit/versioncontrol':
234 * Display a list of the given user's VCS accounts, or directly return the form
235 * array from versioncontrol_account_edit_form() if only a single account
236 * exists for that user (or if the account has been given in the URL).
237 */
238 function versioncontrol_account_page($accounts, $url_repo_id = NULL, $url_username = NULL) {
239 $selected_usernames = array();
240
241 foreach ($accounts as $only_uid => $vcs_accounts_by_repository) {
242 // The caller (menu system) ensures that there is only one uid.
243 $uid = $only_uid;
244
245 foreach ($vcs_accounts_by_repository as $repo_id => $vcs_account) {
246 if (isset($url_repo_id) && $repo_id != $url_repo_id) {
247 unset($accounts[$uid][$repo_id]);
248 continue; // disregard repositories that don't match the URL constraints
249 }
250 $vcs_accounts = array($vcs_account);
251
252 foreach ($vcs_accounts as $key => $vcs_account) {
253 if (isset($url_username) && $vcs_account->vcs_username != $url_username) {
254 unset($vcs_accounts[$uid][$repo_id]);
255 continue; // disregard usernames that don't match the URL constraints
256 }
257 $any_repo_id = $repo_id;
258 $selected_usernames[] = $vcs_account->vcs_username;
259 }
260 }
261 }
262
263 if (empty($selected_usernames)) {
264 drupal_not_found();
265 return;
266 }
267 elseif (count($selected_usernames) == 1) {
268 $repository = VersioncontrolRepositoryCache::getInstance()->getRepository($any_repo_id);
269 return drupal_get_form('versioncontrol_account_edit_form',
270 $uid, $repository, reset($selected_usernames)
271 );
272 }
273 else {
274 return drupal_get_form('versioncontrol_account_list_form', $accounts);
275 }
276 }
277
278 /**
279 * Form callback for "admin/project/versioncontrol-accounts" and
280 * (in certain cases) "user/%versioncontrol_user_accounts/edit/versioncontrol":
281 * Show a list of VCS accounts to the admin or the user.
282 *
283 * @param $accounts
284 * The list of accounts to show, in VersioncontrolAccountCache::getInstance()->getAccounts() format.
285 */
286 function versioncontrol_account_list_form(&$form_state, $accounts) {
287 $form = array();
288 $form['#id'] = 'versioncontrol-account-list-form';
289
290 $repositories = VersioncontrolRepositoryCache::getInstance()->getRepositories(array(
291 'repo_ids' => array_keys(reset($accounts)),
292 ));
293
294 $header = array(t('Repository'), t('Username'), '');
295 $rows = array();
296
297 foreach ($accounts as $uid => $usernames_by_repository) {
298 foreach ($usernames_by_repository as $repo_id => $username) {
299 if (!isset($repositories[$repo_id])) { // happens if the backend isn't loaded
300 continue;
301 }
302 $usernames = array($username);
303
304 foreach ($usernames as $username) {
305 $formatted_username = theme('versioncontrol_account_username',
306 $uid, $username, $repositories[$repo_id],
307 array('prefer_drupal_username' => FALSE)
308 );
309 $repo_name = module_exists('commitlog')
310 ? theme('commitlog_repository', $repositories[$repo_id])
311 : check_plain($repositories[$repo_id]['name']);
312
313 $rows[] = array(
314 $repo_name,
315 $formatted_username,
316 l(t('Edit @vcs account', array('@vcs' => $repositories[$repo_id]->backend->name)),
317 'user/'. $uid .'/edit/versioncontrol/'. $repo_id .'/'. drupal_urlencode($username)
318 ),
319 );
320 }
321 }
322 }
323
324 $form['accounts'] = array(
325 '#type' => 'markup',
326 '#value' => theme('table', $header, $rows, array('style' => 'width: 50%;')),
327 );
328 return $form;
329 }
330
331 /**
332 * Form callback for (in certain cases) "versioncontrol/register"
333 * and "user/%versioncontrol_user_accounts/edit/versioncontrol":
334 * Provide a form to register or edit a VCS account.
335 *
336 * @param $uid
337 * The uid of the Drupal user whose account is being edited or registered.
338 * @param $repository
339 * The repository of the added/edited account.
340 * @param $vcs_username
341 * The user's VCS-specific username for the repository,
342 * or VERSIONCONTROL_FORM_CREATE if a new VCS account should be registered.
343 */
344 function versioncontrol_account_edit_form(&$form_state, $uid, $repository, $vcs_username) {
345 $form = array();
346 $create_account = ($vcs_username === VERSIONCONTROL_FORM_CREATE);
347 $vcs_name = $repository->backend->name;
348
349 $user = ($uid === VERSIONCONTROL_REGISTER_DEMO) ? FALSE : user_load($uid);
350
351 if (!($user || ($uid === VERSIONCONTROL_REGISTER_DEMO && $create_account))) {
352 drupal_not_found(); // cannot edit/register accounts for non-existing users
353 return array();
354 }
355
356 // Set an appropriate page title.
357 if ($create_account) {
358 drupal_set_title(t(
359 'Create user account in @repository',
360 array('@repository' => $repository['name'])
361 ));
362 }
363 elseif ($user) {
364 drupal_set_title(check_plain($user->name));
365 }
366
367 $form['#id'] = 'versioncontrol-account-form';
368
369 $form['#repository'] = $repository;
370 $form['#vcs'] = $repository['vcs'];
371 $form['#vcs_name'] = $vcs_name;
372 $form['#uid'] = $uid;
373 $form['#original_username'] = $vcs_username;
374
375 $form['#validate'] = array('versioncontrol_account_edit_form_validate');
376 $form['#submit'] = array('versioncontrol_account_edit_form_submit');
377
378 if ($create_account) {
379 $registration_message = isset($repository->data['versioncontrol']['registration_message'])
380 ? $repository->data['versioncontrol']['registration_message']
381 : '';
382
383 if (!empty($registration_message)) {
384 $form['overview'] = array(
385 '#type' => 'fieldset',
386 '#title' => t('Overview'),
387 '#weight' => -100,
388 );
389 $form['overview']['overview'] = array(
390 '#type' => 'markup',
391 '#value' => $registration_message,
392 );
393 }
394 }
395
396 $form['account'] = array(
397 '#type' => 'fieldset',
398 '#title' => t('@vcs account settings', array('@vcs' => $vcs_name)),
399 '#weight' => 0,
400 );
401
402 $admin_access = versioncontrol_admin_access();
403
404 if ($create_account || $admin_access) {
405 if ($create_account) {
406 $vcs_account = new $repository->backend->classes['account']($vcs_username, $uid, $repository);
407 // Have a nice default value for the new VCS username.
408 $vcs_username = $vcs_account->usernameSuggestion($user);
409 }
410
411 if ($admin_access) { // the admin version
412 $description = t('The @vcs username associated with the account of !user. This field is used to link commit messages to user accounts.', array('@vcs' => $vcs_name, '!user' => theme_username($user)));
413 }
414 else { // the account creation version
415 $description = t('Choose a username to access the @vcs repository with. @vcs usernames should be lowercase. Spaces or other special characters are not allowed.', array('@vcs' => $vcs_name));
416 }
417
418 $form['account']['account_name'] = array(
419 '#type' => 'textfield',
420 '#title' => t('@vcs username', array('@vcs' => $vcs_name)),
421 '#description' => $description,
422 '#default_value' => $vcs_username,
423 '#weight' => 0,
424 '#size' => 30,
425 '#maxlength' => 64,
426 );
427 }
428 else {
429 $form['account_name'] = array(
430 '#type' => 'value',
431 '#value' => $vcs_username,
432 );
433 $form['account']['account_name_display'] = array(
434 '#type' => 'item',
435 '#title' => t('@vcs username', array('@vcs' => $vcs_name)),
436 '#description' => t('Your @vcs username. This field can only be edited by administrators and is used to link your @vcs messages to your user account.', array('@vcs' => $vcs_name)),
437 '#value' => $vcs_username,
438 '#weight' => 0,
439 );
440 }
441
442 if ($uid !== VERSIONCONTROL_REGISTER_DEMO) {
443 $form['submit'] = array(
444 '#type' => 'submit',
445 '#value' => $create_account
446 ? t('Create @vcs account', array('@vcs' => $vcs_name))
447 : t('Update @vcs account', array('@vcs' => $vcs_name)),
448 '#weight' => 100,
449 );
450 }
451 return $form;
452 }
453
454 /**
455 * Validate the edit/register user account form submission before it is submitted.
456 */
457 function versioncontrol_account_edit_form_validate($form, &$form_state) {
458 if (!isset($form_state['values']['account_name'])) {
459 return;
460 }
461 $uid = $form['#uid'];
462 $username = trim($form_state['values']['account_name']);
463 $repository = $form['#repository'];
464 $vcs_name = $form['#vcs_name'];
465
466 if (!isset($repository)) { // admin deletes repo while user fills in form
467 form_set_error('account',
468 t('The repository has been deleted.')
469 );
470 return;
471 }
472
473 if (empty($username)) {
474 form_set_error('account_name',
475 t('The @vcs username may not be empty.', array('@vcs' => $vcs_name))
476 );
477 }
478 else {
479 // Check for username validity - done by the backend, but with a fallback
480 // for alphanum-only characters.
481 $vcs_account = new $repository->backend->classes['account']($username, $uid, $repository);
482 if (!$vcs_account->isUsernameValid($username)) {
483 form_set_error('account_name',
484 t('The specified @vcs username is invalid.', array('@vcs' => $vcs_name))
485 );
486 }
487 // The username is passed by reference and might have changed. That's a bit
488 // uncomfortable as a caller API, but more convenient for the backends.
489 // (Plus it makes sense anyways since we have trimmed the username too.)
490 $form_state['values']['account_name'] = $username;
491
492 // Check for duplicates.
493 $existing_uid = $repository->getAccountUidForUsername($username, TRUE);
494 if ($existing_uid && $uid != $existing_uid) {
495 if ($existing_user = user_load(array('uid' => $existing_uid))) {
496 $existing_username = theme('username', $existing_user);
497 }
498 else {
499 $existing_username = t('user #!id', array('!id' => $existing_uid));
500 }
501 form_set_error('account_name',
502 t('The specified @vcs username is already in use by !existing-user.',
503 array('@vcs' => $vcs_name, '!existing-user' => $existing_username))
504 );
505 }
506 }
507 }
508
509 /**
510 * Add or update the user account when the edit/register form is submitted.
511 */
512 function versioncontrol_account_edit_form_submit($form, &$form_state) {
513 // Reconstruct the user data from the $form_state that was passed.
514 $uid = $form['#uid'];
515 $username = $form_state['values']['account_name'];
516 $repository = $form['#repository'];
517 $vcs_name = $form['#vcs_name'];
518
519 // Let other modules provide additional account data.
520 $additional_data = array();
521 foreach (module_implements('versioncontrol_account_submit') as $module) {
522 $function = $module .'_versioncontrol_account_submit';
523 $function($additional_data, $form, $form_state);
524 }
525
526 if (empty($form['#original_username'])) {
527 $vcs_account = new $repository->backend->classes['account']($username, $uid, $repository);
528 $vcs_account->insert($additional_data);
529 $message = drupal_set_message(t(
530 'The @vcs account %username has been registered.',
531 array('@vcs' => $vcs_name, '%username' => $username)
532 ));
533 }
534 else {
535 //FIXME why username are a required constraint?
536 // uid and repo_id are the PK on the table getAccounts query
537 $constraints = array(
538 'uids' => array($uid),
539 'repo_ids' => array($repository->repo_id),
540 'usernames' => array($form['#original_username'])
541 );
542 $vcs_accounts = VersioncontrolAccountCache::getInstance()->getAccounts($constraints, TRUE);
543 // if we got an original_username we can trust on getting a value
544 $vcs_account = array_shift(array_shift($vcs_accounts));
545
546 $vcs_account->update($username, $additional_data);
547
548 // Regular users cannot change the username, and will probably get
549 // a message for each of the other actions that hook into the form.
550 if (versioncontrol_admin_access()) {
551 $message = drupal_set_message(t(
552 'The @vcs account %username has been updated successfully.',
553 array('@vcs' => $vcs_name, '%username' => $username)
554 ));
555 }
556 }
557
558 $form_state['redirect'] = versioncontrol_admin_access()
559 ? 'admin/project/versioncontrol-accounts'
560 : 'user/'. $uid .'/edit/versioncontrol/'. $repository->repo_id
561 .'/'. drupal_urlencode($username);
562 }

  ViewVC Help
Powered by ViewVC 1.1.2