PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/pacore/web/BlockModules/UserContactsModule/UserContactsModule.php

https://github.com/DigitalCityMechanics/PeopleAggregator
PHP | 477 lines | 417 code | 29 blank | 31 comment | 32 complexity | 094ee50d6c60ed27aa5d3a38e45059f1 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, LGPL-2.1
  1. <?php
  2. /** !
  3. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4. * [filename] is a part of PeopleAggregator.
  5. * [description including history]
  6. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7. * @author [creator, or "Original Author"]
  8. * @license http://bit.ly/aVWqRV PayAsYouGo License
  9. * @copyright Copyright (c) 2010 Broadband Mechanics
  10. * @package PeopleAggregator
  11. */
  12. ?>
  13. <?php
  14. error_reporting(E_ALL);
  15. require_once "api/User/UserContact.class.php";
  16. require_once "web/includes/classes/xHtml.class.php";
  17. require_once "web/includes/classes/CSVParser.class.php";
  18. include_once( "api/ProfileIO/map/CSVDataMapper.class.php");
  19. require_once "api/Messaging/MessageDispatcher.class.php";
  20. class UserContactsModule extends Module {
  21. public $module_type = 'user';
  22. public $module_placement = 'middle';
  23. private $contacts;
  24. private $type;
  25. private $types = array('import', 'plaxo', 'mslive', 'linkedin', 'outlook');
  26. private $valid_cvs_mime_types = array('application/octet-stream', 'text/csv', 'text/plain', 'application/vnd.ms-excel');
  27. function __construct() {
  28. parent::__construct();
  29. $this->title = __('Contacts');
  30. $this->outer_template = "outer_public_center_edit_profile_module.tpl";
  31. $this->contacts = array();
  32. }
  33. function initializeModule($request_method, $request_data) {
  34. $this->type = (!empty($request_data['stype'])) ? $request_data['stype'] : 'import';
  35. $invite_message = (!empty($request_data['message'])) ? $request_data['message'] : CUSTOM_INVITATION_MESSAGE;
  36. switch($this->type) {
  37. case 'import':
  38. if(!empty($request_data['import_type'])) {
  39. switch($request_data['import_type']) {
  40. case 'plaxo':
  41. case 'mslive':
  42. case 'linkedin':
  43. case 'outlook':
  44. $this->prepareImportContacts($request_data);
  45. break;
  46. default:
  47. }
  48. }
  49. break;
  50. case 'plaxo':
  51. $this->contacts = $this->getUserContacts((int)PA::$login_uid, 'plaxo');
  52. break;
  53. case 'mslive':
  54. $this->contacts = $this->getUserContacts((int)PA::$login_uid, 'mslive');
  55. break;
  56. case 'linkedin':
  57. $this->contacts = $this->getUserContacts((int)PA::$login_uid, 'linkedin');
  58. break;
  59. case 'outlook':
  60. $this->contacts = $this->getUserContacts((int)PA::$login_uid, 'outlook');
  61. break;
  62. default:
  63. }
  64. $this->set_inner_template("contacts_main.tpl");
  65. if(($request_method != 'POST') && ($request_method != 'AJAX')) {
  66. $this->inner_HTML = $this->generate_inner_html(array('type' => 'contacts',
  67. 'stype' => $this->type,
  68. 'message' => $invite_message,
  69. 'active_tab' => 1 + array_search($this->type, $this->types),
  70. 'contacts' => $this->contacts
  71. ));
  72. }
  73. }
  74. function handleRequest($request_method, $request_data) {
  75. if(!empty($request_data['action'])) {
  76. $action = $request_data['action'];
  77. $class_name = get_class($this);
  78. switch($request_method) {
  79. case 'POST':
  80. $method_name = 'handlePOST_'. $action;
  81. if(method_exists($this, $method_name)) {
  82. $this->{$method_name}($request_data);
  83. } else {
  84. throw new Exception("$class_name error: Unhandled POST action - \"$action\" in request." );
  85. }
  86. break;
  87. case 'GET':
  88. $method_name = 'handleGET_'. $action;
  89. if(method_exists($this, $method_name)) {
  90. $this->{$method_name}($request_data);
  91. } else {
  92. throw new Exception("$class_name error: Unhandled GET action - \"$action\" in request." );
  93. }
  94. break;
  95. case 'AJAX':
  96. $method_name = 'handleAJAX_'. $action;
  97. if(method_exists($this, $method_name)) {
  98. $this->{$method_name}($request_data);
  99. } else {
  100. throw new Exception("$class_name error: Unhandled AJAX action - \"$action\" in request." );
  101. }
  102. break;
  103. }
  104. }
  105. }
  106. private function handlePOST_import_contacts($request_data) {
  107. // echo "<pre>" . print_r($request_data, 1) . "</pre>";
  108. // echo "<pre>" . print_r($this->contacts, 1) . "</pre>";
  109. $msg = null;
  110. $nb_imported = 0;
  111. try {
  112. foreach($this->contacts as $contact) {
  113. $params = array("user_id" => PA::$login_uid,
  114. "contact_name" => $contact['name'],
  115. "contact_email" => $contact['email'],
  116. "contact_extra" => serialize($contact['profile']),
  117. "contact_type" => $request_data['import_type']
  118. );
  119. UserContact::insertUserContact($params);
  120. $nb_imported++;
  121. // echo "<pre>" . print_r($params, 1) . "</pre>";
  122. }
  123. $msg = $nb_imported . __(' contact(s) sucessfully imported');
  124. } catch(Exception $e) {
  125. $msg = $e->getMessage();
  126. }
  127. $redirect_url = PA::$url.PA_ROUTE_USER_CONTACTS . "?type=contacts&stype=" . $request_data['import_type'] . "&msg=" . urlencode($msg);
  128. $this->controller->redirect($redirect_url);
  129. /*
  130. $this->inner_HTML = $this->generate_inner_html(array('type' => 'contacts',
  131. 'stype' => $this->type,
  132. 'active_tab' => 1 + array_search($this->type, $this->types)
  133. ));
  134. */
  135. }
  136. private function handlePOST_importLinkedInCSV($request_data) {
  137. // echo "<pre>" . print_r($request_data, 1) . "</pre>";
  138. // echo "<pre>" . print_r($_FILES, 1) . "</pre>";
  139. $error = '';
  140. $html = '';
  141. if(!empty($_FILES['linkedin_csv']['name']) && is_uploaded_file($_FILES['linkedin_csv']['tmp_name'])) {
  142. $ext = strtolower(end(explode('.', $_FILES['linkedin_csv']['name'])));
  143. if(!in_array($_FILES['linkedin_csv']['type'], $this->valid_cvs_mime_types) || ($ext != 'csv')) {
  144. // $html = htmlspecialchars("<pre>" . print_r($_FILES, 1) . "</pre>");
  145. $error = __('Invalid file type. Please select a valid LinkedIn CSV file. ');
  146. } else {
  147. try {
  148. $content = file_get_contents($_FILES['linkedin_csv']['tmp_name']);
  149. $csv_parser = new CSVParser($content);
  150. $contacts = $csv_parser->getCSVContacts('CSVDataMapper', true);
  151. if(!$contacts) $error = $csv_parser->lastError;
  152. $this->deleteWithoutEmail($contacts, $csv_parser->mapped_contacts);
  153. $templ = PA::$blockmodule_path .'/'. get_class($this) . "/linkedin_list.tpl";
  154. $html_gen = new Template($templ);
  155. $html_gen->set('contacts', $contacts);
  156. $html_gen->set('mapped_contacts', $csv_parser->mapped_contacts);
  157. $html = $html_gen->fetch();
  158. } catch (Exception $e) {
  159. $error = $e->getMessage();
  160. }
  161. }
  162. } else {
  163. $error = __('Please, select a valid LinkedIn CSV file.');
  164. }
  165. echo "{";
  166. echo "error: '" . $error . "',\n";
  167. echo "content: '" . base64_encode(htmlspecialchars($html)) . "'\n";
  168. echo "}";
  169. exit;
  170. }
  171. private function handlePOST_importOutlookCSV($request_data) {
  172. // echo "<pre>" . print_r($request_data, 1) . "</pre>";
  173. // echo "<pre>" . print_r($_FILES, 1) . "</pre>";
  174. $error = '';
  175. $html = '';
  176. if(!empty($_FILES['outlook_csv']['name']) && is_uploaded_file($_FILES['outlook_csv']['tmp_name'])) {
  177. $ext = strtolower(end(explode('.', $_FILES['outlook_csv']['name'])));
  178. if(!in_array($_FILES['outlook_csv']['type'], $this->valid_cvs_mime_types) || ($ext != 'csv')) {
  179. // $html = htmlspecialchars("<pre>" . print_r($_FILES, 1) . "</pre>");
  180. $error = __('Invalid file type. Please select a valid Outlook CSV file. ');
  181. } else {
  182. try {
  183. $content = file_get_contents($_FILES['outlook_csv']['tmp_name']);
  184. $csv_parser = new CSVParser($content);
  185. $contacts = $csv_parser->getCSVContacts('CSVDataMapper', true);
  186. if(!$contacts) $error = $csv_parser->lastError;
  187. $this->deleteWithoutEmail($contacts, $csv_parser->mapped_contacts);
  188. $templ = PA::$blockmodule_path .'/'. get_class($this) . "/outlook_list.tpl";
  189. $html_gen = new Template($templ);
  190. $html_gen->set('contacts', $contacts);
  191. $html_gen->set('mapped_contacts', $csv_parser->mapped_contacts);
  192. $html = $html_gen->fetch();
  193. } catch (Exception $e) {
  194. $error = $e->getMessage();
  195. }
  196. }
  197. } else {
  198. $error = __('Please, select a valid Outlook CSV file.');
  199. }
  200. /*
  201. echo "Error: $error <br />";
  202. echo "Contacts: <pre>" . print_r($contacts, 1) . "</pre>";
  203. echo "Mapped Contacts: <pre>" . print_r($csv_parser->mapped_contacts, 1) . "</pre>";
  204. */
  205. echo "{";
  206. echo "error: '" . $error . "',\n";
  207. echo "content: '" . base64_encode(htmlspecialchars($html)) . "'\n";
  208. echo "}";
  209. exit;
  210. }
  211. private function deleteWithoutEmail(&$contacts_list, &$mapped_contacts) {
  212. for($cnt = 0; $cnt < count($contacts_list); $cnt++) {
  213. if($contacts_list[$cnt]['email'] == "-no email address-") {
  214. unset($contacts_list[$cnt]);
  215. unset($mapped_contacts[$cnt]);
  216. }
  217. }
  218. }
  219. private function handlePOST_inviteSelected($request_data) {
  220. $message = trim($request_data['message']);
  221. if(empty($message)) {
  222. $msg = __("Invite message can't be empty.");
  223. } else {
  224. $msg = null;
  225. $message = nl2br($message);
  226. $selected_contacts = (!empty($request_data['invite_selected'])) ? $request_data['invite_selected'] : null;
  227. if($selected_contacts) {
  228. foreach($selected_contacts as $key => $cntct_id) {
  229. $contact = $this->contacts[$key]; // selected index = contacts index
  230. $inv = new Invitation();
  231. $inv->user_id = PA::$login_uid;
  232. $inv->username = PA::$login_user->login_name;
  233. $user = PA::$login_user;
  234. // for invitation not for any group invitation collection id is -1
  235. $inv->inv_collection_id = -1;
  236. $inv->inv_status = INVITATION_PENDING;
  237. $auth_token = get_invitation_token(LONG_EXPIRES, $contact['email']);
  238. $token = '&amp;token='.$auth_token;
  239. $link_desc = wordwrap(PA::$url . "/register.php?InvID=$inv->inv_id", 120, "<br>", 1);
  240. $inv->register_url = "<a href=\"". PA::$url . "/register.php?InvID=$inv->inv_id\">$link_desc</a>";
  241. $acc_link_desc = wordwrap(PA::$url . "/login.php?action=accept&InvID=$inv->inv_id$token", 120, "<br>", 1);
  242. $inv->accept_url = "<a href=\"". PA::$url . "/login.php?action=accept&InvID=$inv->inv_id$token\">$acc_link_desc</a>";
  243. $inv->inv_user_id = NULL;
  244. $inv->inv_user_first_name = $contact['name'];
  245. $inv->inv_email = $contact['email'];
  246. $inv->inv_summary = "Invitation from $user->first_name $user->last_name to join ".PA::$site_name;
  247. if($message != CUSTOM_INVITATION_MESSAGE){
  248. $inv->inv_message = !empty($message) ? $message : null;
  249. }
  250. try {
  251. $inv->send();
  252. }
  253. catch (PAException $e) {
  254. $msg = "$e->message";
  255. $save_error = true;
  256. }
  257. if(isset($save_error) && ($save_error == true)) {
  258. $msg = "Sorry: you are unable to invite a friend. <br /> Reason: " . $msg;
  259. } else {
  260. // invitation has been sent, now send mail
  261. PAMail::send('invite_pa', $inv->inv_email, PA::$login_user, $inv);
  262. $msg .= "<br />" . $contact['name'] . ", " . $contact['email'];
  263. }
  264. } // end for : invitation to multiple email
  265. $msg = "<br />Invitation message has been sent to: " . $msg;
  266. } else {
  267. $msg = __("Please, select one or more contacts.");
  268. }
  269. }
  270. $redirect_url = PA::$url . PA_ROUTE_USER_CONTACTS . "?type=contacts&stype=" . $this->type . "&msg=" . urlencode($msg);
  271. $this->controller->redirect($redirect_url);
  272. }
  273. private function handlePOST_deleteSelected($request_data) {
  274. $selected_contacts = (!empty($request_data['invite_selected'])) ? $request_data['invite_selected'] : null;
  275. if($selected_contacts) {
  276. $cnt = 0;
  277. foreach($selected_contacts as $key => $cntct_id) {
  278. try {
  279. UserContact::deleteUserContact($cntct_id);
  280. $cnt++;
  281. }
  282. catch(Exception $e) {
  283. $msg = $e->getMessage();
  284. }
  285. }
  286. $msg = $cnt . __(" contact(s) sucessfully deleted.");
  287. } else {
  288. $msg = __("Please, select one or more contacts.");
  289. }
  290. $redirect_url = PA::$url . PA_ROUTE_USER_CONTACTS . "?type=contacts&stype=" . $this->type . "&msg=" . urlencode($msg);
  291. $this->controller->redirect($redirect_url);
  292. }
  293. private function handleAJAX_contactDetails($request_data) {
  294. $id = $request_data['contact_id'];
  295. $contact = UserContact::getUserContact( $id );
  296. if(!empty($contact) && is_object($contact)) {
  297. $html = null;
  298. $name = $contact->get_contact_name();
  299. $email = $contact->get_contact_email();
  300. $contact_extra = unserialize($contact->get_contact_extra());
  301. if(!empty($contact_extra['general'])) {
  302. if(!empty($contact_extra['general']['dob'])) {
  303. $bday_info = date_parse($contact_extra['general']['dob']);
  304. $bday = date("F dS", mktime(0, 0, 0, $bday_info['month'], $bday_info['day'], 0));
  305. $contact_extra['general']['dob'] = $bday;
  306. }
  307. $html .= "<h4 style=\"margin: 0px;\">" . __("General") . "</h4>";
  308. $li_contents = $this->buildHtmlList($contact_extra['general']);
  309. $html .= xHtml::ulistTag($li_contents, array("style" => "list-style-type: none; display: inline;"));
  310. }
  311. if(!empty($contact_extra['personal'])) {
  312. if(!empty($contact_extra['personal']['picture'])) {
  313. $img_url = $this->normalizeImgUrl($contact_extra['personal']['picture']);
  314. $img_url = PA::$url.'/resize_img.php?src='. $img_url .'&height=98&width=98';
  315. $contact_extra['personal']['picture'] = "<img src=\"$img_url\" alt=\"picture\" title=\"picture\" />";
  316. }
  317. $html .= "<h4 style=\"margin: 0px;\">" . __("Personal") . "</h4>";
  318. $li_contents = $this->buildHtmlList($contact_extra['personal']);
  319. $html .= xHtml::ulistTag($li_contents, array("style" => "list-style-type: none; display: inline;"));
  320. }
  321. if(!empty($contact_extra['professional'])) {
  322. $html .= "<h4 style=\"margin: 0px;\">" . __("Professional") . "</h4>";
  323. $li_contents = $this->buildHtmlList($contact_extra['professional']);
  324. $html .= xHtml::ulistTag($li_contents, array("style" => "list-style-type: none; display: inline;"));
  325. }
  326. if(!empty($contact_extra['extra'])) {
  327. if(!empty($contact_extra['extra']['business_photo'])) {
  328. $img_url = $this->normalizeImgUrl($contact_extra['extra']['business_photo']);
  329. $img_url = PA::$url.'/resize_img.php?src='. $img_url .'&height=98&width=98';
  330. $contact_extra['extra']['business_photo'] = "<img src=\"$img_url\" alt=\"picture\" title=\"picture\" />";
  331. }
  332. $html .= "<h4 style=\"margin: 0px;\">" . __("Other") . "</h4>";
  333. $li_contents = $this->buildHtmlList($contact_extra['extra']);
  334. $html .= xHtml::ulistTag($li_contents, array("style" => "list-style-type: none; display: inline;"));
  335. }
  336. echo $html;
  337. } else {
  338. echo __("No details.");
  339. }
  340. exit;
  341. }
  342. private function buildHtmlList($data) {
  343. $output = array();
  344. if(!is_array($data)) {
  345. $data = array($data);
  346. }
  347. foreach($data as $key => $value) {
  348. $key_upcs = ucfirst(strtr($key, array("_" => " ")));
  349. if(!preg_match("#</?[a-z][a-z0-9]*[^<>]*>#", $value)) {
  350. $value = wordwrap($value, 22, "<br />\n", true);
  351. }
  352. $html = "<ul style=\"padding-left: 12px;\">
  353. <li style=\"width:84px; display: table-cell;\">$key_upcs:</li>
  354. <li style=\"display: table-cell;\">$value</li>
  355. </ul>
  356. ";
  357. $output[] = $html;
  358. }
  359. return $output;
  360. }
  361. private function getUserContacts($user_id, $type) {
  362. $contacts_list = array();
  363. $contacts = UserContact::listUserContact( "user_id=$user_id AND contact_type='$type'" );
  364. foreach($contacts as $contact) {
  365. $name = $contact->get_contact_name();
  366. $email = $contact->get_contact_email();
  367. $contact_extra = unserialize($contact->get_contact_extra());
  368. $contacts_list[] = array('cont_id' => $contact->get_id(),
  369. 'name' => $name,
  370. 'email' => $email,
  371. 'picture' => $this->getContactPicture($contact_extra),
  372. 'general' => (!empty($contact_extra['general'])) ? $contact_extra['general'] : null,
  373. 'personal' => (!empty($contact_extra['personal'])) ? $contact_extra['personal'] : null,
  374. 'professional' => (!empty($contact_extra['professional'])) ? $contact_extra['professional'] : null,
  375. 'extra' => (!empty($contact_extra['extra'])) ? $contact_extra['extra'] : null
  376. );
  377. }
  378. return $contacts_list;
  379. }
  380. private function getContactPicture($contact_extra) {
  381. if(!empty($contact_extra['personal']['picture'])) {
  382. $img_url = $this->normalizeImgUrl($contact_extra['personal']['picture']);
  383. $picture_url = PA::$url.'/resize_img.php?src='. $img_url .'&height=98&width=98';
  384. } else if(!empty($contact_extra['extra']['business_photo'])) { // Plaxo contacts can have BusinessPhoto data field
  385. $img_url = $this->normalizeImgUrl($contact_extra['extra']['business_photo']);
  386. $picture_url = PA::$url.'/resize_img.php?src='. $img_url .'&height=98&width=98';
  387. } else {
  388. $picture_url = PA::$url.'/resize_img.php?src=' . PA::$theme_url . '/images/default.png' . '&height=98&width=98';
  389. }
  390. return $picture_url;
  391. }
  392. private function normalizeImgUrl($url) {
  393. $outdata = null;
  394. if(false === strpos($url, "http://")) {
  395. $outdata = "http://" . $url;
  396. } else {
  397. $outdata = $url;
  398. }
  399. return $outdata;
  400. }
  401. private function prepareImportContacts($request_data) {
  402. $mapped_contacts = unserialize(base64_decode($request_data['contacts_encoded']));
  403. foreach($request_data['contact'] as $key => $value) {
  404. if(!empty($value['email'])) {
  405. $this->contacts[] = array('name' => $value['name'], 'email' => $value['email'], 'profile' => $mapped_contacts[$key]);
  406. }
  407. }
  408. }
  409. function set_inner_template($template_fname) {
  410. $this->inner_template = PA::$blockmodule_path .'/'. get_class($this) . "/$template_fname";
  411. }
  412. function render() {
  413. $content = parent::render();
  414. return $content;
  415. }
  416. function generate_inner_html($template_vars = array()) {
  417. $inner_html_gen = new Template($this->inner_template);
  418. foreach($template_vars as $name => $value) {
  419. if(is_object($value)) {
  420. $inner_html_gen->set_object($name, $value);
  421. } else {
  422. $inner_html_gen->set($name, $value);
  423. }
  424. }
  425. $inner_html = $inner_html_gen->fetch();
  426. return $inner_html;
  427. }
  428. }