link.lib.php 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CourseBundle\Entity\CLink;
  4. /**
  5. * Function library for the links tool.
  6. *
  7. * This is a complete remake of the original link tool.
  8. * New features:
  9. * - Organize links into categories;
  10. * - favorites/bookmarks interface;
  11. * - move links up/down within a category;
  12. * - move categories up/down;
  13. * - expand/collapse all categories;
  14. * - add link to 'root' category => category-less link is always visible.
  15. *
  16. * @author Patrick Cool, complete remake (December 2003 - January 2004)
  17. * @author René Haentjens, CSV file import (October 2004)
  18. *
  19. * @package chamilo.link
  20. */
  21. class Link extends Model
  22. {
  23. public $table;
  24. public $is_course_model = true;
  25. public $columns = [
  26. 'id',
  27. 'c_id',
  28. 'url',
  29. 'title',
  30. 'description',
  31. 'category_id',
  32. 'display_order',
  33. 'on_homepage',
  34. 'target',
  35. 'session_id',
  36. ];
  37. public $required = ['url', 'title'];
  38. private $course;
  39. /**
  40. * Link constructor.
  41. */
  42. public function __construct()
  43. {
  44. $this->table = Database::get_course_table(TABLE_LINK);
  45. }
  46. /**
  47. * @param array $course
  48. */
  49. public function setCourse($course)
  50. {
  51. $this->course = $course;
  52. }
  53. /**
  54. * @return array
  55. */
  56. public function getCourse()
  57. {
  58. return !empty($this->course) ? $this->course : api_get_course_info();
  59. }
  60. /**
  61. * Organize the saving of a link, using the parent's save method and
  62. * updating the item_property table.
  63. *
  64. * @param array $params
  65. * @param bool $show_query Whether to show the query in logs when
  66. * calling parent's save method
  67. *
  68. * @return bool True if link could be saved, false otherwise
  69. */
  70. public function save($params, $show_query = null)
  71. {
  72. $course_info = $this->getCourse();
  73. $courseId = $course_info['real_id'];
  74. $params['session_id'] = api_get_session_id();
  75. $params['category_id'] = isset($params['category_id']) ? $params['category_id'] : 0;
  76. $sql = "SELECT MAX(display_order)
  77. FROM ".$this->table."
  78. WHERE
  79. c_id = $courseId AND
  80. category_id = '".intval($params['category_id'])."'";
  81. $result = Database:: query($sql);
  82. list($orderMax) = Database:: fetch_row($result);
  83. $order = $orderMax + 1;
  84. $params['display_order'] = $order;
  85. $id = parent::save($params, $show_query);
  86. if (!empty($id)) {
  87. // iid
  88. $sql = "UPDATE ".$this->table." SET id = iid WHERE iid = $id";
  89. Database::query($sql);
  90. api_item_property_update(
  91. $course_info,
  92. TOOL_LINK,
  93. $id,
  94. 'LinkAdded',
  95. api_get_user_id()
  96. );
  97. api_set_default_visibility($id, TOOL_LINK);
  98. }
  99. return $id;
  100. }
  101. /**
  102. * Update a link in the database.
  103. *
  104. * @param int $linkId The ID of the link to update
  105. * @param string $linkUrl The new URL to be saved
  106. * @param int $courseId
  107. * @param int $sessionId
  108. *
  109. * @return bool
  110. */
  111. public function updateLink(
  112. $linkId,
  113. $linkUrl,
  114. $courseId = null,
  115. $sessionId = null
  116. ) {
  117. $tblLink = Database::get_course_table(TABLE_LINK);
  118. $linkUrl = Database::escape_string($linkUrl);
  119. $linkId = intval($linkId);
  120. if (is_null($courseId)) {
  121. $courseId = api_get_course_int_id();
  122. }
  123. $courseId = intval($courseId);
  124. if (is_null($sessionId)) {
  125. $sessionId = api_get_session_id();
  126. }
  127. $sessionId = intval($sessionId);
  128. if ($linkUrl != '') {
  129. $sql = "UPDATE $tblLink SET
  130. url = '$linkUrl'
  131. WHERE id = $linkId AND c_id = $courseId AND session_id = $sessionId";
  132. $resLink = Database::query($sql);
  133. return $resLink;
  134. }
  135. return false;
  136. }
  137. /**
  138. * Used to add a link or a category.
  139. *
  140. * @param string $type , "link" or "category"
  141. *
  142. * @todo replace strings by constants
  143. *
  144. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  145. *
  146. * @return bool True on success, false on failure
  147. */
  148. public static function addlinkcategory($type)
  149. {
  150. $ok = true;
  151. $_course = api_get_course_info();
  152. $course_id = $_course['real_id'];
  153. $session_id = api_get_session_id();
  154. if ($type == 'link') {
  155. $title = Security::remove_XSS(stripslashes($_POST['title']));
  156. $urllink = Security::remove_XSS($_POST['url']);
  157. $description = Security::remove_XSS($_POST['description']);
  158. $selectcategory = Security::remove_XSS($_POST['category_id']);
  159. $onhomepage = 0;
  160. if (isset($_POST['on_homepage'])) {
  161. $onhomepage = Security::remove_XSS($_POST['on_homepage']);
  162. }
  163. $target = '_self'; // Default target.
  164. if (!empty($_POST['target'])) {
  165. $target = Security::remove_XSS($_POST['target']);
  166. }
  167. $urllink = trim($urllink);
  168. $title = trim($title);
  169. $description = trim($description);
  170. // We ensure URL to be absolute.
  171. if (strpos($urllink, '://') === false) {
  172. $urllink = 'http://'.$urllink;
  173. }
  174. // If the title is empty, we use the URL as title.
  175. if ($title == '') {
  176. $title = $urllink;
  177. }
  178. // If the URL is invalid, an error occurs.
  179. if (!api_valid_url($urllink, true)) {
  180. // A check against an absolute URL
  181. Display::addFlash(Display::return_message(get_lang('Please give the link URL, it should be valid.'), 'error'));
  182. return false;
  183. } else {
  184. // Looking for the largest order number for this category.
  185. $link = new Link();
  186. $params = [
  187. 'c_id' => $course_id,
  188. 'url' => $urllink,
  189. 'title' => $title,
  190. 'description' => $description,
  191. 'category_id' => $selectcategory,
  192. 'on_homepage' => $onhomepage,
  193. 'target' => $target,
  194. 'session_id' => $session_id,
  195. ];
  196. $link_id = $link->save($params);
  197. if ((api_get_setting('search_enabled') == 'true') &&
  198. $link_id && extension_loaded('xapian')
  199. ) {
  200. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  201. $course_int_id = $_course['real_id'];
  202. $courseCode = $_course['code'];
  203. $specific_fields = get_specific_field_list();
  204. $ic_slide = new IndexableChunk();
  205. // Add all terms to db.
  206. $all_specific_terms = '';
  207. foreach ($specific_fields as $specific_field) {
  208. if (isset($_REQUEST[$specific_field['code']])) {
  209. $sterms = trim($_REQUEST[$specific_field['code']]);
  210. if (!empty($sterms)) {
  211. $all_specific_terms .= ' '.$sterms;
  212. $sterms = explode(',', $sterms);
  213. foreach ($sterms as $sterm) {
  214. $ic_slide->addTerm(
  215. trim($sterm),
  216. $specific_field['code']
  217. );
  218. add_specific_field_value(
  219. $specific_field['id'],
  220. $courseCode,
  221. TOOL_LINK,
  222. $link_id,
  223. $sterm
  224. );
  225. }
  226. }
  227. }
  228. }
  229. // Build the chunk to index.
  230. $ic_slide->addValue('title', $title);
  231. $ic_slide->addCourseId($courseCode);
  232. $ic_slide->addToolId(TOOL_LINK);
  233. $xapian_data = [
  234. SE_COURSE_ID => $courseCode,
  235. SE_TOOL_ID => TOOL_LINK,
  236. SE_DATA => [
  237. 'link_id' => (int) $link_id,
  238. ],
  239. SE_USER => (int) api_get_user_id(),
  240. ];
  241. $ic_slide->xapian_data = serialize($xapian_data);
  242. $description = $all_specific_terms.' '.$description;
  243. $ic_slide->addValue('content', $description);
  244. // Add category name if set.
  245. if (isset($selectcategory) && $selectcategory > 0) {
  246. $table_link_category = Database::get_course_table(
  247. TABLE_LINK_CATEGORY
  248. );
  249. $sql_cat = 'SELECT * FROM %s WHERE id=%d AND c_id = %d LIMIT 1';
  250. $sql_cat = sprintf(
  251. $sql_cat,
  252. $table_link_category,
  253. (int) $selectcategory,
  254. $course_int_id
  255. );
  256. $result = Database:: query($sql_cat);
  257. if (Database:: num_rows($result) == 1) {
  258. $row = Database:: fetch_array($result);
  259. $ic_slide->addValue(
  260. 'category',
  261. $row['category_title']
  262. );
  263. }
  264. }
  265. $di = new ChamiloIndexer();
  266. isset($_POST['language']) ? $lang = Database:: escape_string(
  267. $_POST['language']
  268. ) : $lang = 'english';
  269. $di->connectDb(null, null, $lang);
  270. $di->addChunk($ic_slide);
  271. // Index and return search engine document id.
  272. $did = $di->index();
  273. if ($did) {
  274. // Save it to db.
  275. $tbl_se_ref = Database::get_main_table(
  276. TABLE_MAIN_SEARCH_ENGINE_REF
  277. );
  278. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  279. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  280. $sql = sprintf(
  281. $sql,
  282. $tbl_se_ref,
  283. $course_int_id,
  284. $courseCode,
  285. TOOL_LINK,
  286. $link_id,
  287. $did
  288. );
  289. Database:: query($sql);
  290. }
  291. }
  292. Display::addFlash(Display::return_message(get_lang('The link has been added.')));
  293. return $link_id;
  294. }
  295. } elseif ($type == 'category') {
  296. $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
  297. $category_title = trim($_POST['category_title']);
  298. $description = trim($_POST['description']);
  299. if (empty($category_title)) {
  300. echo Display::return_message(get_lang('Please give the category name'), 'error');
  301. $ok = false;
  302. } else {
  303. // Looking for the largest order number for this category.
  304. $result = Database:: query(
  305. "SELECT MAX(display_order) FROM $tbl_categories
  306. WHERE c_id = $course_id "
  307. );
  308. list($orderMax) = Database:: fetch_row($result);
  309. $order = $orderMax + 1;
  310. $order = intval($order);
  311. $session_id = api_get_session_id();
  312. $params = [
  313. 'c_id' => $course_id,
  314. 'category_title' => $category_title,
  315. 'description' => $description,
  316. 'display_order' => $order,
  317. 'session_id' => $session_id,
  318. ];
  319. $linkId = Database::insert($tbl_categories, $params);
  320. if ($linkId) {
  321. // iid
  322. $sql = "UPDATE $tbl_categories SET id = iid WHERE iid = $linkId";
  323. Database:: query($sql);
  324. // add link_category visibility
  325. // course ID is taken from context in api_set_default_visibility
  326. //api_set_default_visibility($linkId, TOOL_LINK_CATEGORY);
  327. api_item_property_update(
  328. $_course,
  329. TOOL_LINK_CATEGORY,
  330. $linkId,
  331. 'LinkCategoryAdded',
  332. api_get_user_id()
  333. );
  334. api_set_default_visibility($linkId, TOOL_LINK_CATEGORY);
  335. }
  336. Display::addFlash(Display::return_message(get_lang('Category added')));
  337. return $linkId;
  338. }
  339. }
  340. return $ok;
  341. }
  342. /**
  343. * Used to delete a link or a category.
  344. *
  345. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  346. *
  347. * @param int $id
  348. * @param string $type The type of item to delete
  349. *
  350. * @return bool
  351. */
  352. public static function deletelinkcategory($id, $type)
  353. {
  354. $courseInfo = api_get_course_info();
  355. $tbl_link = Database::get_course_table(TABLE_LINK);
  356. $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
  357. $course_id = $courseInfo['real_id'];
  358. $id = intval($id);
  359. if (empty($id)) {
  360. return false;
  361. }
  362. $result = false;
  363. switch ($type) {
  364. case 'link':
  365. // -> Items are no longer physically deleted,
  366. // but the visibility is set to 2 (in item_property).
  367. // This will make a restore function possible for the platform administrator.
  368. $sql = "UPDATE $tbl_link SET on_homepage='0'
  369. WHERE c_id = $course_id AND id='".$id."'";
  370. Database:: query($sql);
  371. api_item_property_update(
  372. $courseInfo,
  373. TOOL_LINK,
  374. $id,
  375. 'delete',
  376. api_get_user_id()
  377. );
  378. self::delete_link_from_search_engine(api_get_course_id(), $id);
  379. Skill::deleteSkillsFromItem($id, ITEM_TYPE_LINK);
  380. Display::addFlash(Display::return_message(get_lang('The link has been deleted')));
  381. $result = true;
  382. break;
  383. case 'category':
  384. // First we delete the category itself and afterwards all the links of this category.
  385. $sql = "DELETE FROM ".$tbl_categories."
  386. WHERE c_id = $course_id AND id='".$id."'";
  387. Database:: query($sql);
  388. $sql = "DELETE FROM ".$tbl_link."
  389. WHERE c_id = $course_id AND category_id='".$id."'";
  390. Database:: query($sql);
  391. api_item_property_update(
  392. $courseInfo,
  393. TOOL_LINK_CATEGORY,
  394. $id,
  395. 'delete',
  396. api_get_user_id()
  397. );
  398. Display::addFlash(Display::return_message(get_lang('The category has been deleted.')));
  399. $result = true;
  400. break;
  401. }
  402. return $result;
  403. }
  404. /**
  405. * Removes a link from search engine database.
  406. *
  407. * @param string $course_id Course code
  408. * @param int $link_id Document id to delete
  409. */
  410. public static function delete_link_from_search_engine($course_id, $link_id)
  411. {
  412. // Remove from search engine if enabled.
  413. if (api_get_setting('search_enabled') === 'true') {
  414. $tbl_se_ref = Database::get_main_table(
  415. TABLE_MAIN_SEARCH_ENGINE_REF
  416. );
  417. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  418. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
  419. $res = Database:: query($sql);
  420. if (Database:: num_rows($res) > 0) {
  421. $row = Database::fetch_array($res);
  422. $di = new ChamiloIndexer();
  423. $di->remove_document($row['search_did']);
  424. }
  425. $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  426. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_LINK, $link_id);
  427. Database:: query($sql);
  428. // Remove terms from db.
  429. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  430. delete_all_values_for_item($course_id, TOOL_DOCUMENT, $link_id);
  431. }
  432. }
  433. /**
  434. * Get link info.
  435. *
  436. * @param int $id
  437. *
  438. * @return array link info
  439. */
  440. public static function getLinkInfo($id)
  441. {
  442. $tbl_link = Database::get_course_table(TABLE_LINK);
  443. $course_id = api_get_course_int_id();
  444. if (empty($id) || empty($course_id)) {
  445. return [];
  446. }
  447. $sql = "SELECT * FROM $tbl_link
  448. WHERE c_id = $course_id AND id='".intval($id)."' ";
  449. $result = Database::query($sql);
  450. $data = [];
  451. if (Database::num_rows($result)) {
  452. $data = Database::fetch_array($result);
  453. }
  454. return $data;
  455. }
  456. /**
  457. * @param int $id
  458. * @param array $values
  459. */
  460. public static function editLink($id, $values = [])
  461. {
  462. $tbl_link = Database::get_course_table(TABLE_LINK);
  463. $_course = api_get_course_info();
  464. $course_id = $_course['real_id'];
  465. $id = intval($id);
  466. $values['url'] = trim($values['url']);
  467. $values['title'] = trim($values['title']);
  468. $values['description'] = trim($values['description']);
  469. $values['target'] = empty($values['target']) ? '_self' : $values['target'];
  470. $values['on_homepage'] = isset($values['on_homepage']) ? $values['on_homepage'] : '';
  471. $categoryId = intval($values['category_id']);
  472. // We ensure URL to be absolute.
  473. if (strpos($values['url'], '://') === false) {
  474. $values['url'] = 'http://'.$_POST['url'];
  475. }
  476. // If the title is empty, we use the URL as title.
  477. if ($values['title'] == '') {
  478. $values['title'] = $values['url'];
  479. }
  480. // If the URL is invalid, an error occurs.
  481. if (!api_valid_url($values['url'], true)) {
  482. Display::addFlash(
  483. Display::return_message(get_lang('Please give the link URL, it should be valid.'), 'error')
  484. );
  485. return false;
  486. }
  487. if (empty($id) || empty($course_id)) {
  488. return false;
  489. }
  490. // Finding the old category_id.
  491. $sql = "SELECT * FROM $tbl_link
  492. WHERE c_id = $course_id AND id='".$id."'";
  493. $result = Database:: query($sql);
  494. $row = Database:: fetch_array($result);
  495. $category_id = $row['category_id'];
  496. if ($category_id != $values['category_id']) {
  497. $sql = "SELECT MAX(display_order)
  498. FROM $tbl_link
  499. WHERE
  500. c_id = $course_id AND
  501. category_id='".intval($values['category_id'])."'";
  502. $result = Database:: query($sql);
  503. list($max_display_order) = Database:: fetch_row($result);
  504. $max_display_order++;
  505. } else {
  506. $max_display_order = $row['display_order'];
  507. }
  508. $params = [
  509. 'url' => $values['url'],
  510. 'title' => $values['title'],
  511. 'description' => $values['description'],
  512. 'category_id' => $values['category_id'],
  513. 'display_order' => $max_display_order,
  514. 'on_homepage' => $values['on_homepage'],
  515. 'target' => $values['target'],
  516. 'category_id' => $values['category_id'],
  517. ];
  518. Database::update(
  519. $tbl_link,
  520. $params,
  521. ['c_id = ? AND id = ?' => [$course_id, $id]]
  522. );
  523. // Update search enchine and its values table if enabled.
  524. if (api_get_setting('search_enabled') == 'true') {
  525. $course_int_id = api_get_course_int_id();
  526. $course_id = api_get_course_id();
  527. $link_title = Database:: escape_string($values['title']);
  528. $link_description = Database:: escape_string($values['description']);
  529. // Actually, it consists on delete terms from db,
  530. // insert new ones, create a new search engine document, and remove the old one.
  531. // Get search_did.
  532. $tbl_se_ref = Database::get_main_table(
  533. TABLE_MAIN_SEARCH_ENGINE_REF
  534. );
  535. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  536. $sql = sprintf(
  537. $sql,
  538. $tbl_se_ref,
  539. $course_id,
  540. TOOL_LINK,
  541. $id
  542. );
  543. $res = Database:: query($sql);
  544. if (Database:: num_rows($res) > 0) {
  545. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  546. $se_ref = Database:: fetch_array($res);
  547. $specific_fields = get_specific_field_list();
  548. $ic_slide = new IndexableChunk();
  549. $all_specific_terms = '';
  550. foreach ($specific_fields as $specific_field) {
  551. delete_all_specific_field_value(
  552. $course_id,
  553. $specific_field['id'],
  554. TOOL_LINK,
  555. $id
  556. );
  557. if (isset($_REQUEST[$specific_field['code']])) {
  558. $sterms = trim(
  559. $_REQUEST[$specific_field['code']]
  560. );
  561. if (!empty($sterms)) {
  562. $all_specific_terms .= ' '.$sterms;
  563. $sterms = explode(',', $sterms);
  564. foreach ($sterms as $sterm) {
  565. $ic_slide->addTerm(
  566. trim($sterm),
  567. $specific_field['code']
  568. );
  569. add_specific_field_value(
  570. $specific_field['id'],
  571. $course_id,
  572. TOOL_LINK,
  573. $id,
  574. $sterm
  575. );
  576. }
  577. }
  578. }
  579. }
  580. // Build the chunk to index.
  581. $ic_slide->addValue("title", $link_title);
  582. $ic_slide->addCourseId($course_id);
  583. $ic_slide->addToolId(TOOL_LINK);
  584. $xapian_data = [
  585. SE_COURSE_ID => $course_id,
  586. SE_TOOL_ID => TOOL_LINK,
  587. SE_DATA => [
  588. 'link_id' => (int) $id,
  589. ],
  590. SE_USER => (int) api_get_user_id(),
  591. ];
  592. $ic_slide->xapian_data = serialize($xapian_data);
  593. $link_description = $all_specific_terms.' '.$link_description;
  594. $ic_slide->addValue('content', $link_description);
  595. // Add category name if set.
  596. if (isset($categoryId) && $categoryId > 0) {
  597. $table_link_category = Database::get_course_table(
  598. TABLE_LINK_CATEGORY
  599. );
  600. $sql_cat = 'SELECT * FROM %s WHERE id=%d and c_id = %d LIMIT 1';
  601. $sql_cat = sprintf(
  602. $sql_cat,
  603. $table_link_category,
  604. $categoryId,
  605. $course_int_id
  606. );
  607. $result = Database:: query($sql_cat);
  608. if (Database:: num_rows($result) == 1) {
  609. $row = Database:: fetch_array($result);
  610. $ic_slide->addValue(
  611. 'category',
  612. $row['category_title']
  613. );
  614. }
  615. }
  616. $di = new ChamiloIndexer();
  617. isset($_POST['language']) ? $lang = Database:: escape_string($_POST['language']) : $lang = 'english';
  618. $di->connectDb(null, null, $lang);
  619. $di->remove_document($se_ref['search_did']);
  620. $di->addChunk($ic_slide);
  621. // Index and return search engine document id.
  622. $did = $di->index();
  623. if ($did) {
  624. // Save it to db.
  625. $sql = 'DELETE FROM %s
  626. WHERE course_code=\'%s\'
  627. AND tool_id=\'%s\'
  628. AND ref_id_high_level=\'%s\'';
  629. $sql = sprintf(
  630. $sql,
  631. $tbl_se_ref,
  632. $course_id,
  633. TOOL_LINK,
  634. $id
  635. );
  636. Database:: query($sql);
  637. $sql = 'INSERT INTO %s (c_id, id, course_code, tool_id, ref_id_high_level, search_did)
  638. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  639. $sql = sprintf(
  640. $sql,
  641. $tbl_se_ref,
  642. $course_int_id,
  643. $course_id,
  644. TOOL_LINK,
  645. $id,
  646. $did
  647. );
  648. Database:: query($sql);
  649. }
  650. }
  651. }
  652. // "WHAT'S NEW" notification: update table last_toolEdit.
  653. api_item_property_update(
  654. $_course,
  655. TOOL_LINK,
  656. $id,
  657. 'LinkUpdated',
  658. api_get_user_id()
  659. );
  660. Display::addFlash(Display::return_message(get_lang('The link has been modified.')));
  661. }
  662. /**
  663. * @param int $id
  664. * @param array $values
  665. *
  666. * @return bool
  667. */
  668. public static function editCategory($id, $values)
  669. {
  670. $table = Database::get_course_table(TABLE_LINK_CATEGORY);
  671. $course_id = api_get_course_int_id();
  672. $id = intval($id);
  673. // This is used to put the modified info of the category-form into the database.
  674. $params = [
  675. 'category_title' => $values['category_title'],
  676. 'description' => $values['description'],
  677. ];
  678. Database::update(
  679. $table,
  680. $params,
  681. ['c_id = ? AND id = ?' => [$course_id, $id]]
  682. );
  683. Display::addFlash(Display::return_message(get_lang('The category has been modified.')));
  684. return true;
  685. }
  686. /**
  687. * Changes the visibility of a link.
  688. *
  689. * @todo add the changing of the visibility of a course
  690. *
  691. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  692. */
  693. public static function change_visibility_link($id, $scope)
  694. {
  695. $_course = api_get_course_info();
  696. $_user = api_get_user_info();
  697. if ($scope == TOOL_LINK) {
  698. api_item_property_update(
  699. $_course,
  700. TOOL_LINK,
  701. $id,
  702. $_GET['action'],
  703. $_user['user_id']
  704. );
  705. Display::addFlash(Display::return_message(get_lang('The visibility has been changed.')));
  706. } elseif ($scope == TOOL_LINK_CATEGORY) {
  707. api_item_property_update(
  708. $_course,
  709. TOOL_LINK_CATEGORY,
  710. $id,
  711. $_GET['action'],
  712. $_user['user_id']
  713. );
  714. Display::addFlash(Display::return_message(get_lang('The visibility has been changed.')));
  715. }
  716. }
  717. /**
  718. * Generate SQL to select all the links categories in the current course and
  719. * session.
  720. *
  721. * @param int $courseId
  722. * @param int $sessionId
  723. * @param bool $withBaseContent
  724. *
  725. * @return array
  726. */
  727. public static function getLinkCategories($courseId, $sessionId, $withBaseContent = true)
  728. {
  729. $tblLinkCategory = Database::get_course_table(TABLE_LINK_CATEGORY);
  730. $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  731. $courseId = intval($courseId);
  732. $courseInfo = api_get_course_info_by_id($courseId);
  733. // Condition for the session.
  734. $sessionCondition = api_get_session_condition(
  735. $sessionId,
  736. true,
  737. $withBaseContent,
  738. 'linkcat.session_id'
  739. );
  740. // Getting links
  741. $sql = "SELECT *, linkcat.id
  742. FROM $tblLinkCategory linkcat
  743. WHERE
  744. linkcat.c_id = $courseId
  745. $sessionCondition
  746. ORDER BY linkcat.display_order DESC";
  747. $result = Database::query($sql);
  748. $categories = Database::store_result($result);
  749. $sql = "SELECT *, linkcat.id
  750. FROM $tblLinkCategory linkcat
  751. INNER JOIN $tblItemProperty ip
  752. ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
  753. WHERE
  754. ip.tool = '".TOOL_LINK_CATEGORY."' AND
  755. (ip.visibility = '0' OR ip.visibility = '1')
  756. $sessionCondition AND
  757. linkcat.c_id = ".$courseId."
  758. ORDER BY linkcat.display_order DESC";
  759. $result = Database::query($sql);
  760. $categoryInItemProperty = [];
  761. if (Database::num_rows($result)) {
  762. while ($row = Database::fetch_array($result, 'ASSOC')) {
  763. $categoryInItemProperty[$row['id']] = $row;
  764. }
  765. }
  766. foreach ($categories as &$category) {
  767. if (!isset($categoryInItemProperty[$category['id']])) {
  768. api_item_property_update(
  769. $courseInfo,
  770. TOOL_LINK_CATEGORY,
  771. $category['id'],
  772. 'LinkCategoryAdded',
  773. api_get_user_id()
  774. );
  775. }
  776. }
  777. $sql = "SELECT DISTINCT linkcat.*, visibility
  778. FROM $tblLinkCategory linkcat
  779. INNER JOIN $tblItemProperty ip
  780. ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
  781. WHERE
  782. ip.tool = '".TOOL_LINK_CATEGORY."' AND
  783. (ip.visibility = '0' OR ip.visibility = '1')
  784. $sessionCondition AND
  785. linkcat.c_id = ".$courseId."
  786. ORDER BY linkcat.display_order DESC
  787. ";
  788. $result = Database::query($sql);
  789. return Database::store_result($result, 'ASSOC');
  790. }
  791. /**
  792. * @param int $categoryId
  793. * @param $courseId
  794. * @param $sessionId
  795. * @param bool $withBaseContent
  796. *
  797. * @return array
  798. */
  799. public static function getLinksPerCategory(
  800. $categoryId,
  801. $courseId,
  802. $sessionId,
  803. $withBaseContent = true
  804. ) {
  805. $tbl_link = Database::get_course_table(TABLE_LINK);
  806. $TABLE_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  807. $courseId = (int) $courseId;
  808. $sessionId = (int) $sessionId;
  809. $categoryId = (int) $categoryId;
  810. // Condition for the session.
  811. $condition_session = api_get_session_condition(
  812. $sessionId,
  813. true,
  814. false,
  815. 'ip.session_id'
  816. );
  817. if (!empty($sessionId)) {
  818. $conditionBaseSession = api_get_session_condition(
  819. 0,
  820. true,
  821. $withBaseContent,
  822. 'ip.session_id'
  823. );
  824. $condition = " AND
  825. (
  826. (ip.visibility = '1' $conditionBaseSession) OR
  827. (
  828. (ip.visibility = '0' OR ip.visibility = '1')
  829. $condition_session
  830. )
  831. )
  832. ";
  833. } else {
  834. $condition = api_get_session_condition(
  835. 0,
  836. true,
  837. false,
  838. 'ip.session_id'
  839. );
  840. $condition .= " AND (ip.visibility = '0' OR ip.visibility = '1') $condition ";
  841. }
  842. $sql = "SELECT
  843. link.id,
  844. ip.session_id,
  845. link.session_id link_session_id,
  846. url,
  847. category_id,
  848. visibility,
  849. description,
  850. title,
  851. target,
  852. on_homepage
  853. FROM $tbl_link link
  854. INNER JOIN $TABLE_ITEM_PROPERTY ip
  855. ON (link.id = ip.ref AND link.c_id = ip.c_id)
  856. WHERE
  857. ip.tool = '".TOOL_LINK."' AND
  858. link.category_id = '".$categoryId."' AND
  859. link.c_id = $courseId AND
  860. ip.c_id = $courseId
  861. $condition
  862. ORDER BY link.display_order ASC, ip.session_id DESC";
  863. $result = Database:: query($sql);
  864. return Database::store_result($result);
  865. }
  866. /**
  867. * Displays all the links of a given category.
  868. *
  869. * @param int $catid
  870. * @param int $courseId
  871. * @param int $session_id
  872. * @param bool $showActionLinks
  873. *
  874. * @return string
  875. *
  876. * @author Julio Montoya
  877. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  878. */
  879. public static function showLinksPerCategory($catid, $courseId, $session_id, $showActionLinks = true)
  880. {
  881. global $token;
  882. $_user = api_get_user_info();
  883. $catid = (int) $catid;
  884. $links = self::getLinksPerCategory($catid, $courseId, $session_id);
  885. $content = '';
  886. $numberOfLinks = count($links);
  887. if (!empty($links)) {
  888. $content .= '<div class="link list-group">';
  889. $i = 1;
  890. $linksAdded = [];
  891. foreach ($links as $myrow) {
  892. $linkId = $myrow['id'];
  893. if (in_array($linkId, $linksAdded)) {
  894. continue;
  895. }
  896. $linksAdded[] = $linkId;
  897. $categoryId = $myrow['category_id'];
  898. // Validation when belongs to a session.
  899. $session_img = api_get_session_image(
  900. $myrow['link_session_id'],
  901. $_user['status']
  902. );
  903. $toolbar = '';
  904. $link_validator = '';
  905. if (api_is_allowed_to_edit(null, true)) {
  906. $toolbar .= Display::toolbarButton(
  907. '',
  908. 'javascript:void(0);',
  909. 'check-circle',
  910. 'secondary btn-sm',
  911. [
  912. 'onclick' => "check_url('".$linkId."', '".addslashes($myrow['url'])."');",
  913. 'title' => get_lang('Check link'),
  914. ]
  915. );
  916. $link_validator .= Display::span(
  917. '',
  918. [
  919. 'id' => 'url_id_'.$linkId,
  920. 'class' => 'check-link',
  921. ]
  922. );
  923. if ($session_id == $myrow['link_session_id']) {
  924. $url = api_get_self().'?'.api_get_cidreq().'&action=editlink&id='.$linkId;
  925. $title = get_lang('Edit');
  926. $toolbar .= Display::toolbarButton(
  927. '',
  928. $url,
  929. 'pencil-alt',
  930. 'secondary btn-sm',
  931. [
  932. 'title' => $title,
  933. ]
  934. );
  935. }
  936. $urlVisibility = api_get_self().'?'.api_get_cidreq().
  937. '&sec_token='.$token.
  938. '&id='.$linkId.
  939. '&scope=link&category_id='.$categoryId;
  940. switch ($myrow['visibility']) {
  941. case '1':
  942. $urlVisibility .= '&action=invisible';
  943. $title = get_lang('Make invisible');
  944. $toolbar .= Display::toolbarButton(
  945. '',
  946. $urlVisibility,
  947. 'eye',
  948. 'secondary btn-sm',
  949. [
  950. 'title' => $title,
  951. ]
  952. );
  953. break;
  954. case '0':
  955. $urlVisibility .= '&action=visible';
  956. $title = get_lang('Make Visible');
  957. $toolbar .= Display::toolbarButton(
  958. '',
  959. $urlVisibility,
  960. 'eye-slash',
  961. 'secondary btn-sm',
  962. [
  963. 'title' => $title,
  964. ]
  965. );
  966. break;
  967. }
  968. if ($session_id == $myrow['link_session_id']) {
  969. $moveLinkParams = [
  970. 'id' => $linkId,
  971. 'scope' => 'category',
  972. 'category_id' => $categoryId,
  973. 'action' => 'move_link_up',
  974. ];
  975. $toolbar .= Display::toolbarButton(
  976. get_lang('Move up'),
  977. api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinksParams),
  978. 'level-up-alt',
  979. 'secondary',
  980. ['class' => 'btn-sm '.($i === 1 ? 'disabled' : '')],
  981. false
  982. );
  983. $moveLinkParams['action'] = 'move_link_down';
  984. $toolbar .= Display::toolbarButton(
  985. get_lang('Move down'),
  986. api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinksParams),
  987. 'level-down-alt',
  988. 'secondary',
  989. ['class' => 'btn-sm '.($i === $numberOfLinks ? 'disabled' : '')],
  990. false
  991. );
  992. $url = api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletelink&id='.$linkId.'&category_id='.$categoryId;
  993. $event = "javascript: if(!confirm('".get_lang('Do you want to delete this link?')."'))return false;";
  994. $title = get_lang('Delete');
  995. $toolbar .= Display::toolbarButton(
  996. '',
  997. $url,
  998. 'trash',
  999. 'secondary btn-sm',
  1000. [
  1001. 'onclick' => $event,
  1002. 'title' => $title,
  1003. ]
  1004. );
  1005. }
  1006. }
  1007. $showLink = false;
  1008. $titleClass = '';
  1009. if ($myrow['visibility'] == '1') {
  1010. $showLink = true;
  1011. } else {
  1012. if (api_is_allowed_to_edit(null, true)) {
  1013. $showLink = true;
  1014. $titleClass = 'text-muted';
  1015. }
  1016. }
  1017. if ($showLink) {
  1018. $iconLink = Display::return_icon(
  1019. 'url.png',
  1020. get_lang('Link'),
  1021. null,
  1022. ICON_SIZE_SMALL
  1023. );
  1024. $url = api_get_path(WEB_CODE_PATH).'link/link_goto.php?'.api_get_cidreq().'&link_id='.$linkId.'&link_url='.urlencode($myrow['url']);
  1025. $content .= '<div class="list-group-item">';
  1026. if ($showActionLinks) {
  1027. $content .= '<div class="pull-right"><div class="btn-group">'.$toolbar.'</div></div>';
  1028. }
  1029. $content .= '<h4 class="list-group-item-heading">';
  1030. $content .= $iconLink;
  1031. $content .= Display::tag(
  1032. 'a',
  1033. Security::remove_XSS($myrow['title']),
  1034. [
  1035. 'href' => $url,
  1036. 'target' => $myrow['target'],
  1037. 'class' => $titleClass,
  1038. ]
  1039. );
  1040. $content .= $link_validator;
  1041. $content .= $session_img;
  1042. $content .= '</h4>';
  1043. $content .= '<p class="list-group-item-text">'.$myrow['description'].'</p>';
  1044. $content .= '</div>';
  1045. }
  1046. $i++;
  1047. }
  1048. $content .= '</div>';
  1049. }
  1050. return $content;
  1051. }
  1052. /**
  1053. * Displays the edit, delete and move icons.
  1054. *
  1055. * @param int Category ID
  1056. * @param int $currentCategory
  1057. * @param int $countCategories
  1058. *
  1059. * @return string
  1060. *
  1061. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1062. */
  1063. public static function showCategoryAdminTools($category, $currentCategory, $countCategories)
  1064. {
  1065. $categoryId = $category['id'];
  1066. $token = null;
  1067. $tools = '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=editcategory&id='.$categoryId.'&category_id='.$categoryId.'" title='.get_lang('Edit').'">'.
  1068. Display:: return_icon(
  1069. 'edit.png',
  1070. get_lang('Edit'),
  1071. [],
  1072. ICON_SIZE_SMALL
  1073. ).'</a>';
  1074. // DISPLAY MOVE UP COMMAND only if it is not the top link.
  1075. if ($currentCategory != 0) {
  1076. $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=up&up='.$categoryId.'&category_id='.$categoryId.'" title="'.get_lang('Up').'">'.
  1077. Display:: return_icon(
  1078. 'up.png',
  1079. get_lang('Up'),
  1080. [],
  1081. ICON_SIZE_SMALL
  1082. ).'</a>';
  1083. } else {
  1084. $tools .= Display:: return_icon(
  1085. 'up_na.png',
  1086. get_lang('Up'),
  1087. [],
  1088. ICON_SIZE_SMALL
  1089. ).'</a>';
  1090. }
  1091. // DISPLAY MOVE DOWN COMMAND only if it is not the bottom link.
  1092. if ($currentCategory < $countCategories - 1) {
  1093. $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=down&down='.$categoryId.'&category_id='.$categoryId.'">'.
  1094. Display:: return_icon(
  1095. 'down.png',
  1096. get_lang('down'),
  1097. [],
  1098. ICON_SIZE_SMALL
  1099. ).'</a>';
  1100. } else {
  1101. $tools .= Display:: return_icon(
  1102. 'down_na.png',
  1103. get_lang('down'),
  1104. [],
  1105. ICON_SIZE_SMALL
  1106. ).'</a>';
  1107. }
  1108. $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletecategory&id='.$categoryId."&category_id=$categoryId\"
  1109. onclick=\"javascript: if(!confirm('".get_lang('When deleting a category, all links of this category are also deleted.
  1110. Do you really want to delete this category and its links ?')."')) return false;\">".
  1111. Display:: return_icon(
  1112. 'delete.png',
  1113. get_lang('Delete'),
  1114. [],
  1115. ICON_SIZE_SMALL
  1116. ).'</a>';
  1117. return $tools;
  1118. }
  1119. /**
  1120. * move a link or a linkcategory up or down.
  1121. *
  1122. * @param int Category ID
  1123. * @param int Course ID
  1124. * @param int Session ID
  1125. *
  1126. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1127. *
  1128. * @todo support sessions
  1129. */
  1130. public static function movecatlink($action, $catlinkid, $courseId = null, $sessionId = null)
  1131. {
  1132. $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
  1133. if (is_null($courseId)) {
  1134. $courseId = api_get_course_int_id();
  1135. }
  1136. $courseId = intval($courseId);
  1137. if (is_null($sessionId)) {
  1138. $sessionId = api_get_session_id();
  1139. }
  1140. $sessionId = intval($sessionId);
  1141. $thiscatlinkId = intval($catlinkid);
  1142. if ($action == 'down') {
  1143. $sortDirection = 'DESC';
  1144. }
  1145. if ($action == 'up') {
  1146. $sortDirection = 'ASC';
  1147. }
  1148. $movetable = $tbl_categories;
  1149. if (!empty($sortDirection)) {
  1150. if (!in_array(trim(strtoupper($sortDirection)), ['ASC', 'DESC'])) {
  1151. $sortDirection = 'ASC';
  1152. }
  1153. $sql = "SELECT id, display_order FROM $movetable
  1154. WHERE c_id = $courseId
  1155. ORDER BY display_order $sortDirection";
  1156. $linkresult = Database:: query($sql);
  1157. $thislinkOrder = 1;
  1158. while ($sortrow = Database:: fetch_array($linkresult)) {
  1159. // STEP 2 : FOUND THE NEXT LINK ID AND ORDER, COMMIT SWAP
  1160. // This part seems unlogic, but it isn't . We first look for the current link with the querystring ID
  1161. // and we know the next iteration of the while loop is the next one. These should be swapped.
  1162. if (isset($thislinkFound) && $thislinkFound) {
  1163. $nextlinkId = $sortrow['id'];
  1164. $nextlinkOrder = $sortrow['display_order'];
  1165. Database:: query(
  1166. "UPDATE ".$movetable."
  1167. SET display_order = '$nextlinkOrder'
  1168. WHERE c_id = $courseId AND id = '$thiscatlinkId'"
  1169. );
  1170. Database:: query(
  1171. "UPDATE ".$movetable."
  1172. SET display_order = '$thislinkOrder'
  1173. WHERE c_id = $courseId AND id = '$nextlinkId'"
  1174. );
  1175. break;
  1176. }
  1177. if ($sortrow['id'] == $thiscatlinkId) {
  1178. $thislinkOrder = $sortrow['display_order'];
  1179. $thislinkFound = true;
  1180. }
  1181. }
  1182. }
  1183. Display::addFlash(Display::return_message(get_lang('LinksMoved')));
  1184. }
  1185. /**
  1186. * This function checks if the url is a vimeo link.
  1187. *
  1188. * @author Julio Montoya
  1189. *
  1190. * @version 1.0
  1191. */
  1192. public static function isVimeoLink($url)
  1193. {
  1194. $isLink = strrpos($url, 'vimeo.com');
  1195. return $isLink;
  1196. }
  1197. /**
  1198. * Get vimeo id from URL.
  1199. *
  1200. * @param string $url
  1201. *
  1202. * @return bool|mixed
  1203. */
  1204. public static function getVimeoLinkId($url)
  1205. {
  1206. $possibleUrls = [
  1207. 'http://www.vimeo.com/',
  1208. 'http://vimeo.com/',
  1209. 'https://www.vimeo.com/',
  1210. 'https://vimeo.com/',
  1211. ];
  1212. $url = str_replace($possibleUrls, '', $url);
  1213. if (is_numeric($url)) {
  1214. return $url;
  1215. }
  1216. return false;
  1217. }
  1218. /**
  1219. * This function checks if the url is a youtube link.
  1220. *
  1221. * @author Jorge Frisancho
  1222. * @author Julio Montoya - Fixing code
  1223. *
  1224. * @version 1.0
  1225. */
  1226. public static function is_youtube_link($url)
  1227. {
  1228. $is_youtube_link = strrpos($url, 'youtube') || strrpos(
  1229. $url,
  1230. 'youtu.be'
  1231. );
  1232. return $is_youtube_link;
  1233. }
  1234. /**
  1235. * This function checks if the url is a PDF File link.
  1236. *
  1237. * @author Jorge Frisancho
  1238. * @author Alex Aragón - Fixing code
  1239. *
  1240. * @version 1.0
  1241. */
  1242. public static function isPdfLink($url)
  1243. {
  1244. $isPdfLink = strrpos(strtolower($url), '.pdf');
  1245. return $isPdfLink;
  1246. }
  1247. /**
  1248. * Get youtube id from an URL.
  1249. *
  1250. * @param string $url
  1251. *
  1252. * @return string
  1253. */
  1254. public static function get_youtube_video_id($url)
  1255. {
  1256. // This is the length of YouTube's video IDs
  1257. $len = 11;
  1258. // The ID string starts after "v=", which is usually right after
  1259. // "youtube.com/watch?" in the URL
  1260. $pos = strpos($url, "v=");
  1261. $id = '';
  1262. //If false try other options
  1263. if ($pos === false) {
  1264. $url_parsed = parse_url($url);
  1265. //Youtube shortener
  1266. //http://youtu.be/ID
  1267. $pos = strpos($url, "youtu.be");
  1268. if ($pos == false) {
  1269. $id = '';
  1270. } else {
  1271. return substr($url_parsed['path'], 1);
  1272. }
  1273. //if empty try the youtube.com/embed/ID
  1274. if (empty($id)) {
  1275. $pos = strpos($url, "embed");
  1276. if ($pos === false) {
  1277. return '';
  1278. } else {
  1279. return substr($url_parsed['path'], 7);
  1280. }
  1281. }
  1282. } else {
  1283. // Offset the start location to match the beginning of the ID string
  1284. $pos += 2;
  1285. // Get the ID string and return it
  1286. $id = substr($url, $pos, $len);
  1287. return $id;
  1288. }
  1289. }
  1290. /**
  1291. * @param int $course_id
  1292. * @param int $session_id
  1293. * @param int $categoryId
  1294. * @param string $show
  1295. * @param null $token
  1296. * @param bool $showActionLinks
  1297. * @param bool $forceOpenCategories
  1298. *
  1299. * @return string
  1300. */
  1301. public static function listLinksAndCategories(
  1302. $course_id,
  1303. $session_id,
  1304. $categoryId,
  1305. $show = 'none',
  1306. $token = null,
  1307. $showActionLinks = true,
  1308. $forceOpenCategories = false
  1309. ) {
  1310. $categoryId = (int) $categoryId;
  1311. $content = '';
  1312. $categories = self::getLinkCategories($course_id, $session_id);
  1313. $countCategories = count($categories);
  1314. $linksPerCategory = self::showLinksPerCategory(0, $course_id, $session_id, $showActionLinks);
  1315. if ($showActionLinks) {
  1316. /* Action Links */
  1317. $content = '<div class="actions">';
  1318. if (api_is_allowed_to_edit(null, true)) {
  1319. $content .= '<a href="'.api_get_self().'?'.api_get_cidreq(
  1320. ).'&action=addlink&category_id='.$categoryId.'">'.
  1321. Display::return_icon('new_link.png', get_lang('LinksAdd'), '', ICON_SIZE_MEDIUM).'</a>';
  1322. $content .= '<a href="'.api_get_self().'?'.api_get_cidreq(
  1323. ).'&action=addcategory&category_id='.$categoryId.'">'.
  1324. Display::return_icon('new_folder.png', get_lang('Add a category'), '', ICON_SIZE_MEDIUM).'</a>';
  1325. }
  1326. if (!empty($countCategories)) {
  1327. $content .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=none">';
  1328. $content .= Display::return_icon(
  1329. 'forum_listview.png',
  1330. get_lang('List View'),
  1331. '',
  1332. ICON_SIZE_MEDIUM
  1333. ).' </a>';
  1334. $content .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=all">';
  1335. $content .= Display::return_icon(
  1336. 'forum_nestedview.png',
  1337. get_lang('Nested View'),
  1338. '',
  1339. ICON_SIZE_MEDIUM
  1340. ).'</a>';
  1341. }
  1342. $content .= Display::url(
  1343. Display::return_icon('pdf.png', get_lang('Export to PDF'), '', ICON_SIZE_MEDIUM),
  1344. api_get_self().'?'.api_get_cidreq().'&action=export'
  1345. );
  1346. $content .= '</div>';
  1347. }
  1348. if (empty($countCategories)) {
  1349. $content .= $linksPerCategory;
  1350. } else {
  1351. if (!empty($linksPerCategory)) {
  1352. $content .= Display::panel($linksPerCategory, get_lang('General'));
  1353. }
  1354. }
  1355. $counter = 0;
  1356. foreach ($categories as $myrow) {
  1357. // Student don't see invisible categories.
  1358. if (!api_is_allowed_to_edit(null, true)) {
  1359. if ($myrow['visibility'] == 0) {
  1360. continue;
  1361. }
  1362. }
  1363. // Validation when belongs to a session
  1364. $showChildren = $categoryId == $myrow['id'] || $show === 'all';
  1365. if ($forceOpenCategories) {
  1366. $showChildren = true;
  1367. }
  1368. $strVisibility = '';
  1369. $visibilityClass = null;
  1370. if ($myrow['visibility'] == '1') {
  1371. $strVisibility = '<a href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=invisible&id='.$myrow['id'].'&scope='.TOOL_LINK_CATEGORY.'" title="'.get_lang('Hide').'">'.
  1372. Display::return_icon('visible.png', get_lang('Hide'), [], ICON_SIZE_SMALL).'</a>';
  1373. } elseif ($myrow['visibility'] == '0') {
  1374. $visibilityClass = 'text-muted';
  1375. $strVisibility = ' <a href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=visible&id='.$myrow['id'].'&scope='.TOOL_LINK_CATEGORY.'" title="'.get_lang('Show').'">'.
  1376. Display::return_icon('invisible.png', get_lang('Show'), [], ICON_SIZE_SMALL).'</a>';
  1377. }
  1378. $header = '';
  1379. if ($showChildren) {
  1380. $header .= '<a class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id=">';
  1381. $header .= Display::return_icon('forum_nestedview.png');
  1382. } else {
  1383. $header .= '<a class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id='.$myrow['id'].'">';
  1384. $header .= Display::return_icon('forum_listview.png');
  1385. }
  1386. $header .= Security::remove_XSS($myrow['category_title']).'</a>';
  1387. if ($showActionLinks) {
  1388. if (api_is_allowed_to_edit(null, true)) {
  1389. if ($session_id == $myrow['session_id']) {
  1390. $header .= $strVisibility;
  1391. $header .= self::showCategoryAdminTools($myrow, $counter, count($categories));
  1392. } else {
  1393. $header .= get_lang('Edition not available from the session, please edit from the basic course.');
  1394. }
  1395. }
  1396. }
  1397. $childrenContent = '';
  1398. if ($showChildren) {
  1399. $childrenContent = self::showLinksPerCategory(
  1400. $myrow['id'],
  1401. api_get_course_int_id(),
  1402. api_get_session_id()
  1403. );
  1404. }
  1405. $content .= Display::panel($myrow['description'].$childrenContent, $header);
  1406. $counter++;
  1407. }
  1408. return $content;
  1409. }
  1410. /**
  1411. * @param int $linkId
  1412. * @param string $action
  1413. * @param null $token
  1414. *
  1415. * @return FormValidator
  1416. */
  1417. public static function getLinkForm($linkId, $action, $token = null)
  1418. {
  1419. $course_id = api_get_course_int_id();
  1420. $session_id = api_get_session_id();
  1421. $linkInfo = self::getLinkInfo($linkId);
  1422. $categoryId = isset($linkInfo['category_id']) ? $linkInfo['category_id'] : '';
  1423. $lpId = isset($_GET['lp_id']) ? Security::remove_XSS($_GET['lp_id']) : null;
  1424. $form = new FormValidator(
  1425. 'link',
  1426. 'post',
  1427. api_get_self().'?action='.$action.
  1428. '&category_id='.$categoryId.
  1429. '&'.api_get_cidreq().
  1430. '&id='.$linkId.
  1431. '&sec_token='.$token
  1432. );
  1433. if ($action == 'addlink') {
  1434. $form->addHeader(get_lang('LinksAdd'));
  1435. } else {
  1436. $form->addHeader(get_lang('LinksMod'));
  1437. }
  1438. $target_link = '_blank';
  1439. $title = '';
  1440. $category = '';
  1441. $onhomepage = '';
  1442. $description = '';
  1443. if (!empty($linkInfo)) {
  1444. $urllink = $linkInfo['url'];
  1445. $title = $linkInfo['title'];
  1446. $description = $linkInfo['description'];
  1447. $category = $linkInfo['category_id'];
  1448. if ($linkInfo['on_homepage'] != 0) {
  1449. $onhomepage = 1;
  1450. }
  1451. $target_link = $linkInfo['target'];
  1452. }
  1453. $form->addHidden('id', $linkId);
  1454. $form->addText('url', 'URL');
  1455. $form->addRule('url', get_lang('Please give the link URL, it should be valid.'), 'url');
  1456. $form->addText('title', get_lang('LinksName'));
  1457. $form->addHtmlEditor('description', get_lang('Description'), true, false, ['ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130']);
  1458. $resultcategories = self::getLinkCategories($course_id, $session_id);
  1459. $options = ['0' => '--'];
  1460. if (!empty($resultcategories)) {
  1461. foreach ($resultcategories as $myrow) {
  1462. $options[$myrow['id']] = $myrow['category_title'];
  1463. }
  1464. }
  1465. $form->addSelect('category_id', get_lang('Category'), $options);
  1466. $form->addCheckBox('on_homepage', null, get_lang('Show link on course homepage'));
  1467. $targets = [
  1468. '_self' => get_lang('LinksOpenSelf'),
  1469. '_blank' => get_lang('LinksOpenBlank'),
  1470. '_parent' => get_lang('LinksOpenParent'),
  1471. '_top' => get_lang('LinksOpenTop'),
  1472. ];
  1473. $form->addSelect(
  1474. 'target',
  1475. [
  1476. get_lang('LinksTarget'),
  1477. get_lang('AddTargetOfLinksShow link on course homepage'),
  1478. ],
  1479. $targets
  1480. );
  1481. $defaults = [
  1482. 'url' => empty($urllink) ? 'http://' : Security::remove_XSS($urllink),
  1483. 'title' => Security::remove_XSS($title),
  1484. 'category_id' => $category,
  1485. 'on_homepage' => $onhomepage,
  1486. 'description' => $description,
  1487. 'target' => $target_link,
  1488. ];
  1489. if (api_get_setting('search_enabled') == 'true') {
  1490. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  1491. $specific_fields = get_specific_field_list();
  1492. $form->addCheckBox('index_document', get_lang('Index link title and description?s'), get_lang('Yes'));
  1493. foreach ($specific_fields as $specific_field) {
  1494. $default_values = '';
  1495. if ($action == 'editlink') {
  1496. $filter = [
  1497. 'field_id' => $specific_field['id'],
  1498. 'ref_id' => intval($_GET['id']),
  1499. 'tool_id' => '\''.TOOL_LINK.'\'',
  1500. ];
  1501. $values = get_specific_field_values_list($filter, ['value']);
  1502. if (!empty($values)) {
  1503. $arr_str_values = [];
  1504. foreach ($values as $value) {
  1505. $arr_str_values[] = $value['value'];
  1506. }
  1507. $default_values = implode(', ', $arr_str_values);
  1508. }
  1509. }
  1510. $form->addText($specific_field['name'], $specific_field['code']);
  1511. $defaults[$specific_field['name']] = $default_values;
  1512. }
  1513. }
  1514. $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_LINK, $linkId);
  1515. $form->addHidden('lp_id', $lpId);
  1516. $form->addButtonSave(get_lang('Save links'), 'submitLinks');
  1517. $defaults['skills'] = array_keys($skillList);
  1518. $form->setDefaults($defaults);
  1519. return $form;
  1520. }
  1521. /**
  1522. * @param int $id
  1523. * @param string $action
  1524. *
  1525. * @return FormValidator
  1526. */
  1527. public static function getCategoryForm($id, $action)
  1528. {
  1529. $id = (int) $id;
  1530. $action = Security::remove_XSS($action);
  1531. $form = new FormValidator(
  1532. 'category',
  1533. 'post',
  1534. api_get_self().'?action='.$action.'&'.api_get_cidreq()
  1535. );
  1536. $defaults = [];
  1537. if ($action == 'addcategory') {
  1538. $form->addHeader(get_lang('Add a category'));
  1539. $my_cat_title = get_lang('Add a category');
  1540. } else {
  1541. $form->addHeader(get_lang('Edit Category'));
  1542. $my_cat_title = get_lang('Edit Category');
  1543. $defaults = self::getCategory($id);
  1544. }
  1545. $form->addHidden('id', $id);
  1546. $form->addText('category_title', get_lang('Category name'));
  1547. $form->addHtmlEditor('description', get_lang('Description'), true, false, ['ToolbarSet' => 'Profile', 'Width' => '100%', 'Height' => '130']);
  1548. $form->addButtonSave($my_cat_title, 'submitCategory');
  1549. $form->setDefaults($defaults);
  1550. return $form;
  1551. }
  1552. /**
  1553. * @param int $id
  1554. *
  1555. * @return array
  1556. */
  1557. public static function getCategory($id)
  1558. {
  1559. $table = Database::get_course_table(TABLE_LINK_CATEGORY);
  1560. $id = (int) $id;
  1561. $courseId = api_get_course_int_id();
  1562. if (empty($id) || empty($courseId)) {
  1563. return [];
  1564. }
  1565. $sql = "SELECT * FROM $table
  1566. WHERE id = $id AND c_id = $courseId";
  1567. $result = Database::query($sql);
  1568. $category = Database::fetch_array($result, 'ASSOC');
  1569. return $category;
  1570. }
  1571. /**
  1572. * Move a link up in its category.
  1573. *
  1574. * @param int $id
  1575. *
  1576. * @return bool
  1577. */
  1578. public static function moveLinkUp($id)
  1579. {
  1580. return self::moveLinkDisplayOrder($id, 'ASC');
  1581. }
  1582. /**
  1583. * Move a link down in its category.
  1584. *
  1585. * @param int $id
  1586. *
  1587. * @return bool
  1588. */
  1589. public static function moveLinkDown($id)
  1590. {
  1591. return self::moveLinkDisplayOrder($id, 'DESC');
  1592. }
  1593. /**
  1594. * @param string $url
  1595. *
  1596. * @return bool
  1597. */
  1598. public static function checkUrl($url)
  1599. {
  1600. // Check if curl is available.
  1601. if (!in_array('curl', get_loaded_extensions())) {
  1602. return false;
  1603. }
  1604. // set URL and other appropriate options
  1605. $defaults = [
  1606. CURLOPT_URL => $url,
  1607. CURLOPT_FOLLOWLOCATION => true, // follow redirects accept youtube.com
  1608. CURLOPT_HEADER => 0,
  1609. CURLOPT_RETURNTRANSFER => true,
  1610. CURLOPT_TIMEOUT => 4,
  1611. ];
  1612. $proxySettings = api_get_configuration_value('proxy_settings');
  1613. if (!empty($proxySettings) &&
  1614. isset($proxySettings['curl_setopt_array'])
  1615. ) {
  1616. $defaults[CURLOPT_PROXY] = $proxySettings['curl_setopt_array']['CURLOPT_PROXY'];
  1617. $defaults[CURLOPT_PROXYPORT] = $proxySettings['curl_setopt_array']['CURLOPT_PROXYPORT'];
  1618. }
  1619. // Create a new cURL resource
  1620. $ch = curl_init();
  1621. curl_setopt_array($ch, $defaults);
  1622. // grab URL and pass it to the browser
  1623. ob_start();
  1624. $result = curl_exec($ch);
  1625. ob_get_clean();
  1626. // close cURL resource, and free up system resources
  1627. curl_close($ch);
  1628. return $result;
  1629. }
  1630. /**
  1631. * Move a link inside its category (display_order field).
  1632. *
  1633. * @param int $id The link ID
  1634. * @param string $direction The direction to sort the links
  1635. *
  1636. * @return bool
  1637. */
  1638. private static function moveLinkDisplayOrder($id, $direction)
  1639. {
  1640. $em = Database::getManager();
  1641. /** @var CLink $link */
  1642. $link = $em->find('ChamiloCourseBundle:CLink', $id);
  1643. if (!$link) {
  1644. return false;
  1645. }
  1646. $compareLinks = $em
  1647. ->getRepository('ChamiloCourseBundle:CLink')
  1648. ->findBy(
  1649. [
  1650. 'cId' => $link->getCId(),
  1651. 'categoryId' => $link->getCategoryId(),
  1652. ],
  1653. ['displayOrder' => $direction]
  1654. );
  1655. /** @var CLink $prevLink */
  1656. $prevLink = null;
  1657. /** @var CLink $compareLink */
  1658. foreach ($compareLinks as $compareLink) {
  1659. if ($compareLink->getId() !== $link->getId()) {
  1660. $prevLink = $compareLink;
  1661. continue;
  1662. }
  1663. if (!$prevLink) {
  1664. return false;
  1665. }
  1666. $newPrevLinkDisplayOrder = $link->getDisplayOrder();
  1667. $newLinkDisplayOrder = $prevLink->getDisplayOrder();
  1668. $link->setDisplayOrder($newLinkDisplayOrder);
  1669. $prevLink->setDisplayOrder($newPrevLinkDisplayOrder);
  1670. $em->merge($prevLink);
  1671. $em->merge($link);
  1672. break;
  1673. }
  1674. $em->flush();
  1675. return true;
  1676. }
  1677. }