link.lib.php 68 KB

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