PageRenderTime 65ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Handler/Person.php

http://leaguerunner.googlecode.com/
PHP | 2181 lines | 1814 code | 270 blank | 97 comment | 233 complexity | 5e98f1e4d794591d163331c6ceed7454 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /*
  3. * Code for dealing with user accounts
  4. */
  5. function person_dispatch()
  6. {
  7. $op = arg(1);
  8. $id = arg(2);
  9. switch($op) {
  10. case 'create':
  11. $obj = new PersonCreate;
  12. break;
  13. case 'edit':
  14. $obj = new PersonEdit;
  15. $obj->person = person_load( array('user_id' => $id) );
  16. break;
  17. case 'view':
  18. $obj = new PersonView;
  19. $obj->person = person_load( array('user_id' => $id) );
  20. break;
  21. case 'delete':
  22. $obj = new PersonDelete;
  23. $obj->person = person_load( array('user_id' => $id) );
  24. break;
  25. case 'search':
  26. $obj = new PersonSearch;
  27. break;
  28. case 'approve':
  29. $obj = new PersonApproveNewAccount;
  30. $obj->person = person_load( array('user_id' => $id) );
  31. break;
  32. case 'activate':
  33. $obj = new PersonActivate;
  34. $obj->person = person_load( array('user_id' => $id) );
  35. break;
  36. case 'signwaiver':
  37. $obj = new PersonSignWaiver;
  38. break;
  39. case 'signdogwaiver':
  40. $obj = new PersonSignDogWaiver;
  41. break;
  42. case 'listnew':
  43. $obj = new PersonListNewAccounts;
  44. break;
  45. case 'changepassword':
  46. $obj = new PersonChangePassword;
  47. $obj->person = person_load( array('user_id' => $id) );
  48. break;
  49. case 'forgotpassword':
  50. $obj = new PersonForgotPassword;
  51. break;
  52. case 'historical':
  53. $obj = new PersonHistorical;
  54. $obj->person = person_load( array('user_id' => $id) );
  55. break;
  56. default:
  57. $obj = null;
  58. }
  59. if( $obj->person ) {
  60. person_add_to_menu( $obj->person );
  61. }
  62. return $obj;
  63. }
  64. /**
  65. * The permissions check for all Person actions.
  66. */
  67. function person_permissions ( &$user, $action, $arg1 = NULL, $arg2 = NULL )
  68. {
  69. $self_edit_fields = array(); # TODO
  70. $create_fields = array( 'name', 'username', 'password');
  71. $create_fields = array_merge($self_edit_fields, $create_fields);
  72. $all_view_fields = array( 'name', 'gender', 'skill', 'willing_to_volunteer' );
  73. if (variable_get('dog_questions', 1)) {
  74. $all_view_fields[] = 'dog';
  75. }
  76. $restricted_contact_fields = array( 'email', 'home_phone', 'work_phone', 'mobile_phone' );
  77. $captain_view_fields = array( 'height', 'shirtsize' );
  78. $self_view_fields = array('username','birthdate','address','last_login', 'member_id','height','shirtsize');
  79. $self_view_fields = array_merge($all_view_fields, $restricted_contact_fields, $self_view_fields);
  80. switch( $action ) {
  81. case 'create':
  82. return true;
  83. break;
  84. case 'edit':
  85. if( 'new' == $arg1) {
  86. // Almost all fields can be edited for new players
  87. if( $arg2 ) {
  88. return( in_array( $arg2, $create_fields ) );
  89. } else {
  90. return true;
  91. }
  92. }
  93. if( ! $user->is_active() ) {
  94. return false;
  95. }
  96. if( $user->user_id == $arg1 ) {
  97. if( $arg2 ) {
  98. return( in_array( $arg2, $self_edit_fields ) );
  99. } else {
  100. return true;
  101. }
  102. }
  103. break;
  104. case 'password_change':
  105. // User can change own password
  106. if( is_numeric( $arg1 )) {
  107. if( $user->user_id == $arg1 ) {
  108. return true;
  109. }
  110. }
  111. break;
  112. case 'view':
  113. if( ! ($user && $user->is_active()) ) {
  114. return false;
  115. }
  116. if( is_numeric( $arg1 )) {
  117. if( $user->user_id == $arg1 ) {
  118. // Viewing yourself allowed, most fields
  119. if( $arg2 ) {
  120. return( in_array( $arg2, $self_view_fields ) );
  121. } else {
  122. return true;
  123. }
  124. } else {
  125. // Other user. Now comes the hard part
  126. $player = person_load( array('user_id' => $arg1) );
  127. // New or locked players cannot be viewed.
  128. if( $player->status == 'new' || $player->status == 'locked' ) {
  129. return false;
  130. }
  131. $sess_user_teams = implode(",",array_keys($user->teams));
  132. $viewable_fields = $all_view_fields;
  133. /* If player is a captain, their email is viewable */
  134. if( $player->is_a_captain ) {
  135. // Plus, can view email
  136. $viewable_fields[] = 'email';
  137. }
  138. if($user->is_a_captain) {
  139. /* If the current user is a team captain, and the requested user is on
  140. * their team, they are allowed to view email/phone
  141. */
  142. foreach( $player->teams as $team ) {
  143. if( $user->is_captain_of( $team->team_id ) &&
  144. $team->position != 'captain_request' ) {
  145. /* They are, so publish email and phone */
  146. $viewable_fields = array_merge($all_view_fields, $restricted_contact_fields, $captain_view_fields);
  147. break;
  148. }
  149. }
  150. /* If the current user is a team captain, and the requested user is
  151. * captain for a "nearby" team, they are allowed to view email/phone
  152. */
  153. if($player->is_a_captain) {
  154. foreach( $player->teams as $player_team ) {
  155. if( $player->is_captain_of( $player_team->team_id ) ) {
  156. foreach( $user->teams as $user_team ) {
  157. if( $user->is_captain_of( $user_team->team_id ) &&
  158. $player_team->league_id == $user_team->league_id )
  159. {
  160. $viewable_fields = array_merge($all_view_fields, $restricted_contact_fields);
  161. }
  162. }
  163. }
  164. }
  165. }
  166. }
  167. /* Coordinator info is viewable */
  168. if($player->is_a_coordinator) {
  169. $viewable_fields = array_merge($all_view_fields, $restricted_contact_fields);
  170. }
  171. /* Coordinators get to see phone numbers of the captains they handle */
  172. if($user->is_a_coordinator && $player->is_a_captain) {
  173. foreach( $player->teams as $team ) {
  174. if( $player->is_captain_of( $team->team_id ) &&
  175. $user->coordinates_league_containing( $team->team_id ) )
  176. {
  177. $viewable_fields = array_merge($all_view_fields, $restricted_contact_fields);
  178. }
  179. }
  180. }
  181. // Finally, perform the check and return
  182. if( $arg2 ) {
  183. return( in_array( $arg2, $viewable_fields ) );
  184. } else {
  185. return true;
  186. }
  187. }
  188. }
  189. break;
  190. case 'list':
  191. case 'search':
  192. if( ! ($user && $user->is_active()) ) {
  193. return false;
  194. }
  195. return($user->class != 'visitor');
  196. case 'approve':
  197. // administrator-only
  198. case 'delete':
  199. // administrator-only
  200. case 'listnew':
  201. // administrator-only
  202. default:
  203. return false;
  204. }
  205. return false;
  206. }
  207. /**
  208. * Generate the menu items for the "Players" and "My Account" sections.
  209. */
  210. function person_menu()
  211. {
  212. global $lr_session;
  213. $id = $lr_session->attr_get('user_id');
  214. menu_add_child('_root', 'myaccount','My Account', array('weight' => -10, 'link' => "person/view/$id"));
  215. menu_add_child('myaccount', 'myaccount/edit','edit account', array('weight' => -10, 'link' => "person/edit/$id"));
  216. menu_add_child('myaccount', 'myaccount/pass', 'change password', array( 'link' => "person/changepassword/$id"));
  217. menu_add_child('myaccount', 'myaccount/signwaiver', 'view/sign player waiver', array( 'link' => "person/signwaiver", 'weight' => 3));
  218. if (variable_get('dog_questions', 1) && $lr_session->attr_get('has_dog') == 'Y') {
  219. menu_add_child('myaccount', 'myaccount/signdogwaiver', 'view/sign dog waiver', array( 'link' => "person/signdogwaiver", 'weight' => 4));
  220. }
  221. # Don't show "Players" menu for non-players.
  222. if( ! $lr_session->is_player() ) {
  223. return;
  224. }
  225. menu_add_child('_root','person',"Players", array('weight' => -9));
  226. if($lr_session->has_permission('person','list') ) {
  227. menu_add_child('person','person/search',"search players", array('link' => 'person/search'));
  228. }
  229. if($lr_session->is_admin()) {
  230. $newUsers = person_count(array( 'status' => 'new' ));
  231. if($newUsers) {
  232. menu_add_child('person','person/listnew',"approve new accounts ($newUsers pending)", array('link' => "person/listnew"));
  233. }
  234. menu_add_child('person', 'person/create', "create account", array('link' => "person/create", 'weight' => 1));
  235. # Admin menu
  236. menu_add_child('settings', 'settings/person', 'user settings', array('link' => 'settings/person'));
  237. menu_add_child('statistics', 'statistics/person', 'player statistics', array('link' => 'statistics/person'));
  238. }
  239. }
  240. /**
  241. * Periodic tasks to perform. This should handle any internal checkpointing
  242. * necessary, as the cron task may be called more or less frequently than we
  243. * expect.
  244. */
  245. function person_cron()
  246. {
  247. global $dbh;
  248. $output = '';
  249. if( variable_get('registration', 0) ) {
  250. $output .= h2('Membership welcome letters');
  251. // Defaulting the value here to 0 matches no real events while preventing SQL errors.
  252. $registration_ids = variable_get('membership_ids', '0');
  253. // TODO: Make the rollover date configurable; this starts the new year's letters in April
  254. $year = date('Y');
  255. if (date('n') < 4)
  256. -- $year;
  257. $sth = $dbh->prepare("SELECT user_id FROM person
  258. WHERE user_id IN
  259. (SELECT DISTINCT user_id FROM registrations
  260. WHERE registration_id IN ($registration_ids)
  261. AND payment = 'Paid')
  262. AND user_id NOT IN
  263. (SELECT secondary_id FROM activity_log
  264. WHERE type = ? AND primary_id = ?)");
  265. $sth->execute( array("email_membership_letter", $year) );
  266. $emailed = 0;
  267. while( $id = $sth->fetchColumn() ) {
  268. $person = person_load( array('user_id' => $id) );
  269. if ($person->send_membership_letter())
  270. ++ $emailed;
  271. }
  272. $output .= para("Emailed $emailed membership letters.");
  273. }
  274. return "$output<pre>Completed person_cron run</pre>";
  275. }
  276. /**
  277. * Player viewing handler
  278. */
  279. class PersonView extends Handler
  280. {
  281. var $person;
  282. function has_permission ()
  283. {
  284. global $lr_session;
  285. if(!$this->person) {
  286. error_exit("That user does not exist");
  287. }
  288. return $lr_session->has_permission('person','view', $this->person->user_id);
  289. }
  290. function process ()
  291. {
  292. $this->title = 'View';
  293. $this->setLocation(array(
  294. $this->person->fullname => 'person/view/' . $this->person->user_id,
  295. $this->title => 0));
  296. return $this->generateView($this->person);
  297. }
  298. function generateView (&$person)
  299. {
  300. global $lr_session;
  301. $rows[] = array("Name:", $person->fullname);
  302. if( ! ($lr_session->is_player() || ($lr_session->attr_get('user_id') == $person->user_id)) ) {
  303. return "<div class='pairtable'>" . table(null, $rows) . "</div>";
  304. }
  305. if($lr_session->has_permission('person','view',$person->user_id, 'username') ) {
  306. $rows[] = array("System Username:", $person->username);
  307. }
  308. if($lr_session->has_permission('person','view',$person->user_id, 'member_id') ) {
  309. if($person->member_id) {
  310. $rows[] = array(variable_get('app_org_short_name', 'League') . ' Member ID:', $person->member_id);
  311. } else {
  312. $rows[] = array(variable_get('app_org_short_name', 'League') . ' Member ID:', 'Not a member of ' . variable_get('app_org_short_name', 'the league'));
  313. }
  314. }
  315. if($person->allow_publish_email == 'Y') {
  316. $rows[] = array("Email Address:", l($person->email, "mailto:$person->email") . " (published)");
  317. } else {
  318. if($lr_session->has_permission('person','view',$person->user_id, 'email') ) {
  319. $rows[] = array("Email Address:", l($person->email, "mailto:$person->email") . " (private)");
  320. }
  321. }
  322. foreach(array('home','work','mobile') as $type) {
  323. $item = "${type}_phone";
  324. $publish = "publish_$item";
  325. if($person->$publish == 'Y') {
  326. $rows[] = array("Phone ($type):", $person->$item . " (published)");
  327. } else {
  328. if($lr_session->has_permission('person','view',$person->user_id, $item) && isset($person->$item) ) {
  329. $rows[] = array("Phone ($type):", $person->$item . " (private)");
  330. }
  331. }
  332. }
  333. if($lr_session->has_permission('person','view',$person->user_id, 'address')) {
  334. $rows[] = array("Address:",
  335. format_street_address(
  336. $person->addr_street,
  337. $person->addr_city,
  338. $person->addr_prov,
  339. $person->addr_country,
  340. $person->addr_postalcode
  341. )
  342. );
  343. }
  344. if($lr_session->has_permission('person','view',$person->user_id, 'birthdate')) {
  345. $rows[] = array('Birthdate:', $person->birthdate);
  346. }
  347. if($lr_session->has_permission('person','view',$person->user_id, 'height')) {
  348. $rows[] = array('Height:', $person->height ? "$person->height inches" : "Please edit your account to enter your height");
  349. }
  350. if($lr_session->has_permission('person','view',$person->user_id, 'gender')) {
  351. $rows[] = array("Gender:", $person->gender);
  352. }
  353. if($lr_session->has_permission('person','view',$person->user_id, 'shirtsize')) {
  354. $rows[] = array('Shirt Size:', $person->shirtsize);
  355. }
  356. if($lr_session->has_permission('person','view',$person->user_id, 'skill')) {
  357. $skillAry = getOptionsForSkill();
  358. $rows[] = array("Skill Level:", $skillAry[$person->skill_level]);
  359. $rows[] = array("Year Started:", $person->year_started);
  360. }
  361. if($lr_session->has_permission('person','view',$person->user_id, 'class')) {
  362. $rows[] = array("Account Class:", $person->class);
  363. }
  364. if($lr_session->has_permission('person','view',$person->user_id, 'status')) {
  365. $rows[] = array("Account Status:", $person->status);
  366. }
  367. if(variable_get('dog_questions', 1)) {
  368. if($lr_session->has_permission('person','view',$person->user_id, 'dog')) {
  369. $rows[] = array("Has Dog:",($person->has_dog == 'Y') ? "yes" : "no");
  370. if($person->has_dog == 'Y') {
  371. $rows[] = array("Dog Waiver Signed:",($person->dog_waiver_signed) ? $person->dog_waiver_signed : "Not signed");
  372. }
  373. }
  374. }
  375. if($lr_session->has_permission('person','view',$person->user_id, 'willing_to_volunteer')) {
  376. $rows[] = array('Can ' . variable_get('app_org_short_name', 'the league') . ' contact you with a survey about volunteering?',($person->willing_to_volunteer == 'Y') ? 'yes' : 'no');
  377. }
  378. if($lr_session->has_permission('person','view',$person->user_id, 'contact_for_feedback')) {
  379. $rows[] = array('From time to time, ' . variable_get('app_org_short_name', 'the league') .
  380. ' would like to contact members with information on our programs and to solicit feedback. ' .
  381. 'Can ' . variable_get('app_org_short_name', 'the league') . ' contact you in this regard? ',
  382. ($person->contact_for_feedback == 'Y') ? 'yes' : 'no');
  383. }
  384. if($lr_session->has_permission('person','view',$person->user_id, 'last_login')) {
  385. if($person->last_login) {
  386. $rows[] = array('Last Login:',
  387. $person->last_login . ' from ' . $person->client_ip);
  388. } else {
  389. $rows[] = array('Last Login:', 'Never logged in');
  390. }
  391. }
  392. $rosterPositions = getRosterPositions();
  393. $teams = array();
  394. while(list(,$team) = each($person->teams)) {
  395. $teams[] = array(
  396. $rosterPositions[$team->position],
  397. 'on',
  398. l($team->name, "team/view/$team->id"),
  399. "(" . l($team->league_name, "league/view/$team->league_id") . ")"
  400. );
  401. }
  402. reset($person->teams);
  403. $rows[] = array("Teams:", table( null, $teams) );
  404. if( count ($person->historical_teams) ) {
  405. $rows[] = array( '', 'There is also ' . l('historical team data', "person/historical/$person->user_id") . ' saved');
  406. }
  407. if( $person->is_a_coordinator ) {
  408. $leagues = array();
  409. foreach( $person->leagues as $league ) {
  410. $leagues[] = array(
  411. "Coordinator of",
  412. l($league->fullname, "league/view/$league->league_id")
  413. );
  414. }
  415. reset($person->leagues);
  416. $rows[] = array("Leagues:", table( null, $leagues) );
  417. }
  418. if( variable_get('registration', 0) ) {
  419. if($lr_session->has_permission('registration','history',$person->user_id)) {
  420. $rows[] = array("Registration:", l('View registration history', "registration/history/$person->user_id"));
  421. }
  422. }
  423. return "<div class='pairtable'>" . table(null, $rows) . "</div>";
  424. }
  425. }
  426. /**
  427. * Delete an account
  428. */
  429. class PersonDelete extends PersonView
  430. {
  431. var $person;
  432. function has_permission()
  433. {
  434. global $lr_session;
  435. if(!$this->person) {
  436. error_exit("That user does not exist");
  437. }
  438. return $lr_session->has_permission('person','delete', $this->person->user_id);
  439. }
  440. function process ()
  441. {
  442. global $lr_session;
  443. $this->title = 'Delete';
  444. $edit = $_POST['edit'];
  445. /* Safety check: Don't allow us to delete ourselves */
  446. if($lr_session->attr_get('user_id') == $this->person->user_id) {
  447. error_exit("You cannot delete your own account!");
  448. }
  449. if($edit['step'] == 'perform') {
  450. $this->person->delete();
  451. local_redirect(url("person/search"));
  452. return $rc;
  453. }
  454. $this->setLocation(array(
  455. $this->person->fullname => "person/view/" . $this->person->user_id,
  456. $this->title => 0));
  457. return
  458. para("Confirm that you wish to delete this user from the system.")
  459. . $this->generateView($this->person)
  460. . form(
  461. form_hidden('edit[step]', 'perform')
  462. . form_submit("Delete")
  463. );
  464. }
  465. }
  466. /**
  467. * Approve new account creation
  468. */
  469. class PersonApproveNewAccount extends PersonView
  470. {
  471. var $person;
  472. function has_permission()
  473. {
  474. global $lr_session;
  475. if(!$this->person) {
  476. error_exit("That user does not exist");
  477. }
  478. return $lr_session->has_permission('person','approve', $this->person->user_id);
  479. }
  480. function process ()
  481. {
  482. $edit = $_POST['edit'];
  483. $this->title = 'Approve Account';
  484. if($edit['step'] == 'perform') {
  485. /* Actually do the approval on the 'perform' step */
  486. $this->perform( $edit );
  487. local_redirect("person/listnew");
  488. }
  489. if($this->person->status != 'new') {
  490. error_exit("That account has already been approved");
  491. }
  492. $dispositions = array(
  493. '---' => '- Select One -',
  494. 'approve_player' => 'Approved as Player',
  495. 'approve_visitor' => 'Approved as visitor account',
  496. 'delete' => 'Deleted silently',
  497. );
  498. $sth = $this->person->find_duplicates();
  499. $duplicates = '';
  500. while( $user = $sth->fetchObject('Person', array(LOAD_OBJECT_ONLY)) ) {
  501. $duplicates .= "<li>$user->firstname $user->lastname";
  502. $duplicates .= "[&nbsp;" . l("view", "person/view/$user->user_id") . "&nbsp;]";
  503. $dispositions["delete_duplicate:$user->user_id"] = "Deleted as duplicate of $user->firstname $user->lastname ($user->user_id)";
  504. $dispositions["merge_duplicate:$user->user_id"] = "Merged backwards into $user->firstname $user->lastname ($user->user_id)";
  505. }
  506. $approval_form =
  507. form_hidden('edit[step]', 'perform')
  508. . form_select('This user should be', 'edit[disposition]', '---', $dispositions)
  509. . form_submit("Submit");
  510. $this->setLocation(array(
  511. $this->person->fullname => "person/view/" . $this->person->user_id,
  512. $this->title => 0));
  513. if( strlen($duplicates) > 0 ) {
  514. $duplicates = para("<div class='warning'><br>The following users may be duplicates of this account:<ul>\n"
  515. . $duplicates
  516. . "</ul></div>");
  517. }
  518. return
  519. $duplicates
  520. . form( para($approval_form) )
  521. . $this->generateView($this->person);
  522. }
  523. function perform ( $edit )
  524. {
  525. global $lr_session;
  526. $disposition = $edit['disposition'];
  527. if($disposition == '---') {
  528. error_exit("You must select a disposition for this account");
  529. }
  530. list($disposition,$dup_id) = split(':',$disposition);
  531. switch($disposition) {
  532. case 'approve_player':
  533. $this->person->set('class','player');
  534. $this->person->set('status','inactive');
  535. if(! $this->person->generate_member_id() ) {
  536. error_exit("Couldn't get member ID allocation");
  537. }
  538. if( ! $this->person->save() ) {
  539. error_exit("Couldn't save new member activation");
  540. }
  541. $message = _person_mail_text('approved_body_player', array(
  542. '%fullname' => $this->person->fullname,
  543. '%username' => $this->person->username,
  544. '%memberid' => $this->person->member_id,
  545. '%url' => url(""),
  546. '%adminname' => variable_get('app_admin_name', 'Leaguerunner Admin'),
  547. '%site' => variable_get('app_name','Leaguerunner')));
  548. $rc = send_mail($this->person->email, $this->person->fullname,
  549. false, false, // from the administrator
  550. false, false, // no Cc
  551. _person_mail_text('approved_subject', array( '%username' => $this->person->username, '%site' => variable_get('app_name','Leaguerunner') )),
  552. $message);
  553. if($rc == false) {
  554. error_exit("Error sending email to " . $this->person->email);
  555. }
  556. return true;
  557. case 'approve_visitor':
  558. $this->person->set('class','visitor');
  559. $this->person->set('status','inactive');
  560. if( ! $this->person->save() ) {
  561. error_exit("Couldn't save new member activation");
  562. }
  563. $message = _person_mail_text('approved_body_visitor', array(
  564. '%fullname' => $this->person->fullname,
  565. '%username' => $this->person->username,
  566. '%url' => url(""),
  567. '%adminname' => variable_get('app_admin_name','Leaguerunner Admin'),
  568. '%site' => variable_get('app_name','Leaguerunner')));
  569. $rc = send_mail($this->person->email, $this->person->fullname,
  570. false, false, // from the administrator
  571. false, false, // no Cc
  572. _person_mail_text('approved_subject', array( '%username' => $this->person->username, '%site' => variable_get('app_name','Leaguerunner' ))),
  573. $message);
  574. if($rc == false) {
  575. error_exit("Error sending email to " . $this->person->email);
  576. }
  577. return true;
  578. case 'delete':
  579. if( ! $this->person->delete() ) {
  580. error_exit("Delete of user " . $this->person->fullname . " failed.");
  581. }
  582. return true;
  583. case 'delete_duplicate':
  584. $existing = person_load( array('user_id' => $dup_id) );
  585. $message = _person_mail_text('dup_delete_body', array(
  586. '%fullname' => $this->person->fullname,
  587. '%username' => $this->person->username,
  588. '%existingusername' => $existing->username,
  589. '%existingemail' => $existing->email,
  590. '%passwordurl' => variable_get('password_reset', url('person/forgotpassword')),
  591. '%adminname' => $lr_session->user->fullname,
  592. '%site' => variable_get('app_name','Leaguerunner')));
  593. $addresses = $names = array();
  594. $addresses[] = $this->person->email;
  595. $names[] = $this->person->fullname;
  596. if($this->person->email != $existing->email) {
  597. $addresses[] = $existing->email;
  598. $names[] = $this->person->fullname;
  599. }
  600. if( ! $this->person->delete() ) {
  601. error_exit("Delete of user " . $this->person->fullname . " failed.");
  602. }
  603. $rc = send_mail($addresses, $names,
  604. false, false, // from the administrator
  605. false, false, // no Cc
  606. _person_mail_text('dup_delete_subject', array( '%site' => variable_get('app_name', 'Leaguerunner') )),
  607. $message);
  608. if($rc == false) {
  609. error_exit("Error sending email to " . $this->person->email);
  610. }
  611. return true;
  612. // This is basically the same as the delete duplicate, except
  613. // that some old information (e.g. user ID) is preserved
  614. case 'merge_duplicate':
  615. $existing = person_load( array('user_id' => $dup_id) );
  616. $message = _person_mail_text('dup_merge_body', array(
  617. '%fullname' => $this->person->fullname,
  618. '%username' => $this->person->username,
  619. '%existingusername' => $existing->username,
  620. '%existingemail' => $existing->email,
  621. '%passwordurl' => variable_get('password_reset', url('person/forgotpassword')),
  622. '%adminname' => variable_get('app_admin_name','Leaguerunner Admin'),
  623. '%site' => variable_get('app_name','Leaguerunner')));
  624. $addresses = $names = array();
  625. $addresses[] = $this->person->email;
  626. $names[] = $this->person->fullname;
  627. if($this->person->email != $existing->email) {
  628. $addresses[] = $existing->email;
  629. $names[] = $this->person->fullname;
  630. }
  631. // Copy over almost all of the new data; there must be a better way
  632. $existing->set('status', 'active');
  633. $existing->set('username', $this->person->username);
  634. $existing->set('password', $this->person->password);
  635. $existing->set('firstname', $this->person->firstname);
  636. $existing->set('lastname', $this->person->lastname);
  637. $existing->set('email', $this->person->email);
  638. $existing->set('allow_publish_email', $this->person->allow_publish_email);
  639. $existing->set('home_phone', $this->person->home_phone);
  640. $existing->set('publish_home_phone', $this->person->publish_home_phone);
  641. $existing->set('work_phone', $this->person->work_phone);
  642. $existing->set('publish_work_phone', $this->person->publish_work_phone);
  643. $existing->set('mobile_phone', $this->person->mobile_phone);
  644. $existing->set('publish_mobile_phone', $this->person->publish_mobile_phone);
  645. $existing->set('addr_street', $this->person->addr_street);
  646. $existing->set('addr_city', $this->person->addr_city);
  647. $existing->set('addr_prov', $this->person->addr_prov);
  648. $existing->set('addr_country', $this->person->addr_country);
  649. $existing->set('addr_postalcode', $this->person->addr_postalcode);
  650. $existing->set('gender', $this->person->gender);
  651. $existing->set('birthdate', $this->person->birthdate);
  652. $existing->set('height', $this->person->height);
  653. $existing->set('skill_level', $this->person->skill_level);
  654. $existing->set('year_started', $this->person->year_started);
  655. $existing->set('shirtsize', $this->person->shirtsize);
  656. $existing->set('session_cookie', $this->person->session_cookie);
  657. $existing->set('has_dog', $this->person->has_dog);
  658. $existing->set('survey_completed', $this->person->survey_completed);
  659. $existing->set('willing_to_volunteer', $this->person->willing_to_volunteer);
  660. $existing->set('contact_for_feedback', $this->person->contact_for_feedback);
  661. $existing->set('last_login', $this->person->last_login);
  662. $existing->set('client_ip', $this->person->client_ip);
  663. if( !$existing->member_id) {
  664. $existing->generate_member_id();
  665. }
  666. if( ! $this->person->delete() ) {
  667. error_exit("Delete of user " . $this->person->fullname . " failed.");
  668. }
  669. if( ! $existing->save() ) {
  670. error_exit("Couldn't save new member information");
  671. }
  672. $rc = send_mail($addresses, $names,
  673. false, false, // from the administrator
  674. false, false, // no Cc
  675. _person_mail_text('dup_merge_subject', array( '%site' => variable_get('app_name', 'Leaguerunner') )),
  676. $message);
  677. if($rc == false) {
  678. error_exit("Error sending email to " . $this->person->email);
  679. }
  680. return true;
  681. default:
  682. error_exit("You must select a disposition for this account");
  683. }
  684. }
  685. }
  686. /**
  687. * Player edit handler
  688. */
  689. class PersonEdit extends Handler
  690. {
  691. var $person;
  692. function has_permission ()
  693. {
  694. global $lr_session;
  695. if(!$this->person) {
  696. error_exit("That user does not exist");
  697. }
  698. return $lr_session->has_permission('person','edit', $this->person->user_id);
  699. }
  700. function process ()
  701. {
  702. global $lr_session;
  703. $edit = $_POST['edit'];
  704. $this->title = 'Edit';
  705. switch($edit['step']) {
  706. case 'confirm':
  707. $rc = $this->generateConfirm( $this->person->user_id, $edit );
  708. break;
  709. case 'perform':
  710. $this->perform( $this->person, $edit );
  711. if($this->person->is_active()) {
  712. local_redirect('person/view/' . $this->person->user_id);
  713. }
  714. else {
  715. local_redirect('');
  716. }
  717. break;
  718. default:
  719. $edit = object2array($this->person);
  720. $rc = $this->generateForm($this->person->user_id, $edit, "Edit any of the following fields and click 'Submit' when done.");
  721. }
  722. return $rc;
  723. }
  724. function generateForm ( $id, &$formData, $instructions = "")
  725. {
  726. global $lr_session, $CONFIG;
  727. $output = <<<END_TEXT
  728. <script language="JavaScript" type="text/javascript">
  729. <!--
  730. function popup(url)
  731. {
  732. newwindow=window.open(url,'Leaguerunner Skill Rating Form','height=350,width=400,resizable=yes,scrollbars=yes')
  733. if (window.focus) {newwindow.focus()}
  734. return false;
  735. }
  736. function doNothing() {}
  737. // -->
  738. // </script>
  739. END_TEXT;
  740. $output .= form_hidden('edit[step]', 'confirm');
  741. $output .= para($instructions);
  742. $output .= para(
  743. "Note that email and phone publish settings below only apply to regular players. "
  744. . "Captains will always have access to view the phone numbers and email addresses of their confirmed players. "
  745. . "All Team Captains will also have their email address viewable by other players"
  746. );
  747. $privacy = variable_get('privacy_policy', 'http://www.ocua.ca/node/17');
  748. if($privacy) {
  749. $output .= para(
  750. 'If you have concerns about the data ' . variable_get('app_org_short_name', 'the league') . ' collects, please see our '
  751. . "<b><a href=\"$privacy\" target=\"_new\">Privacy Policy</a>.</b>"
  752. );
  753. }
  754. if($lr_session->has_permission('person', 'edit', $id, 'name') ) {
  755. $group .= form_textfield('First Name', 'edit[firstname]', $formData['firstname'], 25,100, 'First (and, if desired, middle) name.');
  756. $group .= form_textfield('Last Name', 'edit[lastname]', $formData['lastname'], 25,100);
  757. } else {
  758. $group .= form_item('Full Name', $formData['firstname'] . ' ' . $formData['lastname']);
  759. }
  760. if($lr_session->has_permission('person', 'edit', $id, 'username') ) {
  761. $group .= form_textfield('System Username', 'edit[username]', $formData['username'], 25,100, 'Desired login name.');
  762. } else {
  763. $group .= form_item('System Username', $formData['username'], 'Desired login name.');
  764. }
  765. if($lr_session->has_permission('person', 'edit', $id, 'password') ) {
  766. $group .= form_password('Password', 'edit[password_once]', '', 25,100, 'Enter your desired password.');
  767. $group .= form_password('Re-enter Password', 'edit[password_twice]', '', 25,100, 'Enter your desired password a second time to confirm it.');
  768. }
  769. $group .= form_select('Gender', 'edit[gender]', $formData['gender'], getOptionsFromEnum( 'person', 'gender'), 'Select your gender');
  770. $output .= form_group('Identity', $group);
  771. $group = form_textfield('Email Address', 'edit[email]', $formData['email'], 25, 100, 'Enter your preferred email address. This will be used by ' . variable_get('app_org_short_name', 'the league') . ' to correspond with you on league matters.');
  772. $group .= form_checkbox('Allow other players to view my email address','edit[allow_publish_email]','Y',($formData['allow_publish_email'] == 'Y'));
  773. $output .= form_group('Online Contact', $group);
  774. $group = form_textfield('Street and Number','edit[addr_street]',$formData['addr_street'], 25, 100, 'Number, street name, and apartment number if necessary');
  775. $group .= form_textfield('City','edit[addr_city]',$formData['addr_city'], 25, 100, 'Name of city');
  776. /* TODO: evil. Need to allow Americans to use this at some point in
  777. * time... */
  778. $group .= form_select('Province', 'edit[addr_prov]', $formData['addr_prov'], getProvinceNames(), 'Select a province/state from the list');
  779. $group .= form_select('Country', 'edit[addr_country]', $formData['addr_country'], getCountryNames(), 'Select a country from the list');
  780. $group .= form_textfield('Postal Code', 'edit[addr_postalcode]', $formData['addr_postalcode'], 8, 7, 'Please enter a correct postal code matching the address above. ' . variable_get('app_org_short_name', 'the league') . ' uses this information to help locate new fields near its members.');
  781. $output .= form_group('Street Address', $group);
  782. $group = form_textfield('Home', 'edit[home_phone]', $formData['home_phone'], 25, 100, 'Enter your home telephone number');
  783. $group .= form_checkbox('Allow other players to view home number','edit[publish_home_phone]','Y',($formData['publish_home_phone'] == 'Y'));
  784. $group .= form_textfield('Work', 'edit[work_phone]', $formData['work_phone'], 25, 100, 'Enter your work telephone number (optional)');
  785. $group .= form_checkbox('Allow other players to view work number','edit[publish_work_phone]','Y',($formData['publish_work_phone'] == 'Y'));
  786. $group .= form_textfield('Mobile', 'edit[mobile_phone]', $formData['mobile_phone'], 25, 100, 'Enter your cell or pager number (optional)');
  787. $group .= form_checkbox('Allow other players to view mobile number','edit[publish_mobile_phone]','Y',($formData['publish_mobile_phone'] == 'Y'));
  788. $output .= form_group('Telephone Numbers', $group);
  789. $player_classes = array(
  790. 'player' => 'Player',
  791. 'visitor' => 'Non-player account');
  792. if(! $formData['class'] ) {
  793. $formData['class'] = 'visitor';
  794. }
  795. if($lr_session->has_permission('person', 'edit', $id, 'class') ) {
  796. $player_classes['administrator'] = 'Leaguerunner administrator';
  797. $player_classes['volunteer'] = 'Volunteer';
  798. }
  799. # Volunteers can unset themselves as volunteer if they wish.
  800. if( $formData['class'] == 'volunteer' ) {
  801. $player_classes['volunteer'] = 'Volunteer';
  802. }
  803. $group = form_radiogroup('Account Type', 'edit[class]', $formData['class'], $player_classes );
  804. if($lr_session->has_permission('person', 'edit', $id, 'status') ) {
  805. $group .= form_select('Account Status','edit[status]', $formData['status'], getOptionsFromEnum('person','status'));
  806. }
  807. $output .= form_group('Account Information', $group);
  808. $group = form_select('Skill Level', 'edit[skill_level]', $formData['skill_level'],
  809. getOptionsFromRange(1, 10),
  810. "Please use the questionnaire to <a href=\"" . $CONFIG['paths']['base_url'] . "/data/rating.html\" target='_new'>calculate your rating</a>"
  811. );
  812. $thisYear = strftime('%Y', time());
  813. $group .= form_select('Year Started', 'edit[year_started]', $formData['year_started'],
  814. getOptionsFromRange(1986, $thisYear, 'reverse'), 'The year you started playing Ultimate in this league.');
  815. $group .= form_select_date('Birthdate', 'edit[birth]', $formData['birthdate'], ($thisYear - 75), ($thisYear - 5), 'Please enter a correct birthdate; having accurate information is important for insurance purposes');
  816. $group .= form_textfield('Height','edit[height]',$formData['height'], 4, 4, 'Please enter your height in inches (5 feet is 60 inches; 6 feet is 72 inches). This is used to help generate even teams for hat leagues.');
  817. $group .= form_select('Shirt Size','edit[shirtsize]', $formData['shirtsize'], getShirtSizes());
  818. if (variable_get('dog_questions', 1)) {
  819. $group .= form_radiogroup('Has Dog', 'edit[has_dog]', $formData['has_dog'], array(
  820. 'Y' => 'Yes, I have a dog I will be bringing to games',
  821. 'N' => 'No, I will not be bringing a dog to games'));
  822. }
  823. $group .= form_radiogroup('Can ' . variable_get('app_org_short_name', 'the league') . ' contact you with a survey about volunteering?', 'edit[willing_to_volunteer]', $formData['willing_to_volunteer'], array(
  824. 'Y' => 'Yes',
  825. 'N' => 'No'));
  826. $group .= form_radiogroup('From time to time, ' . variable_get('app_org_short_name', 'the league') .
  827. ' would like to contact members with information on our programs and to solicit feedback. ' .
  828. 'Can ' . variable_get('app_org_short_name', 'the league') . ' contact you in this regard? ',
  829. 'edit[contact_for_feedback]', $formData['contact_for_feedback'],
  830. array('Y' => 'Yes',
  831. 'N' => 'No'));
  832. $output .= form_group('Player and Skill Information', $group);
  833. $this->setLocation(array(
  834. $formData['fullname'] => "person/view/$id",
  835. $this->title => 0));
  836. $output .= para(form_submit('submit') . form_reset('reset'));
  837. return form($output, 'post', null, 'id="player_form"');
  838. }
  839. function generateConfirm ( $id, $edit = array() )
  840. {
  841. global $lr_session;
  842. $dataInvalid = $this->isDataInvalid( $id, $edit );
  843. if($dataInvalid) {
  844. error_exit($dataInvalid . "<br>Please use your back button to return to the form, fix these errors, and try again");
  845. }
  846. $output = para("Confirm that the data below is correct and click 'Submit' to make your changes.");
  847. $output .= form_hidden('edit[step]', 'perform');
  848. $group = '';
  849. if($lr_session->has_permission('person', 'edit', $id, 'name') ) {
  850. $group .= form_item('First Name',
  851. form_hidden('edit[firstname]',$edit['firstname']) . $edit['firstname']);
  852. $group .= form_item('Last Name',
  853. form_hidden('edit[lastname]',$edit['lastname']) . $edit['lastname']);
  854. }
  855. if($lr_session->has_permission('person', 'edit', $id, 'username') ) {
  856. $group .= form_item('System Username',
  857. form_hidden('edit[username]',$edit['username']) . $edit['username']);
  858. }
  859. if($lr_session->has_permission('person', 'edit', $id, 'password') ) {
  860. $group .= form_item('Password',
  861. form_hidden('edit[password_once]', $edit['password_once'])
  862. . form_hidden('edit[password_twice]', $edit['password_twice'])
  863. . '<i>(entered)</i>');
  864. }
  865. $group .= form_item('Gender', form_hidden('edit[gender]',$edit['gender']) . $edit['gender']);
  866. $output .= form_group('Identity', $group);
  867. $group = form_item('Email Address',
  868. form_hidden('edit[email]',$edit['email']) . $edit['email']);
  869. $group .= form_item('Show email to other players',
  870. form_hidden('edit[allow_publish_email]',$edit['allow_publish_email']) . $edit['allow_publish_email']);
  871. $output .= form_group('Online Contact', $group);
  872. $group = form_item('',
  873. form_hidden('edit[addr_street]',$edit['addr_street'])
  874. . form_hidden('edit[addr_city]',$edit['addr_city'])
  875. . form_hidden('edit[addr_prov]',$edit['addr_prov'])
  876. . form_hidden('edit[addr_country]',$edit['addr_country'])
  877. . form_hidden('edit[addr_postalcode]',$edit['addr_postalcode'])
  878. . "{$edit['addr_street']}<br>{$edit['addr_city']}, {$edit['addr_prov']}, {$edit['addr_country']}<br>{$edit['addr_postalcode']}");
  879. $output .= form_group('Street Address', $group);
  880. $group = '';
  881. foreach( array('home','work','mobile') as $location) {
  882. if($edit["${location}_phone"]) {
  883. $group .= form_item(ucfirst($location),
  884. form_hidden("edit[${location}_phone]", $edit["${location}_phone"])
  885. . $edit["${location}_phone"]);
  886. if($edit["publish_${location}_phone"] == 'Y') {
  887. $publish_info = "yes";
  888. $publish_info .= form_hidden("edit[publish_${location}_phone]", 'Y');
  889. } else {
  890. $publish_info = "no";
  891. }
  892. $group .= form_item("Allow other players to view $location number", $publish_info);
  893. }
  894. }
  895. $output .= form_group('Telephone Numbers', $group);
  896. $group = form_item("Account Class", form_hidden('edit[class]',$edit['class']) . $edit['class']);
  897. if($lr_session->has_permission('person', 'edit', $id, 'status') ) {
  898. $group .= form_item("Account Status", form_hidden('edit[status]',$edit['status']) . $edit['status']);
  899. }
  900. $output .= form_group('Account Information', $group);
  901. $levels = getOptionsForSkill();
  902. $group = form_item("Skill Level", form_hidden('edit[skill_level]',$edit['skill_level']) . $levels[$edit['skill_level']]);
  903. $group .= form_item("Year Started", form_hidden('edit[year_started]',$edit['year_started']) . $edit['year_started']);
  904. $group .= form_item("Birthdate",
  905. form_hidden('edit[birth][year]',$edit['birth']['year'])
  906. . form_hidden('edit[birth][month]',$edit['birth']['month'])
  907. . form_hidden('edit[birth][day]',$edit['birth']['day'])
  908. . $edit['birth']['year'] . " / " . $edit['birth']['month'] . " / " . $edit['birth']['day']);
  909. if($edit['height']) {
  910. $group .= form_item("Height", form_hidden('edit[height]',$edit['height']) . $edit['height'] . " inches");
  911. }
  912. $group .= form_item("Shirt Size", form_hidden('edit[shirtsize]',$edit['shirtsize']) . $edit['shirtsize']);
  913. if (variable_get('dog_questions', 1)) {
  914. $group .= form_item("Has dog", form_hidden('edit[has_dog]',$edit['has_dog']) . $edit['has_dog']);
  915. }
  916. $group .= form_item('Can ' . variable_get('app_org_short_name', 'the league') . ' contact you with a survey about volunteering?', form_hidden('edit[willing_to_volunteer]',$edit['willing_to_volunteer']) . $edit['willing_to_volunteer']);
  917. $group .= form_item('From time to time, ' . variable_get('app_org_short_name', 'the league') .
  918. ' would like to contact members with information on our programs and to solicit feedback. ' .
  919. 'Can ' . variable_get('app_org_short_name', 'the league') . ' contact you in this regard? ',
  920. form_hidden('edit[contact_for_feedback]',$edit['contact_for_feedback']) . $edit['contact_for_feedback']);
  921. $output .= form_group('Player and Skill Information', $group);
  922. $output .= para(form_submit('submit') . form_reset('reset'));
  923. $this->setLocation(array(
  924. $edit['firstname'] . " " . $edit['lastname'] => "person/view/$id",
  925. $this->title => 0));
  926. return form($output);
  927. }
  928. function perform ( $person, $edit = array() )
  929. {
  930. global $lr_session;
  931. $dataInvalid = $this->isDataInvalid( $person->user_id, $edit );
  932. if($dataInvalid) {
  933. error_exit($dataInvalid . "<br>Please use your back button to return to the form, fix these errors, and try again");
  934. }
  935. if($edit['username'] && $lr_session->has_permission('person', 'edit', $this->person->user_id, 'username') ) {
  936. $person->set('username', $edit['username']);
  937. }
  938. /* EVIL HACK
  939. * If this person is currently a 'visitor', it does not have a
  940. * member number, so if we move it to another class, it needs
  941. * to be given one. We do this by forcing its status to 'new' and
  942. * requiring it be reapproved. Ugly hack, but since
  943. * we're likely to scrutinize non-player accounts less than player
  944. * accounts, it's necessary.
  945. */
  946. if( ($person->class == 'visitor') && ($edit['class'] == 'player') ) {
  947. $person->set('status','new');
  948. $person->set('class','player');
  949. $status_changed = true;
  950. }
  951. if($edit['class'] && $lr_session->has_permission('person', 'edit', $this->person->user_id, 'class') ) {
  952. $person->set('class', $edit['class']);
  953. }
  954. if($edit['status'] && $lr_session->has_permission('person', 'edit', $this->person->user_id, 'status') ) {
  955. $person->set('status',$edit['status']);
  956. }
  957. $person->set('email', $edit['email']);
  958. $person->set('allow_publish_email', $edit['allow_publish_email']);
  959. foreach(array('home_phone','work_phone','mobile_phone') as $type) {
  960. $num = $edit[$type];
  961. if(strlen($num)) {
  962. $person->set($type, clean_telephone_number($num));
  963. } else {
  964. $person->set($type, null);
  965. }
  966. $person->set('publish_' . $type, $edit['publish_' . $type] ? 'Y' : 'N');
  967. }
  968. if($lr_session->has_permission('person', 'edit', $this->person->user_id, 'name') ) {
  969. $person->set('firstname', $edit['firstname']);
  970. $person->set('lastname', $edit['lastname']);
  971. }
  972. $person->set('addr_street', $edit['addr_street']);
  973. $person->set('addr_city', $edit['addr_city']);
  974. $person->set('addr_prov', $edit['addr_prov']);
  975. $person->set('addr_country', $edit['addr_country']);
  976. $postcode = $edit['addr_postalcode'];
  977. if(strlen($postcode) == 6) {
  978. $foo = substr($postcode,0,3) . " " . substr($postcode,3);
  979. $postcode = $foo;
  980. }
  981. $person->set('addr_postalcode', $edit['addr_postalcode']);
  982. $person->set('birthdate', join("-",array(
  983. $edit['birth']['year'],
  984. $edit['birth']['month'],
  985. $edit['birth']['day'])));
  986. if($edit['height']) {
  987. $person->set('height', $edit['height']);
  988. }
  989. $person->set('shirtsize', $edit['shirtsize']);
  990. $person->set('gender', $edit['gender']);
  991. $person->set('skill_level', $edit['skill_level']);
  992. $person->set('year_started', $edit['year_started']);
  993. if (variable_get('dog_questions', 1)) {
  994. $person->set('has_dog', $edit['has_dog']);
  995. }
  996. $person->set('willing_to_volunteer', $edit['willing_to_volunteer']);
  997. $person->set('contact_for_feedback', $edit['contact_for_feedback']);
  998. if( ! $person->save() ) {
  999. error_exit("Internal error: couldn't save changes");
  1000. } else {
  1001. /* EVIL HACK
  1002. * If a user changes their own status from visitor to player, they
  1003. * will get logged out, so we need to warn them of this fact.
  1004. */
  1005. if($status_changed) {
  1006. print theme_header("Edit Account");
  1007. print theme_body($this->breadcrumbs);
  1008. print "<h1>Edit Account</h1>";
  1009. print para(
  1010. "You have requested to change your account status to 'Player'. As such, your account is now being held for one of the administrators to approve. "
  1011. . 'Once your account is approved, you will receive an email informing you of your new ' . variable_get('app_org_short_name', 'League') . ' member number. '
  1012. . 'You will then be able to log in once again with your username and password.');
  1013. print theme_footer();
  1014. exit;
  1015. }
  1016. }
  1017. return true;
  1018. }
  1019. function isDataInvalid ( $id, $edit = array() )
  1020. {
  1021. global $lr_session;
  1022. $errors = "";
  1023. if($lr_session->has_permission('person','edit',$id, 'name')) {
  1024. if( ! validate_name_input($edit['firstname']) || ! validate_name_input($edit['lastname'])) {
  1025. $errors .= "\n<li>You can only use letters, numbers, spaces, and the characters - ' and . in first and last names";
  1026. }
  1027. }
  1028. if($lr_session->has_permission('person','edit',$id, 'username')) {
  1029. if( ! validate_name_input($edit['username']) ) {
  1030. $errors .= "\n<li>You can only use letters, numbers, spaces, and the characters - ' and . in usernames";
  1031. }
  1032. $user = person_load( array('username' => $edit['username']) );
  1033. # TODO: BUG: need to check that $user->user_id != current id
  1034. if( $user && !$lr_session->is_admin()) {
  1035. error_exit("A user with that username already exists; please go back and try again");
  1036. }
  1037. }
  1038. if ( ! validate_email_input($edit['email']) ) {
  1039. $errors .= "\n<li>You must supply a valid email address";
  1040. }
  1041. if( !validate_nonblank($edit['home_phone']) &&
  1042. !validate_nonblank($edit['work_phone']) &&
  1043. !validate_nonblank($edit['mobile_phone']) ) {
  1044. $errors .= "\n<li>You must supply at least one valid telephone number. Please supply area code, number and (if any) extension.";
  1045. }
  1046. if(validate_nonblank($edit['home_phone']) && !validate_telephone_input($edit['home_phone'])) {
  1047. $errors .= "\n<li>Home telephone number is not valid. Please supply area code, number and (if any) extension.";
  1048. }
  1049. if(validate_nonblank($edit['work_phone']) && !validate_telephone_input($edit['work_phone'])) {
  1050. $errors .= "\n<li>Work telephone number is not valid. Please supply area code, number and (if any) extension.";
  1051. }
  1052. if(validate_nonblank($edit['mobile_phone']) && !validate_telephone_input($edit['mobile_phone'])) {
  1053. $errors .= "\n<li>Mobile telephone number is not valid. Please supply area code, number and (if any) extension.";
  1054. }
  1055. $address_errors = validate_address(
  1056. $edit['addr_street'],
  1057. $edit['addr_city'],
  1058. $edit['addr_prov'],
  1059. $edit['addr_postalcode'],
  1060. $edit['addr_country']);
  1061. if( count($address_errors) > 0) {
  1062. $errors .= "\n<li>" . join("\n<li>", $address_errors);
  1063. }
  1064. if( !preg_match("/^[mf]/i",$edit['gender'] ) ) {
  1065. $errors .= "\n<li>You must select either male or female for gender.";
  1066. }
  1067. if( !validate_date_input($edit['birth']['year'], $edit['birth']['month'], $edit['birth']['day']) ) {
  1068. $errors .= "\n<li>You must provide a valid birthdate";
  1069. }
  1070. if( validate_nonblank($edit['height']) ) {
  1071. if( !$lr_session->is_admin() && ( ($edit['height'] < 36) || ($edit['height'] > 84) )) {
  1072. $errors .= "\n<li>Please enter a reasonable and valid value for your height.";
  1073. }
  1074. }
  1075. if( $edit['skill_level'] < 1 || $edit['skill_level'] > 10 ) {
  1076. $errors .= "\n<li>You must select a skill level between 1 and 10. You entered " . $edit['skill_level'];
  1077. }
  1078. $current = localtime(time(),1);
  1079. $this_year = $current['tm_year'] + 1900;
  1080. if( $edit['year_started'] > $this_year ) {
  1081. $errors .= "\n<li>Year started must be before current year.";
  1082. }
  1083. if( $edit['year_started'] < 1986 ) {
  1084. $errors .= "\n<li>Year started must be after 1986. For the number of people who started playing before then, I don't think it matters if you're listed as having played 17 years or 20, you're still old. :)";
  1085. }
  1086. $yearDiff = $edit['year_started'] - $edit['birth']['year'];
  1087. if( $yearDiff < 8) {
  1088. $errors .= "\n<li>You can't have started playing when you were $yearDiff years old! Please correct your birthdate, or your starting year";
  1089. }
  1090. if(strlen($errors) > 0) {
  1091. return $errors;
  1092. } else {
  1093. return false;
  1094. }
  1095. }
  1096. }
  1097. /**
  1098. * Player create handler
  1099. */
  1100. class PersonCreate extends PersonEdit
  1101. {
  1102. var $person;
  1103. function has_permission ()
  1104. {
  1105. global $lr_session;
  1106. return $lr_session->has_permission('person','create');
  1107. }
  1108. function checkPrereqs( $next )
  1109. {
  1110. return false;
  1111. }
  1112. function process ()
  1113. {
  1114. $edit = $_POST['edit'];
  1115. $this->title = 'Create Account';
  1116. $id = 'new';
  1117. switch($edit['step']) {
  1118. case 'confirm':
  1119. $rc = $this->generateConfirm( $id, $edit );
  1120. break;
  1121. case 'perform':
  1122. $this->person = new Person;
  1123. $this->person->user_id = $id;
  1124. return $this->perform( $this->person, $edit );
  1125. default:
  1126. $edit = array();
  1127. $rc = $this->generateForm( $id, $edit, "To create a new account, fill in all the fields below and click 'Submit' when done. Your account will be placed on hold until approved by an administrator. Once approved, you will be allocated a membership number, and have full access to the system.<p><b>NOTE</b> If you already have an account from a previous season, DO NOT CREATE ANOTHER ONE! Instead, please <a href=\"" . variable_get('password_reset', url('person/forgotpassword')) . "\">follow these instructions</a> to gain access to your account.");
  1128. }
  1129. $this->setLocation(array( $this->title => 0));
  1130. return $rc;
  1131. }
  1132. function perform ( $person, $edit = array())
  1133. {
  1134. global $lr_session;
  1135. if( ! validate_name_input($edit['username']) ) {
  1136. $errors .= "\n<li>You can only use letters, numbers, spaces, and the characters - ' and . in usernames";
  1137. }
  1138. $existing_user = person_load( array('username' => $edit['username']) );
  1139. if( $existing_user ) {
  1140. error_exit("A user with that username already exists; please go back and try again");
  1141. }
  1142. if($edit['password_once'] != $edit['password_twice']) {
  1143. error_exit("First and second entries of password do not match");
  1144. }
  1145. $crypt_pass = md5($edit['password_once']);
  1146. $person->set('username', $edit['username']);
  1147. $person->set('firstname', $edit['firstname']);
  1148. $person->set('lastname', $edit['lastname']);
  1149. $person->set('password', $crypt_pass);
  1150. $rc = parent::perform( $person, $edit );
  1151. if( $rc === false ) {
  1152. return false;
  1153. } else {
  1154. return para(
  1155. "Thank you for creating an account. It is now being held for one of the administrators to approve. "
  1156. . "Once your account is approved, you will receive an email informing you. "
  1157. . "You will then be able to log in with your username and password."
  1158. );
  1159. }
  1160. }
  1161. }
  1162. /**
  1163. * Account reactivation
  1164. *
  1165. * Accounts must be periodically reactivated to ensure that they are
  1166. * reasonably up-to-date.
  1167. */
  1168. class PersonActivate extends PersonEdit
  1169. {
  1170. var $person;
  1171. function checkPrereqs ( $ignored )
  1172. {
  1173. return false;
  1174. }
  1175. /**
  1176. * Check to see if this user can activate themselves.
  1177. * This is only possible if the user is in the 'inactive' status. This
  1178. * also means that the user can't have a valid session.
  1179. */
  1180. function has_permission ()
  1181. {
  1182. global $lr_session;
  1183. if($lr_session->is_valid()) {
  1184. return false;
  1185. }
  1186. if ($lr_session->attr_get('status') != 'inactive') {
  1187. error_exit("You do not have a valid session");
  1188. }
  1189. return true;
  1190. }
  1191. function process ()
  1192. {
  1193. global $lr_session;
  1194. $edit = $_POST['edit'];
  1195. $this->title = "Activate Account";
  1196. $this->person = $lr_session->user;
  1197. if( ! $this->person ) {
  1198. error_exit("That account does not exist");
  1199. }
  1200. switch($edit['step']) {
  1201. case 'confirm':
  1202. $rc = $this->generateConfirm( $this->person->user_id, $edit );
  1203. break;
  1204. case 'perform':
  1205. $rc = $this->perform( $this->person, $edit );
  1206. if( ! $rc ) {
  1207. error_exit("Failed attempting to activate account");
  1208. }
  1209. $this->person->set('status', 'active');
  1210. $rc = $this->person->save();
  1211. if( !$rc ) {
  1212. error_exit("Failed attempting to activate account");
  1213. }
  1214. local_redirect(url("home"));
  1215. break;
  1216. default:
  1217. $edit = object2array($this->person);
  1218. $rc = $this->generateForm( $this->person->user_id , $edit, "In order to keep our records up-to-date, please confirm that the information below is correct, and make any changes necessary.");
  1219. }
  1220. return $rc;
  1221. }
  1222. }
  1223. class PersonSignWaiver extends Handler
  1224. {
  1225. function checkPrereqs ( $op )
  1226. {
  1227. return false;
  1228. }
  1229. function initialize ()
  1230. {
  1231. $this->title = 'Consent Form for League Play';
  1232. $this->formFile = 'waiver_form.html';
  1233. $this->querystring = 'UPDATE person SET waiver_signed=NOW() where user_id = ?';
  1234. return true;
  1235. }
  1236. function has_permission()
  1237. {
  1238. global $lr_session;
  1239. if (variable_get('registration', 0) && variable_get('allow_tentative', 0)) {
  1240. return ($lr_session->is_loaded());
  1241. } else {
  1242. return ($lr_session->is_valid());
  1243. }
  1244. }
  1245. function process ()
  1246. {
  1247. $edit = $_POST['edit'];
  1248. $next = $_POST['next'];
  1249. if(is_null($next)) {
  1250. $next = queryPickle("menu");
  1251. }
  1252. switch($edit['step']) {
  1253. case 'perform':
  1254. $this->perform( $edit );
  1255. local_redirect( queryUnpickle($next));
  1256. default:
  1257. $rc = $this->generateForm( $next );
  1258. }
  1259. $this->setLocation( array($this->title => 0 ));
  1260. return $rc;
  1261. }
  1262. /**
  1263. * Process input from the waiver form.
  1264. *
  1265. * User will not be permitted to log in if they have not signed the
  1266. * waiver.
  1267. */
  1268. function perform( $edit = array() )
  1269. {
  1270. global $lr_session, $dbh;
  1271. if('yes' != $edit['signed']) {
  1272. error_exit("Sorry, your account may only be activated by agreeing to the waiver.");
  1273. }
  1274. /* otherwise, it's yes. Perform the appropriate query to mark the
  1275. * waiver as signed.
  1276. */
  1277. $sth = $dbh->prepare( $this->querystring );
  1278. $sth->execute(array($lr_session->attr_get('user_id')));
  1279. return (1 == $sth->rowCount() );
  1280. }
  1281. function generateForm( $next )
  1282. {
  1283. global $CONFIG;
  1284. $output = form_hidden('next', $next);
  1285. $output .= form_hidden('edit[step]', 'perform');
  1286. ob_start();
  1287. $retval = @readfile( trim($CONFIG['paths']['file_path'], '/') . "/data/{$this->formFile}");
  1288. if (false !== $retval) {
  1289. $output .= ob_get_contents();
  1290. }
  1291. ob_end_clean();
  1292. $output .= para(form_submit('submit') . form_reset('reset'));
  1293. return form($output);
  1294. }
  1295. }
  1296. class PersonSignDogWaiver extends PersonSignWaiver
  1297. {
  1298. function initialize ()
  1299. {
  1300. $this->title = 'Consent Form For Dog Owners';
  1301. $this->formFile = 'dog_waiver_form.html';
  1302. $this->querystring = 'UPDATE person SET dog_waiver_signed=NOW() where user_id = ?';
  1303. return true;
  1304. }
  1305. }
  1306. class PersonSearch extends Handler
  1307. {
  1308. function initialize ()
  1309. {
  1310. global $lr_session;
  1311. $this->ops = array(
  1312. 'view' => 'person/view/%d'
  1313. );
  1314. $this->title = "Player Search";
  1315. $this->extra_where = '';
  1316. if( $lr_session->has_permission('person','delete') ) {
  1317. $this->ops['delete'] = 'person/delete/%d';
  1318. }
  1319. return true;
  1320. }
  1321. function has_permission ()
  1322. {
  1323. global $lr_session;
  1324. return $lr_session->has_permission('person','search');
  1325. }
  1326. function process ()
  1327. {
  1328. $edit = &$_POST['edit'];
  1329. $this->max_results = variable_get('items_per_page', 25);
  1330. switch($edit['step']) {
  1331. case 'perform':
  1332. $rc = $this->perform( $edit );
  1333. break;
  1334. default:
  1335. $rc = $this->form();
  1336. }
  1337. $this->setLocation( array($this->title => 0 ));
  1338. return $rc;
  1339. }
  1340. function form ( $data = '' )
  1341. {
  1342. $output = para("Enter last name of person to search for and click 'submit'. You may use '*' as a wildcard");
  1343. $output .= form_hidden('edit[step]', 'perform');
  1344. $output .= "<div class='form-item'><label>Last Name: </label><input type='textfield' size='25' name = 'edit[lastname]' value='$data' />";
  1345. $output .= "<input type='submit' value='search' /></div>";
  1346. return form($output);
  1347. }
  1348. function perform ( &$edit )
  1349. {
  1350. global $lr_session;
  1351. if( $edit['lastname'] == '' ) {
  1352. error_exit("You must provide a last name");
  1353. }
  1354. $offset = $edit['offset'];
  1355. if( !$offset ) {
  1356. $limit = $this->max_results + 1;
  1357. } else {
  1358. $limit = "$offset," . ($offset + $this->max_results + 1);
  1359. }
  1360. $search = array(
  1361. 'lastname_wildcard' => $edit['lastname'],
  1362. '_order' => 'p.lastname, p.firstname',
  1363. '_limit' => $limit
  1364. );
  1365. if( strlen($this->extra_where) ) {
  1366. $search['_extra'] = $this->extra_where;
  1367. }
  1368. $result = person_query( $search );
  1369. $output = $this->form( $edit['lastname' ]);
  1370. $output .= "<table><tr><td>";
  1371. if( $offset > 0 ) {
  1372. $output .= form(
  1373. form_hidden("edit[step]",'perform')
  1374. . form_hidden('edit[lastname]', $edit['lastname'])
  1375. . form_hidden('edit[offset]', $offset - $this->max_results )
  1376. . form_submit("Prev")
  1377. );
  1378. }
  1379. $count = 0;
  1380. $people = '';
  1381. $result->setFetchMode(PDO::FETCH_CLASS, 'Person', array(LOAD_OBJECT_ONLY));
  1382. while($person = $result->fetch() ) {
  1383. if(++$count > $this->max_results) {
  1384. break;
  1385. }
  1386. $people .= "<tr><td>$person->lastname, $person->firstname</td>";
  1387. while ( list($key, $value) = each($this->ops)) {
  1388. $people .= '<td>' .l($key,sprintf($value, $person->user_id)) . "</td>";
  1389. }
  1390. reset($this->ops);
  1391. $people .= "</tr>";
  1392. }
  1393. $output .= "</td><td align='right'>";
  1394. if( $count > $this->max_results ) {
  1395. $output .= form(
  1396. form_hidden("edit[step]",'perform')
  1397. . form_hidden('edit[lastname]', $edit['lastname'])
  1398. . form_hidden('edit[offset]', $edit['offset'] + $this->max_results )
  1399. . form_submit("Next")
  1400. );
  1401. }
  1402. $output .= "</td></tr>$people</table>";
  1403. return $output;
  1404. }
  1405. }
  1406. class PersonListNewAccounts extends Handler
  1407. {
  1408. function has_permission ()
  1409. {
  1410. global $lr_session;
  1411. return $lr_session->has_permission('person','listnew');
  1412. }
  1413. function process ()
  1414. {
  1415. $this->title = "New Accounts";
  1416. $search = array(
  1417. 'status' => 'new',
  1418. '_order' => 'p.lastname, p.firstname'
  1419. );
  1420. $ops = array(
  1421. 'view' => 'person/view/%d',
  1422. 'approve' => 'person/approve/%d',
  1423. 'delete' => 'person/delete/%d'
  1424. );
  1425. $sth = person_query( $search );
  1426. $output = "<table>";
  1427. while( $person = $sth->fetchObject('Person', array(LOAD_OBJECT_ONLY)) ) {
  1428. $output .= '<tr><td>';
  1429. $dup_sth = $person->find_duplicates();
  1430. if( $dup_sth->fetch() ) {
  1431. $output .= "<span class='error'>$person->lastname, $person->firstname</span>";
  1432. } else {
  1433. $output .= "$person->lastname, $person->firstname";
  1434. }
  1435. $output .= '</td><td>';
  1436. while ( list($key, $value) = each($ops)) {
  1437. $output .= '[&nbsp;' .l($key,sprintf($value, $person->user_id)) . '&nbsp;]';
  1438. $output .= "&nbsp;";
  1439. }
  1440. reset($ops);
  1441. $output .= "</td></tr>";
  1442. }
  1443. $output .= "</table>";
  1444. $this->setLocation(array( $this->title => 'person/listnew' ));
  1445. return $output;
  1446. }
  1447. }
  1448. /**
  1449. * Player password change
  1450. */
  1451. class PersonChangePassword extends Handler
  1452. {
  1453. var $person;
  1454. function has_permission ()
  1455. {
  1456. global $lr_session;
  1457. if( ! $this->person ) {
  1458. $this->person =& $lr_session->user;
  1459. }
  1460. return $lr_session->has_permission('person','password_change', $this->person->user_id);
  1461. }
  1462. function process()
  1463. {
  1464. global $lr_session;
  1465. $edit = $_POST['edit'];
  1466. switch($edit['step']) {
  1467. case 'perform':
  1468. if($edit['password_one'] != $edit['password_two']) {
  1469. error_exit("You must enter the same password twice.");
  1470. }
  1471. $this->person->set('password', md5($edit['password_one']));
  1472. if( ! $this->person->save() ) {
  1473. error_exit("Couldn't change password due to internal error");
  1474. }
  1475. local_redirect(url("person/view/" . $this->person->user_id));
  1476. break;
  1477. default:
  1478. $rc = $this->generateForm();
  1479. }
  1480. return $rc;
  1481. }
  1482. function generateForm( )
  1483. {
  1484. $this->setLocation(array(
  1485. $user->fullname => "person/view/" . $this->person->user_id,
  1486. 'Change Password' => 0
  1487. ));
  1488. $output = para("You are changing the password for '" . $this->person->fullname . "' (username '" . $this->person->username . "').");
  1489. $output .= form_hidden('edit[step]', 'perform');
  1490. $output .= "<div class='pairtable'>";
  1491. $output .= table( null,
  1492. array(
  1493. array("New Password:", form_password('', 'edit[password_one]', '', 25, 100, "Enter your new password")),
  1494. array("New Password (again):", form_password('', 'edit[password_two]', '', 25, 100, "Enter your new password a second time to confirm")),
  1495. )
  1496. );
  1497. $output .= "</div>";
  1498. $output .= form_submit("Submit") . form_reset("Reset");
  1499. return form($output);
  1500. }
  1501. }
  1502. class PersonForgotPassword extends Handler
  1503. {
  1504. function checkPrereqs( $next )
  1505. {
  1506. return false;
  1507. }
  1508. function has_permission ()
  1509. {
  1510. // Can always request a password reset
  1511. return true;
  1512. }
  1513. function process()
  1514. {
  1515. global $lr_session;
  1516. $this->title = "Request New Password";
  1517. $edit = $_POST['edit'];
  1518. if ($lr_session->is_admin()) {
  1519. $edit = $_GET['edit'];
  1520. }
  1521. switch($edit['step']) {
  1522. case 'perform':
  1523. $rc = $this->perform( $edit );
  1524. break;
  1525. default:
  1526. $rc = $this->generateForm();
  1527. }
  1528. return $rc;
  1529. }
  1530. function generateForm()
  1531. {
  1532. $admin_addr = variable_get('app_admin_email', '');
  1533. $org = variable_get('app_org_short_name', 'league');
  1534. $output = <<<END_TEXT
  1535. <p>
  1536. If you'd like to reset your password, please enter ONLY ONE OF:
  1537. <ul>
  1538. <li>Your username
  1539. <li>Your email address
  1540. </ul>
  1541. in the form below.
  1542. </p>
  1543. <p>
  1544. If the information you provide matches an account, an email will be sent
  1545. to the address on file, containing login information and a new password.
  1546. If you don't receive an email within a few hours, you may not have
  1547. remembered your information correctly.
  1548. </p>
  1549. <p>
  1550. If you really can't remember any of these, you can mail <a
  1551. href="mailto:$admin_addr">$admin_addr</a> for support. <b>DO NOT CREATE A NEW ACCOUNT!</b>
  1552. </p>
  1553. END_TEXT;
  1554. $output .= form_hidden('edit[step]', 'perform');
  1555. $output .= "<div class='pairtable'>";
  1556. $output .= table(null, array(
  1557. array("Username:", form_textfield('', 'edit[username]', '', 25, 100)),
  1558. array("Email Address:", form_textfield('', 'edit[email]', '', 40, 100, "(please enter only ONE email address in this box)"))
  1559. ));
  1560. $output .= "</div>";
  1561. $output .= form_submit("Submit") . form_reset("Reset");
  1562. return form($output);
  1563. }
  1564. function perform ( $edit = array() )
  1565. {
  1566. $fields = array();
  1567. if(validate_nonblank($edit['username'])) {
  1568. $fields['username'] = $edit['username'];
  1569. }
  1570. if(validate_nonblank($edit['email'])) {
  1571. $fields['email'] = $edit['email'];
  1572. }
  1573. if( count($fields) < 1 ) {
  1574. error_exit("You must supply at least one of username or email address");
  1575. }
  1576. /* Now, try and find the user */
  1577. $user = person_load( $fields );
  1578. /* Now, we either have one or zero users. Regardless, we'll present
  1579. * the user with the same output; that prevents them from using this
  1580. * to guess valid usernames.
  1581. */
  1582. if( $user ) {
  1583. /* Generate a password */
  1584. $pass = generate_password();
  1585. $cryptpass = md5($pass);
  1586. $user->set('password', $cryptpass);
  1587. if( ! $user->save() ) {
  1588. error_exit("Error setting password");
  1589. }
  1590. /* And fire off an email */
  1591. $rc = send_mail($user->email, "$user->firstname $user->lastname",
  1592. false, false, // from the administrator
  1593. false, false, // no Cc
  1594. _person_mail_text('password_reset_subject', array('%site' => variable_get('app_name','Leaguerunner'))),
  1595. _person_mail_text('password_reset_body', array(
  1596. '%fullname' => "$user->firstname $user->lastname",
  1597. '%username' => $user->username,
  1598. '%password' => $pass,
  1599. '%site' => variable_get('app_name','Leaguerunner')
  1600. )));
  1601. if($rc == false) {
  1602. error_exit("System was unable to send email to that user. Please contact system administrator.");
  1603. }
  1604. }
  1605. $output = <<<END_TEXT
  1606. <p>
  1607. The password for the user matching the criteria you've entered has been
  1608. reset to a randomly generated password. The new password has been mailed
  1609. to that user's email address. No, we won't tell you what that email
  1610. address or user's name are -- if it's you, you'll know soon enough.
  1611. </p><p>
  1612. If you don't receive an email within a few hours, you may not have
  1613. remembered your information correctly, or the system may be encountering
  1614. problems.
  1615. </p>
  1616. END_TEXT;
  1617. return $output;
  1618. }
  1619. }
  1620. /**
  1621. * Player historical data handler
  1622. */
  1623. class PersonHistorical extends Handler
  1624. {
  1625. var $person;
  1626. function has_permission ()
  1627. {
  1628. global $lr_session;
  1629. if(!$this->person) {
  1630. error_exit("That user does not exist");
  1631. }
  1632. return $lr_session->has_permission('person','view', $this->person->user_id);
  1633. }
  1634. function process ()
  1635. {
  1636. $this->title = 'View Historical Teams';
  1637. $this->setLocation(array(
  1638. $this->person->fullname => 'person/view/' . $this->person->user_id,
  1639. $this->title => 0));
  1640. return $this->generateView($this->person);
  1641. }
  1642. function generateView (&$person)
  1643. {
  1644. global $lr_session;
  1645. $rosterPositions = getRosterPositions();
  1646. $rows = array();
  1647. $last_year = $last_season = '';
  1648. foreach($person->historical_teams as $team) {
  1649. if( $team->year == $last_year ) {
  1650. $year = '';
  1651. if( $team->season == $last_season ) {
  1652. $season = '';
  1653. } else {
  1654. $season = $team->season;
  1655. }
  1656. } else {
  1657. $year = $team->year;
  1658. $season = $team->season;
  1659. }
  1660. $last_year = $team->year;
  1661. $last_season = $team->season;
  1662. $rows[] = array(
  1663. $year,
  1664. $season,
  1665. $rosterPositions[$team->position],
  1666. 'on',
  1667. l($team->name, "team/view/$team->id"),
  1668. "(" . l($team->league_name, "league/view/$team->league_id") . ")"
  1669. );
  1670. }
  1671. return table(null, $rows);
  1672. }
  1673. }
  1674. function person_add_to_menu( &$person )
  1675. {
  1676. global $lr_session;
  1677. if( ! ($lr_session->attr_get('user_id') == $person->user_id) ) {
  1678. // These links already exist in the 'My Account' section if we're
  1679. // looking at ourself
  1680. menu_add_child('person', $person->fullname, $person->fullname, array('weight' => -10, 'link' => "person/view/$person->user_id"));
  1681. if($lr_session->has_permission('person', 'edit', $person->user_id) ) {
  1682. menu_add_child($person->fullname, "$person->fullname/edit",'edit account', array('weight' => -10, 'link' => "person/edit/$person->user_id"));
  1683. }
  1684. if($lr_session->has_permission('person', 'delete', $person->user_id) ) {
  1685. menu_add_child($person->fullname, "$person->fullname/delete",'delete account', array('weight' => -10, 'link' => "person/delete/$person->user_id"));
  1686. }
  1687. if($lr_session->has_permission('person', 'password_change', $person->user_id) ) {
  1688. menu_add_child($person->fullname, "$person->fullname/changepassword",'change password', array('weight' => -10, 'link' => "person/changepassword/$person->user_id"));
  1689. }
  1690. if($lr_session->has_permission('person', 'password_reset') ) {
  1691. menu_add_child($person->fullname, "$person->fullname/forgotpassword", 'send new password', array( 'link' => "person/forgotpassword?edit[username]=$person->username&amp;edit[step]=perform"));
  1692. }
  1693. }
  1694. }
  1695. function _person_mail_text($messagetype, $variables = array() )
  1696. {
  1697. // Check if the default has been overridden by the DB
  1698. if( $override = variable_get('person_mail_' . $messagetype, false) ) {
  1699. return strtr($override, $variables);
  1700. } else {
  1701. switch($messagetype) {
  1702. case 'approved_subject':
  1703. return strtr("%site Account Activation for %username", $variables);
  1704. case 'approved_body_player':
  1705. return strtr("Dear %fullname,\n\nYour %site account has been approved.\n\nYour new permanent member number is\n\t%memberid\nThis number will identify you for member services, discounts, etc, so please write it down in a safe place so you'll remember it.\n\nYou may now log in to the system at\n\t%url\nwith the username\n\t%username\nand the password you specified when you created your account. You will be asked to confirm your account information and sign a waiver form before your account will be activated.\n\nThanks,\n%adminname", $variables);
  1706. case 'approved_body_visitor':
  1707. return strtr("Dear %fullname,\n\nYour %site account has been approved.\n\nYou may now log in to the system at\n\t%url\nwith the username\n\t%username\nand the password you specified when you created your account. You will be asked to confirm your account information and sign a waiver form before your account will be activated.\n\nThanks,\n%adminname", $variables);
  1708. case 'member_letter_subject':
  1709. return strtr("%site %year Membership",$variables);
  1710. case 'member_letter_body':
  1711. return strtr("Dear %fullname,\n\nThank you for confirming your membership in the %site for %year. You are now eligible to be added to team rosters and enjoy all the other benefits of membership in the %site.\n\nThanks,\n%adminname", $variables);
  1712. case 'password_reset_subject':
  1713. return strtr("%site Password Reset",$variables);
  1714. case 'password_reset_body':
  1715. return strtr("Dear %fullname,\n\nSomeone, probably you, just requested that your password for the account\n\t%username\nbe reset. Your new password is\n\t%password\nSince this password has been sent via unencrypted email, you should change it as soon as possible.\n\nIf you didn't request this change, don't worry. Your account password can only ever be mailed to the email address specified in your %site system account. However, if you think someone may be attempting to gain unauthorized access to your account, please contact the system administrator.", $variables);
  1716. case 'dup_delete_subject':
  1717. return strtr("%site Account Update", $variables);
  1718. case 'dup_delete_body':
  1719. return strtr("Dear %fullname,\n\nYou seem to have created a duplicate %site account. You already have an account with the username\n\t%existingusername\ncreated using the email address\n\t%existingemail\nYour second account has been deleted. If you cannot remember your password for the existing account, please use the 'Forgot your password?' feature at\n\t%passwordurl\nand a new password will be emailed to you.\n\nIf the above email address is no longer correct, please reply to this message and request an address change.\n\nThanks,\n%adminname\n" . variable_get('app_org_short_name', 'League') . " Webteam", $variables);
  1720. case 'dup_merge_subject':
  1721. return strtr("%site Account Update", $variables);
  1722. case 'dup_merge_body':
  1723. return strtr("Dear %fullname,\n\nYou seem to have created a duplicate %site account. You already had an account with the username\n\t%existingusername\ncreated using the email address\n\t%existingemail\nTo preserve historical information (registrations, team records, etc.) this old account has been merged with your new information. You will be able to access this account with your newly chosen user name and password.\n\nThanks,\n%adminname\n" . variable_get('app_org_short_name', 'League') . " Webteam", $variables);
  1724. case 'captain_request_subject':
  1725. case 'player_request_subject':
  1726. return strtr("%site Request to Join Team", $variables);
  1727. case 'captain_request_body':
  1728. return strtr("Dear %fullname,\n\nYou have been invited to join the roster of the %site team %team playing on %day in the '%league' league. We ask that you please accept or decline this invitation at your earliest convenience. More details about %team may be found at\n%teamurl\n\nIf you accept the invitation, you will be added to the team's roster and your contact information will be made available to the team captain. If you decline the invitation you will be removed from this team's roster and your contact information will not be made available to the captain. This protocol is in accordance with the %site Privacy Policy.\n\nPlease be advised that players are NOT considered a part of a team roster until they have accepted a captain's request to join. Your team's roster must be completed (minimum of 12 rostered players) by the team roster deadline, and all team members must be listed as a 'regular player' (accepted the captain request).\n\nThanks,\n%adminname\n" . variable_get('app_org_short_name', 'League') . " Webteam", $variables);
  1729. case 'player_request_body':
  1730. return strtr("Dear %captains,\n\n%fullname has requested to join the roster of the %site team %team playing on %day in the '%league' league. We ask that you please accept or decline this request at your earliest convenience. Your team roster may be accessed at\n%teamurl\n\nIf you accept the invitation, %fullname will be added to the team's roster in whatever capacity you assign. If you decline the invitation they will be removed from this team's roster.\n\nPlease be advised that players are NOT considered a part of a team roster until their request to join has been accepted by a captain. Your team's roster must be completed (minimum of 12 rostered players) by the team roster deadline, and all team members must be listed as a 'regular player' (accepted by the captain).\n\nThanks,\n%adminname\n" . variable_get('app_org_short_name', 'League') . " Webteam", $variables);
  1731. case 'score_reminder_subject':
  1732. return strtr("%site Reminder to Submit Score", $variables);
  1733. case 'score_reminder_body':
  1734. return strtr("Dear %fullname,\n\nYou have not yet submitted a score for the game between your team %team and %opponent, which was scheduled for %gamedate in %league. Scores need to be submitted in a timely fashion by both captains to substantiate results and for optimal scheduling of future games. We ask you to please update the score as soon as possible. You can submit the score for this game at\n%scoreurl\n\nThanks,\n%adminname\n" . variable_get('app_org_short_name', 'League') . " Webteam", $variables);
  1735. case 'approval_notice_subject':
  1736. return strtr("%site Notification of Score Approval", $variables);
  1737. case 'approval_notice_body':
  1738. return strtr("Dear %fullname,\n\nYou have not submitted a score for the game between your team %team and %opponent, which was scheduled for %gamedate in %league. Scores need to be submitted in a timely fashion by both captains to substantiate results and for optimal scheduling of future games. Your opponent's submission for this game has been accepted, they have been given a perfect spirit score, and your spirit score has been penalized.\n\nIf there is some reason why you were unable to submit your score in time, you may contact your convener who will consider reversing the penalty. To avoid such penalties in the future, please be sure to submit your scores promptly.\n\nThanks,\n%adminname\n" . variable_get('app_org_short_name', 'League') . " Webteam", $variables);
  1739. default:
  1740. return "Unknown message type '$messagetype'!";
  1741. }
  1742. }
  1743. }
  1744. function person_settings ( )
  1745. {
  1746. $group = form_textfield('Subject of account approval e-mail', 'edit[person_mail_approved_subject]', _person_mail_text('approved_subject'), 70, 180, 'Customize the subject of your approval e-mail, which is sent after account is approved. Available variables are: %username, %site, %url.');
  1747. $group .= form_textarea('Body of account approval e-mail (player)', 'edit[person_mail_approved_body_player]', _person_mail_text('approved_body_player'), 70, 10, 'Customize the body of your approval e-mail, to be sent to players after accounts are approved. Available variables are: %fullname, %memberid, %adminname, %username, %site, %url.');
  1748. $group .= form_textarea('Body of account approval e-mail (visitor)', 'edit[person_mail_approved_body_visitor]', _person_mail_text('approved_body_visitor'), 70, 10, 'Customize the body of your approval e-mail, to be sent to a non-player visitor after account is approved. Available variables are: %fullname, %adminname, %username, %site, %url.');
  1749. $group .= form_textfield('Subject of membership letter e-mail', 'edit[person_mail_member_letter_subject]', _person_mail_text('member_letter_subject'), 70, 180, 'Customize the subject of your membership letter e-mail, which is sent annually after membership is paid for. Available variables are: %fullname, %firstname, %lastname, %site, %year.');
  1750. $group .= form_textarea('Body of membership letter e-mail (player)', 'edit[person_mail_member_letter_body]', _person_mail_text('member_letter_body'), 70, 10, 'Customize the body of your membership letter e-mail, which is sent annually after membership is paid for. If registrations are disabled, or this field is empty, no letters will be sent. Available variables are: %fullname, %firstname, %lastname, %adminname, %site, %year.');
  1751. $group .= form_textfield('Subject of password reset e-mail', 'edit[person_mail_password_reset_subject]', _person_mail_text('password_reset_subject'), 70, 180, 'Customize the subject of your password reset e-mail, which is sent when a user requests a password reset. Available variables are: %site.');
  1752. $group .= form_textarea('Body of password reset e-mail', 'edit[person_mail_password_reset_body]', _person_mail_text('password_reset_body'), 70, 10, 'Customize the body of your password reset e-mail, which is sent when a user requests a password reset. Available variables are: %fullname, %adminname, %username, %password, %site, %url.');
  1753. $group .= form_textfield('Subject of duplicate account deletion e-mail', 'edit[person_mail_dup_delete_subject]', _person_mail_text('dup_delete_subject'), 70, 180, 'Customize the subject of your account deletion mail, sent to a user who has created a duplicate account. Available variables are: %site.');
  1754. $group .= form_textarea('Body of duplicate account deletion e-mail', 'edit[person_mail_dup_delete_body]', _person_mail_text('dup_delete_body'), 70, 10, 'Customize the body of your account deletion e-mail, sent to a user who has created a duplicate account. Available variables are: %fullname, %adminname, %existingusername, %existingemail, %site, %passwordurl.');
  1755. $group .= form_textfield('Subject of duplicate account merge e-mail', 'edit[person_mail_dup_merge_subject]', _person_mail_text('dup_merge_subject'), 70, 180, 'Customize the subject of your account merge mail, sent to a user who has created a duplicate account. Available variables are: %site.');
  1756. $group .= form_textarea('Body of duplicate account merge e-mail', 'edit[person_mail_dup_merge_body]', _person_mail_text('dup_merge_body'), 70, 10, 'Customize the body of your account merge e-mail, sent to a user who has created a duplicate account. Available variables are: %fullname, %adminname, %existingusername, %existingemail, %site, %passwordurl.');
  1757. $group .= form_textfield('Subject of captain request e-mail', 'edit[person_mail_captain_request_subject]', _person_mail_text('captain_request_subject'), 70, 180, 'Customize the subject of your captain request mail, sent to a user who has been invited to join a team. Available variables are: %site, %fullname, %captain, %team, %league, %day, %adminname.');
  1758. $group .= form_textarea('Body of captain request e-mail', 'edit[person_mail_captain_request_body]', _person_mail_text('captain_request_body'), 70, 10, 'Customize the body of your captain request e-mail, sent to a user who has been invited to join a team. Available variables are: %site, %fullname, %captain, %team, %teamurl, %league, %day, %adminname.');
  1759. $group .= form_textfield('Subject of player request e-mail', 'edit[person_mail_player_request_subject]', _person_mail_text('player_request_subject'), 70, 180, 'Customize the subject of your player request mail, sent to captains when a player asks to join their team. Available variables are: %site, %fullname, %team, %league, %day, %adminname.');
  1760. $group .= form_textarea('Body of player request e-mail', 'edit[person_mail_player_request_body]', _person_mail_text('player_request_body'), 70, 10, 'Customize the body of your player request e-mail, sent to captains when a player asks to join their team. Available variables are: %site, %fullname, %captains, %team, %teamurl, %league, %day, %adminname.');
  1761. $group .= form_textfield('Subject of score reminder e-mail', 'edit[person_mail_score_reminder_subject]', _person_mail_text('score_reminder_subject'), 70, 180, 'Customize the subject of your score reminder mail, sent to captains when they have not submitted a score in a timely fashion. Available variables are: %site, %fullname, %team, %opponent, %league, %gamedate, %scoreurl, %adminname.');
  1762. $group .= form_textarea('Body of score reminder e-mail', 'edit[person_mail_score_reminder_body]', _person_mail_text('score_reminder_body'), 70, 10, 'Customize the body of your score reminder e-mail, sent to captains when they have not submitted a score in a timely fashion. Available variables are: %site, %fullname, %team, %opponent, %league, %gamedate, %scoreurl, %adminname.');
  1763. $group .= form_textfield('Subject of approval notice e-mail', 'edit[person_mail_approval_notice_subject]', _person_mail_text('approval_notice_subject'), 70, 180, 'Customize the subject of your approval notice mail, sent to captains when a game has been approved without a score submission from them. Available variables are: %site, %fullname, %team, %opponent, %league, %gamedate, %scoreurl, %adminname.');
  1764. $group .= form_textarea('Body of approval notice e-mail', 'edit[person_mail_approval_notice_body]', _person_mail_text('approval_notice_body'), 70, 10, 'Customize the body of your approval notice e-mail, sent to captains when a game has been approved without a score submission from them. Available variables are: %site, %fullname, %team, %opponent, %league, %gamedate, %scoreurl, %adminname.');
  1765. $output = form_group('User email settings', $group);
  1766. return settings_form($output);
  1767. }
  1768. function person_statistics ( )
  1769. {
  1770. global $dbh;
  1771. $rows = array();
  1772. $sth = $dbh->prepare('SELECT status, COUNT(*) FROM person GROUP BY status');
  1773. $sth->execute();
  1774. $sub_table = array();
  1775. $sum = 0;
  1776. while($row = $sth->fetch(PDO::FETCH_NUM)) {
  1777. $sub_table[] = $row;
  1778. $sum += $row[1];
  1779. }
  1780. $sub_table[] = array('Total', $sum);
  1781. $rows[] = array('Players by account status:', table(null, $sub_table));
  1782. $sth = $dbh->prepare('SELECT class, COUNT(*) FROM person GROUP BY class');
  1783. $sth->execute();
  1784. $sub_table = $sth->fetchAll(PDO::FETCH_NUM);
  1785. $rows[] = array('Players by account class:', table(null, $sub_table));
  1786. $sth = $dbh->prepare('SELECT gender, COUNT(*) FROM person GROUP BY gender');
  1787. $sth->execute();
  1788. $sub_table = $sth->fetchAll(PDO::FETCH_NUM);
  1789. $rows[] = array('Players by gender:', table(null, $sub_table));
  1790. $sth = $dbh->prepare('SELECT FLOOR((YEAR(NOW()) - YEAR(birthdate)) / 5) * 5 as age_bucket, COUNT(*) AS count FROM person GROUP BY age_bucket');
  1791. $sth->execute();
  1792. $sub_table = array();
  1793. while($row = $sth->fetch(PDO::FETCH_ASSOC)) {
  1794. $sub_table[] = array($row['age_bucket'] . ' to ' . ($row['age_bucket'] + 4), $row['count']);
  1795. }
  1796. $rows[] = array('Players by age:', table(null, $sub_table));
  1797. $sth = $dbh->prepare('SELECT addr_city, COUNT(*) AS num FROM person GROUP BY addr_city HAVING num > 2 ORDER BY num DESC');
  1798. $sth->execute();
  1799. $sub_table = $sth->fetchAll(PDO::FETCH_NUM);
  1800. $rows[] = array('Players by city:', table(null, $sub_table));
  1801. $sth = $dbh->prepare('SELECT skill_level, COUNT(*) FROM person GROUP BY skill_level');
  1802. $sth->execute();
  1803. $sub_table = $sth->fetchAll(PDO::FETCH_NUM);
  1804. $rows[] = array('Players by skill level:', table(null, $sub_table));
  1805. $sth = $dbh->prepare('SELECT year_started, COUNT(*) FROM person GROUP BY year_started');
  1806. $sth->execute();
  1807. $sub_table = $sth->fetchAll(PDO::FETCH_NUM);
  1808. $rows[] = array('Players by starting year:', table(null, $sub_table));
  1809. if (variable_get('dog_questions', 1)) {
  1810. $sth = $dbh->prepare("SELECT COUNT(*) FROM person where has_dog = 'Y'");
  1811. $sth->execute();
  1812. $rows[] = array('Players with dogs :', $sth->fetchColumn());
  1813. }
  1814. $output = "<div class='pairtable'>" . table(null, $rows) . "</div>";
  1815. return form_group('Player Statistics', $output);
  1816. }
  1817. ?>