cis_service_connection.module

  1. cis7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  2. cle7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  3. ecd7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  4. elmsmedia7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  5. harmony7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  6. icor7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  7. meedjum_blog7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
  8. mooc7 sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module

Define links for a unified experience across systems.

Functions

Namesort descending Description
cis_service_connection_admin_paths Implements hook_admin_paths().
cis_service_connection_block_info Implements hook_block_info().
cis_service_connection_block_instructor_contact Callback for instructor contact block content.
cis_service_connection_block_section_context_changer_form Callback to render a list of optional section contexts to cycle through
cis_service_connection_block_section_context_changer_form_submit Submit handler for the context changer block.
cis_service_connection_block_section_outline Render a block based on section context
cis_service_connection_block_view Implements hook_block_view().
cis_service_connection_cron Implements hook_cron().
cis_service_connection_get_footer_language Helper function to set footer language from CIS.
cis_service_connection_load_group Return a group node when passed a section string.
cis_service_connection_menu Implements hook_menu().
cis_service_connection_permission Implements hook_permission().
_cis_service_connection_edit_property Callback to provide contextual link to correct location
_cis_service_connection_expire_roles Handle Role expiration.
_cis_service_connection_get_users_in_group Get all students of a group.
_cis_service_connection_initial_cis_bind Initial cron job to formally bind the CIS Service to the CIS.
_cis_service_connection_links return array of links we support
_cis_service_connection_page Callback to assemble pages correctly.

Constants

Namesort descending Description
CIS_SERVICE_CONNECTION_HOMEPAGE
CIS_SERVICE_CONNECTION_SYNC_FREQUENCY @file Define links for a unified experience across systems.

File

sites/all/modules/elmsln_contrib/cis_connector/modules/cis_service_connection/cis_service_connection.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Define links for a unified experience across systems.
  5. */
  6. define('CIS_SERVICE_CONNECTION_SYNC_FREQUENCY', 1);
  7. define('CIS_SERVICE_CONNECTION_HOMEPAGE', 'welcome_page');
  8. /**
  9. * return array of links we support
  10. */
  11. function _cis_service_connection_links() {
  12. return array('welcome_page', 'syllabus', 'course-help', 'resources');
  13. }
  14. /**
  15. * Implements hook_block_info().
  16. */
  17. function cis_service_connection_block_info() {
  18. $blocks = array(
  19. 'active_outline' => array(
  20. 'info' => t('Instructional Outline'),
  21. 'cache' => DRUPAL_CACHE_PER_USER,
  22. ),
  23. 'instructor_contact' => array(
  24. 'info' => t('Instructor Contact info'),
  25. 'cache' => DRUPAL_CACHE_PER_USER,
  26. ),
  27. 'section_context_changer' => array(
  28. 'info' => t('Change Section context'),
  29. 'cache' => DRUPAL_CACHE_PER_USER,
  30. ),
  31. );
  32. return $blocks;
  33. }
  34. /**
  35. * Implements hook_block_view().
  36. */
  37. function cis_service_connection_block_view($delta = '') {
  38. $block = array();
  39. switch ($delta) {
  40. case 'active_outline':
  41. $block = cis_service_connection_block_section_outline();
  42. break;
  43. case 'instructor_contact':
  44. $block['subject'] = t('Instructor Contact');
  45. $block['content'] = cis_service_connection_block_instructor_contact();
  46. break;
  47. case 'section_context_changer':
  48. if (user_access('switch section context')) {
  49. $block['subject'] = t('Section change');
  50. $block['content'] = drupal_get_form('cis_service_connection_block_section_context_changer_form');
  51. }
  52. break;
  53. }
  54. return $block;
  55. }
  56. /**
  57. * Implements hook_permission().
  58. */
  59. function cis_service_connection_permission() {
  60. return array(
  61. 'switch section context' => array(
  62. 'title' => t('Switch Section context'),
  63. 'description' => t('Allows user to utilize a block that switches the reported section context.'),
  64. ),
  65. );
  66. }
  67. /**
  68. * Implements hook_menu().
  69. */
  70. function cis_service_connection_menu() {
  71. $items = array();
  72. // section specific language, or generic based on context
  73. $items['welcome_page'] = array(
  74. 'title' => 'Welcome',
  75. 'page callback' => '_cis_connector_transaction',
  76. 'page arguments' => array(0),
  77. 'menu_name' => 'main-menu',
  78. 'weight' => -1,
  79. 'access arguments' => array('access content'),
  80. );
  81. // standard language from cis
  82. $items['syllabus'] = array(
  83. 'title' => 'Syllabus',
  84. 'page callback' => '_cis_connector_transaction',
  85. 'page arguments' => array(0),
  86. 'menu_name' => 'main-menu',
  87. 'weight' => 0,
  88. 'access arguments' => array('access content'),
  89. );
  90. // standard language from cis for help
  91. $items['course-help'] = array(
  92. 'title' => 'Help',
  93. 'page callback' => '_cis_service_connection_page',
  94. 'page arguments' => array(0),
  95. 'menu_name' => 'main-menu',
  96. 'weight' => 1,
  97. 'access arguments' => array('access content'),
  98. );
  99. // standard language from cis
  100. $items['resources'] = array(
  101. 'title' => 'Resources',
  102. 'page callback' => '_cis_service_connection_page',
  103. 'page arguments' => array(0),
  104. 'menu_name' => 'main-menu',
  105. 'weight' => 2,
  106. 'access arguments' => array('access content'),
  107. );
  108. // direct download of the welcome letter, useful for remote referencing
  109. $items['welcome_page/download'] = array(
  110. 'title' => 'Letter',
  111. 'page callback' => '_cis_connector_transaction',
  112. 'page arguments' => array('welcome_letter', 1),
  113. 'type' => MENU_LOCAL_TASK,
  114. 'weight' => 2,
  115. 'access arguments' => array('access content'),
  116. );
  117. // direct download of the syllabus, useful for remote referencing
  118. $items['syllabus/download'] = array(
  119. 'title' => 'Download',
  120. 'page callback' => '_cis_connector_transaction',
  121. 'page arguments' => array(0, 1),
  122. 'type' => MENU_LOCAL_TASK,
  123. 'weight' => 2,
  124. 'access arguments' => array('access content'),
  125. );
  126. // build tabs for pages
  127. $vals = _cis_service_connection_links();
  128. foreach ($vals as $val) {
  129. $items[$val . '/view'] = array(
  130. 'title' => 'View',
  131. 'page callback' => '_cis_connector_transaction',
  132. 'page arguments' => array(0),
  133. 'menu_name' => 'main-menu',
  134. 'weight' => 0,
  135. 'access arguments' => array('access content'),
  136. 'type' => MENU_DEFAULT_LOCAL_TASK
  137. );
  138. $items[$val . '/edit'] = array(
  139. 'title' => 'Edit',
  140. 'page callback' => '_cis_service_connection_edit_property',
  141. 'page arguments' => array(0),
  142. 'weight' => 1,
  143. 'access callback' => 'cis_connector_role_access',
  144. 'access arguments' => array(array('administrator', 'instructor', 'staff')),
  145. 'type' => MENU_LOCAL_TASK,
  146. );
  147. }
  148. return $items;
  149. }
  150. /**
  151. * Callback to provide contextual link to correct location
  152. */
  153. function _cis_service_connection_edit_property($property) {
  154. $section = _cis_connector_transaction('section');
  155. $path = _cis_connector_real_address($section['url']) . '/edit';
  156. return '<iframe width="100%" height="600px" src="' . $path . '"></iframe>';
  157. }
  158. /**
  159. * Callback to assemble pages correctly.
  160. */
  161. function _cis_service_connection_page($request) {
  162. $output = '';
  163. $suffix = '';
  164. if ($request == 'course-help') {
  165. $request = 'help';
  166. }
  167. // allow for per option processing
  168. switch ($request) {
  169. case 'help':
  170. // first thing student sees is instructor contact info
  171. $info = _cis_connector_transaction('contact_info');
  172. // render text applying the input filter requested
  173. if (isset($info['value'])) {
  174. $suffix .= '<h2>' . t('Instructor Contact') . '</h2>' . $info['value'];
  175. }
  176. break;
  177. }
  178. // apply traditional transaction for the request
  179. $body = _cis_connector_transaction($request);
  180. if (isset($body['value'])) {
  181. $body['value'] = $suffix . $body['value'];
  182. // check the markup of the format
  183. $output .= check_markup($body['value'], $body['format']);
  184. }
  185. return $output;
  186. }
  187. /**
  188. * Implements hook_cron().
  189. */
  190. function cis_service_connection_cron() {
  191. $frequency = variable_get('cis_service_connection_sync_frequency', CIS_SERVICE_CONNECTION_SYNC_FREQUENCY);
  192. $interval['interval'] = 86400 * $frequency;
  193. $interval['weekly'] = 86400 * 7 * $frequency;
  194. $interval['monthly'] = 86400 * 28 * $frequency;
  195. $interval['yearly'] = 86400 * 365 * $frequency;
  196. // if last sync isn't set this is the first cron run
  197. if (variable_get('cis_service_connection_last_sync', 0) == 0) {
  198. // perform the initial setup routine
  199. // this will help bind the CIS to this instance of the service
  200. _cis_service_connection_initial_cis_bind();
  201. // if initial bind then end early
  202. return TRUE;
  203. }
  204. // see if this is just beyond the initial run
  205. if (variable_get('cis_service_connection_initial', FALSE)) {
  206. // select the instance uuid
  207. $select = array(
  208. 'type' => 'service_instance',
  209. 'uuid' => variable_get('cis_service_instance_uuid', ''),
  210. );
  211. // cron key is critical that its set this needs to happen
  212. // on a second pass running of local cron this is because
  213. // during installation we might not have a connection to
  214. // the CIS established based on install order.
  215. $data = array(
  216. 'field_cron_key' => variable_get('cron_key', ''),
  217. );
  218. // set the data in the CIS
  219. _cis_connection_set_data($select, $data);
  220. // ask for the LTI request that will be recognized locally
  221. if (module_exists('cis_service_lti')) {
  222. _cis_service_lti_get_consumer();
  223. }
  224. // delete this variable so this doesn't run ever again
  225. variable_del('cis_service_connection_initial');
  226. }
  227. // if last sync is less then the update interval, update
  228. if ((REQUEST_TIME - variable_get('cis_service_connection_last_sync', 0)) > $interval['interval']) {
  229. // select the service instance in question based on uuid
  230. $select = array(
  231. 'type' => 'service_instance',
  232. 'uuid' => variable_get('cis_service_instance_uuid', '')
  233. );
  234. $data = module_invoke_all('set_cis_service_data', 'interval');
  235. // set the data in the CIS if we have any
  236. if (!empty($data)) {
  237. _cis_connection_set_data($select, $data);
  238. }
  239. variable_set('cis_service_connection_last_sync', REQUEST_TIME);
  240. }
  241. // weekly sync
  242. if ((REQUEST_TIME - variable_get('cis_service_connection_weekly_last_sync', 0)) > $interval['weekly']) {
  243. $data = module_invoke_all('set_cis_service_data', 'weekly');
  244. variable_set('cis_service_connection_weekly_last_sync', REQUEST_TIME);
  245. }
  246. // monthly sync
  247. if ((REQUEST_TIME - variable_get('cis_service_connection_monthly_last_sync', 0)) > $interval['monthly']) {
  248. $data = module_invoke_all('set_cis_service_data', 'monthly');
  249. // get the latest footer copy language
  250. cis_service_connection_get_footer_language();
  251. variable_set('cis_service_connection_monthly_last_sync', REQUEST_TIME);
  252. }
  253. // yearly sync
  254. if ((REQUEST_TIME - variable_get('cis_service_connection_yearly_last_sync', 0)) > $interval['yearly']) {
  255. $data = module_invoke_all('set_cis_service_data', 'yearly');
  256. variable_set('cis_service_connection_yearly_last_sync', REQUEST_TIME);
  257. }
  258. // clear cached versions of section queries regardless of condition
  259. _cis_connector_cache_clear();
  260. }
  261. /**
  262. * Helper function to set footer language from CIS.
  263. */
  264. function cis_service_connection_get_footer_language() {
  265. // request the standard footer language
  266. $query = array('type' => 'resource', 'field_machine_name' => 'footer_language');
  267. $response = _cis_connection_query($query);
  268. // render text applying the input filter requested
  269. // @ignore coder_tough_love_14
  270. $text = str_replace('!current', date('Y'), $response['list'][0]['body']['value']);
  271. // load box object
  272. $footer = boxes_box_load('site_footer');
  273. if (isset($footer->options)) {
  274. // set text as the body of the block/box
  275. $footer->options['body']['value'] = $text;
  276. // ensure correct format is in use
  277. $footer->options['body']['format'] = $response['list'][0]['body']['format'];
  278. // save
  279. $footer->save();
  280. }
  281. }
  282. /**
  283. * Initial cron job to formally bind the CIS Service to the CIS.
  284. */
  285. function _cis_service_connection_initial_cis_bind() {
  286. // select the service instance in question based on uuid
  287. $select = array(
  288. 'type' => 'service_instance',
  289. 'uuid' => variable_get('cis_service_instance_uuid', '')
  290. );
  291. // report back data based on hook being invoked
  292. $data = module_invoke_all('set_cis_service_data', 'initial');
  293. // set the data in the CIS
  294. _cis_connection_set_data($select, $data);
  295. // get the latest footer copy language
  296. cis_service_connection_get_footer_language();
  297. // set last sync time
  298. variable_set('cis_service_connection_last_sync', REQUEST_TIME);
  299. // set this to say initial happened but we may need to do it again
  300. variable_set('cis_service_connection_initial', TRUE);
  301. }
  302. /**
  303. * Render a block based on section context
  304. */
  305. function cis_service_connection_block_section_outline() {
  306. // ensure this doesn't load when it doesn't have to
  307. $block = &drupal_static(__FUNCTION__);
  308. if (!isset($block)) {
  309. // never load when on an edit form in case it gets called
  310. if (arg(2) != 'edit') {
  311. $group = cis_service_connection_load_group();
  312. // test that we've got a group from context
  313. if (isset($group->nid)) {
  314. $onid = NULL;
  315. if (isset($group->field_instructional_outlines['und'])) {
  316. $onid = $group->field_instructional_outlines['und'][0]['target_id'];
  317. }
  318. else {
  319. // edge case where section is set and doesn't have an outline defined
  320. // this really is only possible during initial setup of a system
  321. // it helps improve ux substantially so you aren't confused
  322. // mooc is the only thing using this currently
  323. if (module_exists('mooc_helper')) {
  324. $onid = variable_get('mooc_default_outline', '');
  325. // edge case, default was never set
  326. if ($onid == '') {
  327. // load all books
  328. $books = _mooc_helper_all_book_outlines('nid', 'created');
  329. // make sure we at least have some books in here
  330. if (is_array($books)) {
  331. // move to 1st array position in iterator
  332. reset($books);
  333. // sort maintaining index which is the nid
  334. asort($books);
  335. // set default to first key in array
  336. $onid = key($books);
  337. }
  338. }
  339. }
  340. }
  341. // exit early cause we found nothing
  342. if (is_null($onid)) {
  343. return FALSE;
  344. }
  345. $node = node_load($onid);
  346. // load the active outline
  347. $active = menu_get_object();
  348. // test for not being on a node as well as global setting overriding outline to use
  349. if (!isset($active->book) || ($active->book['menu_name'] != $node->book['menu_name'])) {
  350. $active = $node;
  351. }
  352. // only show the block if the user has view access for the top-level node.
  353. if (entity_access('view', 'node', $active) && isset($active->book)) {
  354. $tree = menu_tree_all_data($active->book['menu_name'], $active->book);
  355. // There should only be one element at the top level.
  356. $data = array_shift($tree);
  357. $block['subject'] = '<none>';
  358. $block['content'] = menu_tree_output($data['below']);
  359. return $block;
  360. }
  361. }
  362. }
  363. }
  364. else {
  365. return $block;
  366. }
  367. return FALSE;
  368. }
  369. /**
  370. * Callback for instructor contact block content.
  371. */
  372. function cis_service_connection_block_instructor_contact() {
  373. // pull contact info from cis
  374. $info = _cis_connector_transaction('contact_info');
  375. // ensure we have contact info to display
  376. if (!empty($info)) {
  377. // run listed input filter
  378. return check_markup($info['value'], $info['format']);
  379. }
  380. return FALSE;
  381. }
  382. /**
  383. * Callback to render a list of optional section contexts to cycle through
  384. */
  385. function cis_service_connection_block_section_context_changer_form() {
  386. // provide all sections of students in this course
  387. $sections = cis_section_all_sections();
  388. $form = array();
  389. $form['section'] = array(
  390. '#type' => 'select',
  391. '#options' => $sections,
  392. '#title' => t('Section to view'),
  393. '#default_value' => _cis_connector_section_context(),
  394. );
  395. $form['submit'] = array(
  396. '#type' => 'submit',
  397. '#value' => t('Switch section'),
  398. );
  399. // check for section context override
  400. if (isset($_SESSION['cis_section_context'])) {
  401. $form['reset'] = array(
  402. '#type' => 'submit',
  403. '#value' => t('Reset'),
  404. );
  405. }
  406. return $form;
  407. }
  408. /**
  409. * Submit handler for the context changer block.
  410. */
  411. function cis_service_connection_block_section_context_changer_form_submit($form, &$form_state) {
  412. // set global state or unset the context switch
  413. if ($form_state['input']['op'] == 'Reset') {
  414. unset($_SESSION['cis_section_context']);
  415. }
  416. else {
  417. $_SESSION['cis_section_context'] = $form_state['values']['section'];
  418. }
  419. }
  420. /**
  421. * Return a group node when passed a section string.
  422. *
  423. * @param $section
  424. * (optional) section string to look up.
  425. * @return $section
  426. * a fully loaded section entity.
  427. */
  428. function cis_service_connection_load_group($section = NULL) {
  429. // allow for loading of current context
  430. if (empty($section)) {
  431. $section = _cis_connector_section_context();
  432. }
  433. // select field section data
  434. $query = new EntityFieldQuery();
  435. // pull all nodes
  436. $query->entityCondition('entity_type', 'node')
  437. // that are sections
  438. ->entityCondition('bundle', 'section')
  439. // that are published
  440. ->propertyCondition('status', 1)
  441. // that have the passed section
  442. ->fieldCondition('field_section_id', 'value', $section, '=')
  443. ->addMetaData('account', user_load(1));
  444. // store results
  445. $result = $query->execute();
  446. // ensure we have results
  447. if (isset($result['node'])) {
  448. $nids = array_keys($result['node']);
  449. $sections = entity_load('node', $nids);
  450. // convert to a readable array of options
  451. foreach ($sections as $section) {
  452. return $section;
  453. }
  454. }
  455. return NULL;
  456. }
  457. /**
  458. * Handle Role expiration.
  459. *
  460. * Accept a section name and look up an associated organic group.
  461. * Read in the group's user list and set all student roles to past student
  462. *
  463. * @param $section
  464. * string section to expire roles for.
  465. */
  466. function _cis_service_connection_expire_roles($section) {
  467. // full group node for this section
  468. $group = cis_service_connection_load_group($section);
  469. // Get a list of all the users in the group
  470. $students = _cis_service_connection_get_users_in_group($group->nid);
  471. // add past_student role
  472. $role = user_role_load_by_name('past student');
  473. user_multiple_role_edit($students, 'add_role', $role->rid);
  474. // drop student role
  475. $role = user_role_load_by_name('student');
  476. user_multiple_role_edit($students, 'remove_role', $role->rid);
  477. }
  478. /**
  479. * Get all students of a group.
  480. *
  481. * @param $gid
  482. * group / section entity id.
  483. * @return array
  484. * list of user ids
  485. */
  486. function _cis_service_connection_get_users_in_group($gid) {
  487. // load full student role object by name
  488. $role = user_role_load_by_name('student');
  489. // return membership to this group that are students
  490. $query = db_select('og_membership', 'ogm');
  491. // join user roles and memberships
  492. $query->join('users_roles', 'ur', 'ur.uid = ogm.etid');
  493. // only this group
  494. $query->condition('ogm.gid', $gid, '=');
  495. // ensure it's a user type of entity
  496. $query->condition('ogm.entity_type', 'user', '=');
  497. // only grab people who are students
  498. $query->condition('ur.rid', $role->rid, '=');
  499. // return the entity id which is the user's id
  500. $query->fields('ogm', array('etid'));
  501. // execute
  502. $result = $query->execute();
  503. $records = $result->fetchAll();
  504. $uids = array();
  505. // convert to an array of uids
  506. foreach ($records as $record) {
  507. $uids[] = $record->etid;
  508. }
  509. return $uids;
  510. }
  511. /**
  512. * Implements hook_admin_paths().
  513. */
  514. function cis_service_connection_admin_paths() {
  515. $vals = _cis_service_connection_links();
  516. foreach ($vals as $val) {
  517. $paths[$val . '/edit'] = TRUE;
  518. }
  519. return $paths;
  520. }