link.lib.php 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949
  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. * @param integer $id
  421. * @return array link info
  422. *
  423. **/
  424. public static function get_link_info($id)
  425. {
  426. $tbl_link = Database::get_course_table(TABLE_LINK);
  427. $course_id = api_get_course_int_id();
  428. if (empty($id) || empty($course_id)) {
  429. return [];
  430. }
  431. $sql = "SELECT * FROM $tbl_link
  432. WHERE c_id = $course_id AND id='".intval($id)."' ";
  433. $result = Database::query($sql);
  434. $data = array();
  435. if (Database::num_rows($result)) {
  436. $data = Database::fetch_array($result);
  437. }
  438. return $data;
  439. }
  440. /**
  441. * @param int $id
  442. * @param array $values
  443. */
  444. public static function editLink($id, $values = array())
  445. {
  446. $tbl_link = Database::get_course_table(TABLE_LINK);
  447. $_course = api_get_course_info();
  448. $course_id = $_course['real_id'];
  449. $id = intval($id);
  450. $values['url'] = trim($values['url']);
  451. $values['title'] = trim($values['title']);
  452. $values['description'] = trim($values['description']);
  453. $values['target'] = empty($values['target']) ? '_self' : $values['target'];
  454. $values['on_homepage'] = isset($values['on_homepage']) ? $values['on_homepage'] : '';
  455. $categoryId = intval($values['category_id']);
  456. // We ensure URL to be absolute.
  457. if (strpos($values['url'], '://') === false) {
  458. $values['url'] = 'http://'.$_POST['url'];
  459. }
  460. // If the title is empty, we use the URL as title.
  461. if ($values['title'] == '') {
  462. $values['title'] = $values['url'];
  463. }
  464. // If the URL is invalid, an error occurs.
  465. if (!api_valid_url($values['url'], true)) {
  466. Display::addFlash(
  467. Display::return_message(get_lang('GiveURL'), 'error')
  468. );
  469. return false;
  470. }
  471. if (empty($id) || empty($course_id)) {
  472. return false;
  473. }
  474. // Finding the old category_id.
  475. $sql = "SELECT * FROM $tbl_link
  476. WHERE c_id = $course_id AND id='".$id."'";
  477. $result = Database:: query($sql);
  478. $row = Database:: fetch_array($result);
  479. $category_id = $row['category_id'];
  480. if ($category_id != $values['category_id']) {
  481. $sql = "SELECT MAX(display_order)
  482. FROM $tbl_link
  483. WHERE
  484. c_id = $course_id AND
  485. category_id='".intval($values['category_id'])."'";
  486. $result = Database:: query($sql);
  487. list ($max_display_order) = Database:: fetch_row($result);
  488. $max_display_order++;
  489. } else {
  490. $max_display_order = $row['display_order'];
  491. }
  492. $params = [
  493. 'url' => $values['url'],
  494. 'title' => $values['title'],
  495. 'description' => $values['description'],
  496. 'category_id' => $values['category_id'],
  497. 'display_order' => $max_display_order,
  498. 'on_homepage' => $values['on_homepage'],
  499. 'target' => $values['target'],
  500. 'category_id' => $values['category_id']
  501. ];
  502. Database::update(
  503. $tbl_link,
  504. $params,
  505. ['c_id = ? AND id = ?' => [$course_id, $id]]
  506. );
  507. // Update search enchine and its values table if enabled.
  508. if (api_get_setting('search_enabled') == 'true') {
  509. $course_int_id = api_get_course_int_id();
  510. $course_id = api_get_course_id();
  511. $link_title = Database:: escape_string($values['title']);
  512. $link_description = Database:: escape_string($values['description']);
  513. // Actually, it consists on delete terms from db,
  514. // insert new ones, create a new search engine document, and remove the old one.
  515. // Get search_did.
  516. $tbl_se_ref = Database::get_main_table(
  517. TABLE_MAIN_SEARCH_ENGINE_REF
  518. );
  519. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  520. $sql = sprintf(
  521. $sql,
  522. $tbl_se_ref,
  523. $course_id,
  524. TOOL_LINK,
  525. $id
  526. );
  527. $res = Database:: query($sql);
  528. if (Database:: num_rows($res) > 0) {
  529. require_once api_get_path(LIBRARY_PATH).'search/ChamiloIndexer.class.php';
  530. require_once api_get_path(LIBRARY_PATH).'search/IndexableChunk.class.php';
  531. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  532. $se_ref = Database:: fetch_array($res);
  533. $specific_fields = get_specific_field_list();
  534. $ic_slide = new IndexableChunk();
  535. $all_specific_terms = '';
  536. foreach ($specific_fields as $specific_field) {
  537. delete_all_specific_field_value(
  538. $course_id,
  539. $specific_field['id'],
  540. TOOL_LINK,
  541. $id
  542. );
  543. if (isset($_REQUEST[$specific_field['code']])) {
  544. $sterms = trim(
  545. $_REQUEST[$specific_field['code']]
  546. );
  547. if (!empty($sterms)) {
  548. $all_specific_terms .= ' '.$sterms;
  549. $sterms = explode(',', $sterms);
  550. foreach ($sterms as $sterm) {
  551. $ic_slide->addTerm(
  552. trim($sterm),
  553. $specific_field['code']
  554. );
  555. add_specific_field_value(
  556. $specific_field['id'],
  557. $course_id,
  558. TOOL_LINK,
  559. $id,
  560. $sterm
  561. );
  562. }
  563. }
  564. }
  565. }
  566. // Build the chunk to index.
  567. $ic_slide->addValue("title", $link_title);
  568. $ic_slide->addCourseId($course_id);
  569. $ic_slide->addToolId(TOOL_LINK);
  570. $xapian_data = array(
  571. SE_COURSE_ID => $course_id,
  572. SE_TOOL_ID => TOOL_LINK,
  573. SE_DATA => array(
  574. 'link_id' => (int) $id
  575. ),
  576. SE_USER => (int) api_get_user_id(),
  577. );
  578. $ic_slide->xapian_data = serialize($xapian_data);
  579. $link_description = $all_specific_terms.' '.$link_description;
  580. $ic_slide->addValue('content', $link_description);
  581. // Add category name if set.
  582. if (isset($categoryId) && $categoryId > 0) {
  583. $table_link_category = Database::get_course_table(
  584. TABLE_LINK_CATEGORY
  585. );
  586. $sql_cat = 'SELECT * FROM %s WHERE id=%d and c_id = %d LIMIT 1';
  587. $sql_cat = sprintf(
  588. $sql_cat,
  589. $table_link_category,
  590. $categoryId,
  591. $course_int_id
  592. );
  593. $result = Database:: query($sql_cat);
  594. if (Database:: num_rows($result) == 1) {
  595. $row = Database:: fetch_array($result);
  596. $ic_slide->addValue(
  597. 'category',
  598. $row['category_title']
  599. );
  600. }
  601. }
  602. $di = new ChamiloIndexer();
  603. isset ($_POST['language']) ? $lang = Database:: escape_string($_POST['language']) : $lang = 'english';
  604. $di->connectDb(null, null, $lang);
  605. $di->remove_document((int) $se_ref['search_did']);
  606. $di->addChunk($ic_slide);
  607. // Index and return search engine document id.
  608. $did = $di->index();
  609. if ($did) {
  610. // Save it to db.
  611. $sql = 'DELETE FROM %s
  612. WHERE course_code=\'%s\'
  613. AND tool_id=\'%s\'
  614. AND ref_id_high_level=\'%s\'';
  615. $sql = sprintf(
  616. $sql,
  617. $tbl_se_ref,
  618. $course_id,
  619. TOOL_LINK,
  620. $id
  621. );
  622. Database:: query($sql);
  623. $sql = 'INSERT INTO %s (c_id, id, course_code, tool_id, ref_id_high_level, search_did)
  624. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  625. $sql = sprintf(
  626. $sql,
  627. $tbl_se_ref,
  628. $course_int_id,
  629. $course_id,
  630. TOOL_LINK,
  631. $id,
  632. $did
  633. );
  634. Database:: query($sql);
  635. }
  636. }
  637. }
  638. // "WHAT'S NEW" notification: update table last_toolEdit.
  639. api_item_property_update(
  640. $_course,
  641. TOOL_LINK,
  642. $id,
  643. 'LinkUpdated',
  644. api_get_user_id()
  645. );
  646. Display::addFlash(Display::return_message(get_lang('LinkModded')));
  647. }
  648. /**
  649. * @param int $id
  650. * @return bool
  651. */
  652. public static function editCategory($id, $values)
  653. {
  654. $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
  655. $course_id = api_get_course_int_id();
  656. $id = intval($id);
  657. // This is used to put the modified info of the category-form into the database.
  658. $params = [
  659. 'category_title' => $values['category_title'],
  660. 'description' => $values['description']
  661. ];
  662. Database::update(
  663. $tbl_categories,
  664. $params,
  665. ['c_id = ? AND id = ?' => [$course_id, $id]]
  666. );
  667. Display::addFlash(Display::return_message(get_lang('CategoryModded')));
  668. return true;
  669. }
  670. /**
  671. * Changes the visibility of a link
  672. * @todo add the changing of the visibility of a course
  673. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  674. */
  675. public static function change_visibility_link($id, $scope)
  676. {
  677. $_course = api_get_course_info();
  678. $_user = api_get_user_info();
  679. if ($scope == TOOL_LINK) {
  680. api_item_property_update(
  681. $_course,
  682. TOOL_LINK,
  683. $id,
  684. $_GET['action'],
  685. $_user['user_id']
  686. );
  687. Display::addFlash(Display::return_message(get_lang('VisibilityChanged')));
  688. } elseif ($scope == TOOL_LINK_CATEGORY) {
  689. api_item_property_update(
  690. $_course,
  691. TOOL_LINK_CATEGORY,
  692. $id,
  693. $_GET['action'],
  694. $_user['user_id']
  695. );
  696. Display::addFlash(Display::return_message(get_lang('VisibilityChanged')));
  697. }
  698. }
  699. /**
  700. * Generate SQL to select all the links categories in the current course and
  701. * session
  702. * @param int $courseId
  703. * @param int $sessionId
  704. * @param bool $withBaseContent
  705. *
  706. * @return array
  707. */
  708. public static function getLinkCategories($courseId, $sessionId, $withBaseContent = true)
  709. {
  710. $tblLinkCategory = Database::get_course_table(TABLE_LINK_CATEGORY);
  711. $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  712. $courseId = intval($courseId);
  713. // Condition for the session.
  714. $sessionCondition = api_get_session_condition(
  715. $sessionId,
  716. true,
  717. $withBaseContent,
  718. 'linkcat.session_id'
  719. );
  720. // Getting links
  721. $sql = "SELECT *, linkcat.id
  722. FROM $tblLinkCategory linkcat
  723. WHERE
  724. linkcat.c_id = $courseId
  725. $sessionCondition
  726. ORDER BY linkcat.display_order DESC";
  727. $result = Database::query($sql);
  728. $categories = Database::store_result($result);
  729. $sql = "SELECT *, linkcat.id
  730. FROM $tblLinkCategory linkcat
  731. INNER JOIN $tblItemProperty ip
  732. ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
  733. WHERE
  734. ip.tool = '".TOOL_LINK_CATEGORY."' AND
  735. (ip.visibility = '0' OR ip.visibility = '1')
  736. $sessionCondition AND
  737. linkcat.c_id = ".$courseId."
  738. ORDER BY linkcat.display_order DESC";
  739. $result = Database::query($sql);
  740. $categoryInItemProperty = array();
  741. if (Database::num_rows($result)) {
  742. while ($row = Database::fetch_array($result, 'ASSOC')) {
  743. $categoryInItemProperty[$row['id']] = $row;
  744. }
  745. }
  746. foreach ($categories as & $category) {
  747. if (!isset($categoryInItemProperty[$category['id']])) {
  748. api_set_default_visibility($category['id'], TOOL_LINK_CATEGORY);
  749. }
  750. }
  751. $sql = "SELECT DISTINCT linkcat.*, visibility
  752. FROM $tblLinkCategory linkcat
  753. INNER JOIN $tblItemProperty ip
  754. ON (linkcat.id = ip.ref AND linkcat.c_id = ip.c_id)
  755. WHERE
  756. ip.tool = '".TOOL_LINK_CATEGORY."' AND
  757. (ip.visibility = '0' OR ip.visibility = '1')
  758. $sessionCondition AND
  759. linkcat.c_id = ".$courseId."
  760. ORDER BY linkcat.display_order DESC
  761. ";
  762. $result = Database::query($sql);
  763. return Database::store_result($result, 'ASSOC');
  764. }
  765. /**
  766. * @param integer $categoryId
  767. * @param $courseId
  768. * @param $sessionId
  769. * @param bool $withBaseContent
  770. *
  771. * @return array
  772. */
  773. public static function getLinksPerCategory(
  774. $categoryId,
  775. $courseId,
  776. $sessionId,
  777. $withBaseContent = true
  778. ) {
  779. $tbl_link = Database::get_course_table(TABLE_LINK);
  780. $TABLE_ITEM_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  781. $courseId = (int) $courseId;
  782. $sessionId = (int) $sessionId;
  783. $categoryId = (int) $categoryId;
  784. // Condition for the session.
  785. $condition_session = api_get_session_condition(
  786. $sessionId,
  787. true,
  788. false,
  789. 'ip.session_id'
  790. );
  791. if (!empty($sessionId)) {
  792. $conditionBaseSession = api_get_session_condition(
  793. 0,
  794. true,
  795. $withBaseContent,
  796. 'ip.session_id'
  797. );
  798. $condition = " AND
  799. (
  800. (ip.visibility = '1' $conditionBaseSession) OR
  801. (
  802. (ip.visibility = '0' OR ip.visibility = '1')
  803. $condition_session
  804. )
  805. )
  806. ";
  807. } else {
  808. $condition = api_get_session_condition(
  809. 0,
  810. true,
  811. false,
  812. 'ip.session_id'
  813. );
  814. $condition .= " AND (ip.visibility = '0' OR ip.visibility = '1') $condition ";
  815. }
  816. $sql = "SELECT
  817. link.id,
  818. ip.session_id,
  819. link.session_id link_session_id,
  820. url,
  821. category_id,
  822. visibility,
  823. description,
  824. title,
  825. target,
  826. on_homepage
  827. FROM $tbl_link link
  828. INNER JOIN $TABLE_ITEM_PROPERTY ip
  829. ON (link.id = ip.ref AND link.c_id = ip.c_id)
  830. WHERE
  831. ip.tool = '".TOOL_LINK."' AND
  832. link.category_id = '" . $categoryId."' AND
  833. link.c_id = $courseId AND
  834. ip.c_id = $courseId
  835. $condition
  836. ORDER BY link.display_order ASC, ip.session_id DESC";
  837. $result = Database:: query($sql);
  838. return Database::store_result($result);
  839. }
  840. /**
  841. * Displays all the links of a given category.
  842. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  843. * @author Julio Montoya
  844. *
  845. * @param $catid
  846. * @param integer $courseId
  847. * @param integer $session_id
  848. * @return string
  849. */
  850. public static function showLinksPerCategory($catid, $courseId, $session_id)
  851. {
  852. global $token;
  853. $_user = api_get_user_info();
  854. $catid = intval($catid);
  855. $links = self::getLinksPerCategory($catid, $courseId, $session_id);
  856. $content = '';
  857. $numberOfLinks = count($links);
  858. if (!empty($links)) {
  859. $content .= '<div class="link list-group">';
  860. $i = 1;
  861. $linksAdded = [];
  862. foreach ($links as $myrow) {
  863. $linkId = $myrow['id'];
  864. if (in_array($linkId, $linksAdded)) {
  865. continue;
  866. }
  867. $linksAdded[] = $linkId;
  868. $categoryId = $myrow['category_id'];
  869. // Validation when belongs to a session.
  870. $session_img = api_get_session_image(
  871. $myrow['link_session_id'],
  872. $_user['status']
  873. );
  874. $toolbar = '';
  875. $link_validator = '';
  876. if (api_is_allowed_to_edit(null, true)) {
  877. $toolbar .= Display::toolbarButton(
  878. '',
  879. 'javascript:void(0);',
  880. 'check-circle-o',
  881. 'default btn-sm',
  882. array(
  883. 'onclick' => "check_url('".$linkId."', '".addslashes($myrow['url'])."');",
  884. 'title' => get_lang('CheckURL')
  885. )
  886. );
  887. $link_validator .= Display::span(
  888. '',
  889. array(
  890. 'id' => 'url_id_'.$linkId,
  891. 'class' => 'check-link'
  892. )
  893. );
  894. if ($session_id == $myrow['link_session_id']) {
  895. $url = api_get_self().'?'.api_get_cidreq().'&action=editlink&id='.$linkId;
  896. $title = get_lang('Edit');
  897. $toolbar .= Display::toolbarButton(
  898. '',
  899. $url,
  900. 'pencil',
  901. 'default btn-sm',
  902. array(
  903. 'title' => $title
  904. )
  905. );
  906. }
  907. $urlVisibility = api_get_self().'?'.api_get_cidreq().
  908. '&sec_token='.$token.
  909. '&id='.$linkId.
  910. '&scope=link&category_id='.$categoryId;
  911. switch ($myrow['visibility']) {
  912. case '1':
  913. $urlVisibility .= '&action=invisible';
  914. $title = get_lang('MakeInvisible');
  915. $toolbar .= Display::toolbarButton(
  916. '',
  917. $urlVisibility,
  918. 'eye',
  919. 'default btn-sm',
  920. array(
  921. 'title' => $title
  922. )
  923. );
  924. break;
  925. case '0':
  926. $urlVisibility .= '&action=visible';
  927. $title = get_lang('MakeVisible');
  928. $toolbar .= Display::toolbarButton(
  929. '',
  930. $urlVisibility,
  931. 'eye-slash',
  932. 'primary btn-sm',
  933. array(
  934. 'title' => $title
  935. )
  936. );
  937. break;
  938. }
  939. if ($session_id == $myrow['link_session_id']) {
  940. $moveLinkParams = [
  941. 'id' => $linkId,
  942. 'scope' => 'category',
  943. 'category_id' => $categoryId,
  944. 'action' => 'move_link_up'
  945. ];
  946. $toolbar .= Display::toolbarButton(
  947. get_lang('MoveUp'),
  948. api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
  949. 'level-up',
  950. 'default',
  951. ['class' => 'btn-sm '.($i === 1 ? 'disabled' : '')],
  952. false
  953. );
  954. $moveLinkParams['action'] = 'move_link_down';
  955. $toolbar .= Display::toolbarButton(
  956. get_lang('MoveDown'),
  957. api_get_self().'?'.api_get_cidreq().'&'.http_build_query($moveLinkParams),
  958. 'level-down',
  959. 'default',
  960. ['class' => 'btn-sm '.($i === $numberOfLinks ? 'disabled' : '')],
  961. false
  962. );
  963. $url .= api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletelink&id='.$linkId.'&category_id='.$categoryId;
  964. $event = "javascript: if(!confirm('".get_lang('LinkDelconfirm')."'))return false;";
  965. $title = get_lang('Delete');
  966. $toolbar .= Display::toolbarButton(
  967. '',
  968. $url,
  969. 'trash',
  970. 'default btn-sm',
  971. array(
  972. 'onclick' => $event,
  973. 'title' => $title
  974. )
  975. );
  976. }
  977. }
  978. $iconLink = Display::return_icon(
  979. 'url.png',
  980. get_lang('Link'),
  981. null,
  982. ICON_SIZE_SMALL
  983. );
  984. if ($myrow['visibility'] == '1') {
  985. $content .= '<div class="list-group-item">';
  986. $content .= '<div class="pull-right"><div class="btn-group">'.$toolbar.'</div></div>';
  987. $content .= '<h4 class="list-group-item-heading">';
  988. $content .= $iconLink;
  989. $url = api_get_path(WEB_CODE_PATH).'link/link_goto.php?'.api_get_cidreq().'&link_id='.$linkId.'&link_url='.urlencode($myrow['url']);
  990. $content .= Display::tag(
  991. 'a',
  992. Security::remove_XSS($myrow['title']),
  993. array(
  994. 'href' => $url,
  995. 'target' => $myrow['target']
  996. )
  997. );
  998. $content .= $link_validator;
  999. $content .= $session_img;
  1000. $content .= '</h4>';
  1001. $content .= '<p class="list-group-item-text">'.$myrow['description'].'</p>';
  1002. $content .= '</div>';
  1003. } else {
  1004. if (api_is_allowed_to_edit(null, true)) {
  1005. $content .= '<div class="list-group-item">';
  1006. $content .= '<div class="pull-right"><div class="btn-group">'.$toolbar.'</div></div>';
  1007. $content .= '<h4 class="list-group-item-heading">';
  1008. $content .= $iconLink;
  1009. $url = api_get_path(WEB_CODE_PATH).'link/link_goto.php?'.api_get_cidreq().'&link_id='.$linkId."&link_url=".urlencode($myrow['url']);
  1010. $content .= Display::tag(
  1011. 'a',
  1012. Security::remove_XSS($myrow['title']),
  1013. array(
  1014. 'href' => $url,
  1015. 'target' => '_blank',
  1016. 'class' => 'text-muted'
  1017. )
  1018. );
  1019. $content .= $link_validator;
  1020. $content .= $session_img;
  1021. $content .= '</h4>';
  1022. $content .= '<p class="list-group-item-text">'.$myrow['description'].'</p>';
  1023. $content .= '</div>';
  1024. }
  1025. }
  1026. $i++;
  1027. }
  1028. $content .= '</div>';
  1029. }
  1030. return $content;
  1031. }
  1032. /**
  1033. * Displays the edit, delete and move icons
  1034. * @param int Category ID
  1035. * @param integer $currentCategory
  1036. * @param integer $countCategories
  1037. * @return string
  1038. *
  1039. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1040. */
  1041. public static function showCategoryAdminTools($category, $currentCategory, $countCategories)
  1042. {
  1043. $categoryId = $category['id'];
  1044. $token = null;
  1045. $tools = '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=editcategory&id='.$categoryId.'&category_id='.$categoryId.'" title='.get_lang('Modify').'">'.
  1046. Display:: return_icon(
  1047. 'edit.png',
  1048. get_lang('Modify'),
  1049. array(),
  1050. ICON_SIZE_SMALL
  1051. ).'</a>';
  1052. // DISPLAY MOVE UP COMMAND only if it is not the top link.
  1053. if ($currentCategory != 0) {
  1054. $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=up&up='.$categoryId.'&category_id='.$categoryId.'" title="'.get_lang('Up').'">'.
  1055. Display:: return_icon(
  1056. 'up.png',
  1057. get_lang('Up'),
  1058. array(),
  1059. ICON_SIZE_SMALL
  1060. ).'</a>';
  1061. } else {
  1062. $tools .= Display:: return_icon(
  1063. 'up_na.png',
  1064. get_lang('Up'),
  1065. array(),
  1066. ICON_SIZE_SMALL
  1067. ).'</a>';
  1068. }
  1069. // DISPLAY MOVE DOWN COMMAND only if it is not the bottom link.
  1070. if ($currentCategory < $countCategories - 1) {
  1071. $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=down&down='.$categoryId.'&category_id='.$categoryId.'">'.
  1072. Display:: return_icon(
  1073. 'down.png',
  1074. get_lang('Down'),
  1075. array(),
  1076. ICON_SIZE_SMALL
  1077. ).'</a>';
  1078. } else {
  1079. $tools .= Display:: return_icon(
  1080. 'down_na.png',
  1081. get_lang('Down'),
  1082. array(),
  1083. ICON_SIZE_SMALL
  1084. ).'</a>';
  1085. }
  1086. $tools .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&sec_token='.$token.'&action=deletecategory&id='.$categoryId."&category_id=$categoryId\"
  1087. onclick=\"javascript: if(!confirm('".get_lang('CategoryDelconfirm')."')) return false;\">".
  1088. Display:: return_icon(
  1089. 'delete.png',
  1090. get_lang('Delete'),
  1091. array(),
  1092. ICON_SIZE_SMALL
  1093. ).'</a>';
  1094. return $tools;
  1095. }
  1096. /**
  1097. * move a link or a linkcategory up or down
  1098. * @param int Category ID
  1099. * @param int Course ID
  1100. * @param int Session ID
  1101. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  1102. * @todo support sessions
  1103. */
  1104. public static function movecatlink($action, $catlinkid, $courseId = null, $sessionId = null)
  1105. {
  1106. $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
  1107. if (is_null($courseId)) {
  1108. $courseId = api_get_course_int_id();
  1109. }
  1110. $courseId = intval($courseId);
  1111. if (is_null($sessionId)) {
  1112. $sessionId = api_get_session_id();
  1113. }
  1114. $sessionId = intval($sessionId);
  1115. $thiscatlinkId = intval($catlinkid);
  1116. if ($action == 'down') {
  1117. $sortDirection = 'DESC';
  1118. }
  1119. if ($action == 'up') {
  1120. $sortDirection = 'ASC';
  1121. }
  1122. $movetable = $tbl_categories;
  1123. if (!empty($sortDirection)) {
  1124. if (!in_array(trim(strtoupper($sortDirection)), array('ASC', 'DESC'))) {
  1125. $sortDirection = 'ASC';
  1126. }
  1127. $sql = "SELECT id, display_order FROM $movetable
  1128. WHERE c_id = $courseId
  1129. ORDER BY display_order $sortDirection";
  1130. $linkresult = Database:: query($sql);
  1131. $thislinkOrder = 1;
  1132. while ($sortrow = Database:: fetch_array($linkresult)) {
  1133. // STEP 2 : FOUND THE NEXT LINK ID AND ORDER, COMMIT SWAP
  1134. // This part seems unlogic, but it isn't . We first look for the current link with the querystring ID
  1135. // and we know the next iteration of the while loop is the next one. These should be swapped.
  1136. if (isset($thislinkFound) && $thislinkFound) {
  1137. $nextlinkId = $sortrow['id'];
  1138. $nextlinkOrder = $sortrow['display_order'];
  1139. Database:: query(
  1140. "UPDATE ".$movetable."
  1141. SET display_order = '$nextlinkOrder'
  1142. WHERE c_id = $courseId AND id = '$thiscatlinkId'"
  1143. );
  1144. Database:: query(
  1145. "UPDATE ".$movetable."
  1146. SET display_order = '$thislinkOrder'
  1147. WHERE c_id = $courseId AND id = '$nextlinkId'"
  1148. );
  1149. break;
  1150. }
  1151. if ($sortrow['id'] == $thiscatlinkId) {
  1152. $thislinkOrder = $sortrow['display_order'];
  1153. $thislinkFound = true;
  1154. }
  1155. }
  1156. }
  1157. Display::addFlash(Display::return_message(get_lang('LinkMoved')));
  1158. }
  1159. /**
  1160. * CSV file import functions
  1161. * @author René Haentjens , Ghent University
  1162. * @param string $catname
  1163. */
  1164. public static function get_cat($catname)
  1165. {
  1166. // Get category id (existing or make new).
  1167. $tbl_categories = Database::get_course_table(TABLE_LINK_CATEGORY);
  1168. $course_id = api_get_course_int_id();
  1169. $result = Database:: query(
  1170. "SELECT id FROM ".$tbl_categories."
  1171. WHERE c_id = $course_id AND category_title='".Database::escape_string($catname)."'"
  1172. );
  1173. if (Database:: num_rows($result) >= 1 && ($row = Database:: fetch_array($result))) {
  1174. return $row['id']; // Several categories with same name: take the first.
  1175. }
  1176. $result = Database:: query(
  1177. "SELECT MAX(display_order) FROM ".$tbl_categories." WHERE c_id = $course_id "
  1178. );
  1179. list ($max_order) = Database:: fetch_row($result);
  1180. $params = [
  1181. 'c_id' => $course_id,
  1182. 'category_title' => $catname,
  1183. 'description' => '',
  1184. 'display_order' => $max_order + 1
  1185. ];
  1186. $id = Database::insert($tbl_categories, $params);
  1187. return $id;
  1188. }
  1189. /**
  1190. * CSV file import functions
  1191. * @author René Haentjens , Ghent University
  1192. * @param string $url
  1193. * @param string $title
  1194. * @param string $description
  1195. * @param string $on_homepage
  1196. * @param string $hidden
  1197. */
  1198. public static function put_link($url, $cat, $title, $description, $on_homepage, $hidden)
  1199. {
  1200. $_course = api_get_course_info();
  1201. $_user = api_get_user_info();
  1202. $tbl_link = Database::get_course_table(TABLE_LINK);
  1203. $course_id = api_get_course_int_id();
  1204. $urleq = "url='".Database:: escape_string($url)."'";
  1205. $cateq = "category_id=".intval($cat);
  1206. $result = Database:: query("
  1207. SELECT id FROM $tbl_link
  1208. WHERE c_id = $course_id AND ".$urleq.' AND '.$cateq
  1209. );
  1210. if (Database:: num_rows($result) >= 1 && ($row = Database:: fetch_array($result))) {
  1211. $sql = "UPDATE $tbl_link SET
  1212. title = '".Database:: escape_string($title)."',
  1213. description = '" . Database:: escape_string($description)."'
  1214. WHERE c_id = $course_id AND id='".Database:: escape_string($row['id'])."'";
  1215. Database:: query($sql);
  1216. $ipu = 'LinkUpdated';
  1217. $rv = 1; // 1 = upd
  1218. } else {
  1219. // Add new link
  1220. $result = Database:: query(
  1221. "SELECT MAX(display_order) FROM $tbl_link
  1222. WHERE c_id = $course_id AND category_id='".intval($cat)."'"
  1223. );
  1224. list ($max_order) = Database:: fetch_row($result);
  1225. Database:: query(
  1226. "INSERT INTO $tbl_link (c_id, url, title, description, category_id, display_order, on_homepage)
  1227. VALUES (".api_get_course_int_id().",
  1228. '" . Database:: escape_string($url)."',
  1229. '" . Database:: escape_string($title)."',
  1230. '" . Database:: escape_string($description)."',
  1231. '" . intval($cat)."','".(intval($max_order) + 1)."',
  1232. '" . intval($on_homepage).
  1233. "')"
  1234. );
  1235. $id = Database:: insert_id();
  1236. $ipu = 'LinkAdded';
  1237. $rv = 2; // 2 = new
  1238. }
  1239. api_item_property_update(
  1240. $_course,
  1241. TOOL_LINK,
  1242. $id,
  1243. $ipu,
  1244. $_user['user_id']
  1245. );
  1246. if ($hidden && $ipu == 'LinkAdded') {
  1247. api_item_property_update(
  1248. $_course,
  1249. TOOL_LINK,
  1250. $id,
  1251. 'invisible',
  1252. $_user['user_id']
  1253. );
  1254. }
  1255. return $rv;
  1256. }
  1257. /**
  1258. * CSV file import functions
  1259. * @author René Haentjens , Ghent University
  1260. */
  1261. public static function import_link($linkdata)
  1262. {
  1263. // url, category_id, title, description, ...
  1264. // Field names used in the uploaded file
  1265. $known_fields = array(
  1266. 'url',
  1267. 'category',
  1268. 'title',
  1269. 'description',
  1270. 'on_homepage',
  1271. 'hidden'
  1272. );
  1273. $hide_fields = array(
  1274. 'kw',
  1275. 'kwd',
  1276. 'kwds',
  1277. 'keyword',
  1278. 'keywords'
  1279. );
  1280. // All other fields are added to description, as "name:value".
  1281. // Only one hide_field is assumed to be present, <> is removed from value.
  1282. if (!($url = trim($linkdata['url'])) || !($title = trim($linkdata['title']))) {
  1283. return 0; // 0 = fail
  1284. }
  1285. $cat = ($catname = trim($linkdata['category'])) ? self::get_cat($catname) : 0;
  1286. $regs = array(); // Will be passed to ereg()
  1287. $d = '';
  1288. foreach ($linkdata as $key => $value) {
  1289. if (!in_array($key, $known_fields)) {
  1290. if (in_array($key, $hide_fields) && ereg(
  1291. '^<?([^>]*)>?$',
  1292. $value,
  1293. $regs
  1294. )
  1295. ) { // possibly in <...>
  1296. if (($kwlist = trim($regs[1])) != '') {
  1297. $kw = '<i kw="'.htmlspecialchars($kwlist).'">';
  1298. } else {
  1299. $kw = '';
  1300. }
  1301. // i.e. assume only one of the $hide_fields will be present
  1302. // and if found, hide the value as expando property of an <i> tag
  1303. } elseif (trim($value)) {
  1304. $d .= ', '.$key.':'.$value;
  1305. }
  1306. }
  1307. }
  1308. if (!empty($d)) {
  1309. $d = substr($d, 2).' - ';
  1310. }
  1311. return self::put_link(
  1312. $url,
  1313. $cat,
  1314. $title,
  1315. $kw.ereg_replace(
  1316. '\[((/?(b|big|i|small|sub|sup|u))|br/)\]',
  1317. '<\\1>',
  1318. htmlspecialchars($d.$linkdata['description'])
  1319. ).($kw ? '</i>' : ''),
  1320. $linkdata['on_homepage'] ? '1' : '0',
  1321. $linkdata['hidden'] ? '1' : '0'
  1322. );
  1323. // i.e. allow some BBcode tags, e.g. [b]...[/b]
  1324. }
  1325. /**
  1326. * This function checks if the url is a vimeo link
  1327. * @author Julio Montoya
  1328. * @version 1.0
  1329. */
  1330. public static function isVimeoLink($url)
  1331. {
  1332. $isLink = strrpos($url, "vimeo.com");
  1333. return $isLink;
  1334. }
  1335. /**
  1336. * Get vimeo id from URL
  1337. * @param string $url
  1338. * @return bool|mixed
  1339. */
  1340. public static function getVimeoLinkId($url)
  1341. {
  1342. $possibleUrls = array(
  1343. 'http://www.vimeo.com/',
  1344. 'http://vimeo.com/',
  1345. 'https://www.vimeo.com/',
  1346. 'https://vimeo.com/'
  1347. );
  1348. $url = str_replace($possibleUrls, '', $url);
  1349. if (is_numeric($url)) {
  1350. return $url;
  1351. }
  1352. return false;
  1353. }
  1354. /**
  1355. * This function checks if the url is a youtube link
  1356. * @author Jorge Frisancho
  1357. * @author Julio Montoya - Fixing code
  1358. * @version 1.0
  1359. */
  1360. public static function is_youtube_link($url)
  1361. {
  1362. $is_youtube_link = strrpos($url, "youtube") || strrpos(
  1363. $url,
  1364. "youtu.be"
  1365. );
  1366. return $is_youtube_link;
  1367. }
  1368. /**
  1369. * Get youtube id from an URL
  1370. * @param string $url
  1371. * @return string
  1372. */
  1373. public static function get_youtube_video_id($url)
  1374. {
  1375. // This is the length of YouTube's video IDs
  1376. $len = 11;
  1377. // The ID string starts after "v=", which is usually right after
  1378. // "youtube.com/watch?" in the URL
  1379. $pos = strpos($url, "v=");
  1380. $id = '';
  1381. //If false try other options
  1382. if ($pos === false) {
  1383. $url_parsed = parse_url($url);
  1384. //Youtube shortener
  1385. //http://youtu.be/ID
  1386. $pos = strpos($url, "youtu.be");
  1387. if ($pos == false) {
  1388. $id = '';
  1389. } else {
  1390. return substr($url_parsed['path'], 1);
  1391. }
  1392. //if empty try the youtube.com/embed/ID
  1393. if (empty($id)) {
  1394. $pos = strpos($url, "embed");
  1395. if ($pos === false) {
  1396. return '';
  1397. } else {
  1398. return substr($url_parsed['path'], 7);
  1399. }
  1400. }
  1401. } else {
  1402. // Offset the start location to match the beginning of the ID string
  1403. $pos += 2;
  1404. // Get the ID string and return it
  1405. $id = substr($url, $pos, $len);
  1406. return $id;
  1407. }
  1408. }
  1409. /**
  1410. * @param int $course_id
  1411. * @param int $session_id
  1412. * @param int $categoryId
  1413. * @param string $show
  1414. * @param null $token
  1415. */
  1416. public static function listLinksAndCategories($course_id, $session_id, $categoryId, $show = 'none', $token = null)
  1417. {
  1418. $tbl_link = Database::get_course_table(TABLE_LINK);
  1419. $tblCIP = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1420. $categoryId = intval($categoryId);
  1421. /* Action Links */
  1422. echo '<div class="actions">';
  1423. if (api_is_allowed_to_edit(null, true)) {
  1424. echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=addlink&category_id='.$categoryId.'">'.
  1425. Display::return_icon('new_link.png', get_lang('LinkAdd'), '', ICON_SIZE_MEDIUM).'</a>';
  1426. echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=addcategory&category_id='.$categoryId.'">'.
  1427. Display::return_icon('new_folder.png', get_lang('CategoryAdd'), '', ICON_SIZE_MEDIUM).'</a>';
  1428. }
  1429. $categories = self::getLinkCategories($course_id, $session_id);
  1430. $countCategories = count($categories);
  1431. if (!empty($countCategories)) {
  1432. echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=none">';
  1433. echo Display::return_icon('forum_listview.png', get_lang('FlatView'), '', ICON_SIZE_MEDIUM).' </a>';
  1434. echo '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=list&show=all">';
  1435. echo Display::return_icon('forum_nestedview.png', get_lang('NestedView'), '', ICON_SIZE_MEDIUM).'</a>';
  1436. }
  1437. echo '</div>';
  1438. // Displaying the links which have no category (thus category = 0 or NULL),
  1439. // if none present this will not be displayed
  1440. $sql = "
  1441. SELECT COUNT(1) AS count FROM $tbl_link l
  1442. INNER JOIN $tblCIP c
  1443. ON (l.c_id = c.c_id AND l.iid = c.ref)
  1444. WHERE
  1445. c.tool = 'link' AND
  1446. c.visibility != 2 AND
  1447. l.c_id = $course_id AND
  1448. (l.category_id = 0 OR l.category_id IS NULL)
  1449. ";
  1450. $result = Database::query($sql);
  1451. $count = Database::result($result, 0, 'count');
  1452. $linksPerCategory = self::showLinksPerCategory(0, $course_id, $session_id);
  1453. if ($count && !$countCategories) {
  1454. echo $linksPerCategory;
  1455. } elseif ($count && $countCategories) {
  1456. echo Display::panel($linksPerCategory, get_lang('NoCategory'));
  1457. }
  1458. $counter = 0;
  1459. foreach ($categories as $myrow) {
  1460. // Student don't see invisible categories.
  1461. if (!api_is_allowed_to_edit(null, true)) {
  1462. if ($myrow['visibility'] == 0) {
  1463. continue;
  1464. }
  1465. }
  1466. // Validation when belongs to a session
  1467. $showChildren = $categoryId == $myrow['id'] || $show == 'all';
  1468. $myrow['description'] = $myrow['description'];
  1469. $strVisibility = '';
  1470. $visibilityClass = null;
  1471. if ($myrow['visibility'] == '1') {
  1472. $strVisibility = '<a href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=invisible&id='.$myrow['id'].'&scope='.TOOL_LINK_CATEGORY.'" title="'.get_lang('Hide').'">'.
  1473. Display::return_icon('visible.png', get_lang('Hide'), array(), ICON_SIZE_SMALL).'</a>';
  1474. } elseif ($myrow['visibility'] == '0') {
  1475. $visibilityClass = 'text-muted';
  1476. $strVisibility = ' <a href="link.php?'.api_get_cidreq().'&sec_token='.$token.'&action=visible&id='.$myrow['id'].'&scope='.TOOL_LINK_CATEGORY.'" title="'.get_lang('Show').'">'.
  1477. Display::return_icon('invisible.png', get_lang('Show'), array(), ICON_SIZE_SMALL).'</a>';
  1478. }
  1479. $header = '';
  1480. if ($showChildren) {
  1481. $header .= '<a class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id=">';
  1482. $header .= Display::return_icon('forum_nestedview.png');
  1483. } else {
  1484. $header .= '<a class="'.$visibilityClass.'" href="'.api_get_self().'?'.api_get_cidreq().'&category_id='.$myrow['id'].'">';
  1485. $header .= Display::return_icon('forum_listview.png');
  1486. }
  1487. $header .= Security::remove_XSS($myrow['category_title']).'</a>';
  1488. $header .= '<div class="pull-right">';
  1489. if (api_is_allowed_to_edit(null, true)) {
  1490. if ($session_id == $myrow['session_id']) {
  1491. $header .= $strVisibility;
  1492. $header .= self::showCategoryAdminTools($myrow, $counter, count($categories));
  1493. } else {
  1494. $header .= get_lang('EditionNotAvailableFromSession');
  1495. }
  1496. }
  1497. $childrenContent = '';
  1498. if ($showChildren) {
  1499. $childrenContent = self::showLinksPerCategory(
  1500. $myrow['id'],
  1501. api_get_course_int_id(),
  1502. api_get_session_id()
  1503. );
  1504. }
  1505. echo Display::panel($myrow['description'].$childrenContent, $header);
  1506. $counter++;
  1507. }
  1508. }
  1509. /**
  1510. * @param int $linkId
  1511. * @param $action
  1512. * @param null $token
  1513. *
  1514. * @return FormValidator
  1515. */
  1516. public static function getLinkForm($linkId, $action, $token = null)
  1517. {
  1518. $course_id = api_get_course_int_id();
  1519. $session_id = api_get_session_id();
  1520. $linkInfo = self::get_link_info($linkId);
  1521. $categoryId = isset($linkInfo['category_id']) ? $linkInfo['category_id'] : '';
  1522. $lpId = isset($_GET['lp_id']) ? Security::remove_XSS($_GET['lp_id']) : null;
  1523. $form = new FormValidator(
  1524. 'link',
  1525. 'post',
  1526. api_get_self().'?action='.$action.
  1527. '&category_id='.$categoryId.
  1528. '&'.api_get_cidreq().
  1529. '&id='.$linkId.
  1530. '&sec_token='.$token
  1531. );
  1532. if ($action == 'addlink') {
  1533. $form->addHeader(get_lang('LinkAdd'));
  1534. } else {
  1535. $form->addHeader(get_lang('LinkMod'));
  1536. }
  1537. $target_link = '_blank';
  1538. $title = '';
  1539. $category = '';
  1540. $onhomepage = '';
  1541. $description = '';
  1542. if (!empty($linkInfo)) {
  1543. $urllink = $linkInfo['url'];
  1544. $title = $linkInfo['title'];
  1545. $description = $linkInfo['description'];
  1546. $category = $linkInfo['category_id'];
  1547. if ($linkInfo['on_homepage'] != 0) {
  1548. $onhomepage = 1;
  1549. }
  1550. $target_link = $linkInfo['target'];
  1551. }
  1552. $form->addHidden('id', $linkId);
  1553. $form->addText('url', 'URL');
  1554. $form->addRule('url', get_lang('GiveURL'), 'url');
  1555. $form->addText('title', get_lang('LinkName'));
  1556. $form->addTextarea('description', get_lang('Description'));
  1557. $resultcategories = self::getLinkCategories($course_id, $session_id);
  1558. $options = ['0' => '--'];
  1559. if (!empty($resultcategories)) {
  1560. foreach ($resultcategories as $myrow) {
  1561. $options[$myrow['id']] = $myrow['category_title'];
  1562. }
  1563. }
  1564. $form->addSelect('category_id', get_lang('Category'), $options);
  1565. $form->addCheckBox('on_homepage', null, get_lang('OnHomepage'));
  1566. $targets = array(
  1567. '_self' => get_lang('LinkOpenSelf'),
  1568. '_blank' => get_lang('LinkOpenBlank'),
  1569. '_parent' => get_lang('LinkOpenParent'),
  1570. '_top' => get_lang('LinkOpenTop')
  1571. );
  1572. $form->addSelect(
  1573. 'target',
  1574. array(
  1575. get_lang('LinkTarget'),
  1576. get_lang('AddTargetOfLinkOnHomepage')
  1577. ),
  1578. $targets
  1579. );
  1580. $defaults = array(
  1581. 'url' => empty($urllink) ? 'http://' : Security::remove_XSS($urllink),
  1582. 'title' => Security::remove_XSS($title),
  1583. 'category_id' => $category,
  1584. 'on_homepage' => $onhomepage,
  1585. 'description' => $description,
  1586. 'target' => $target_link
  1587. );
  1588. if (api_get_setting('search_enabled') == 'true') {
  1589. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  1590. $specific_fields = get_specific_field_list();
  1591. $form->addCheckBox('index_document', get_lang('SearchFeatureDoIndexLink'), get_lang('Yes'));
  1592. foreach ($specific_fields as $specific_field) {
  1593. $default_values = '';
  1594. if ($action == 'editlink') {
  1595. $filter = array(
  1596. 'field_id' => $specific_field['id'],
  1597. 'ref_id' => intval($_GET['id']),
  1598. 'tool_id' => '\''.TOOL_LINK.'\''
  1599. );
  1600. $values = get_specific_field_values_list($filter, array('value'));
  1601. if (!empty($values)) {
  1602. $arr_str_values = array();
  1603. foreach ($values as $value) {
  1604. $arr_str_values[] = $value['value'];
  1605. }
  1606. $default_values = implode(', ', $arr_str_values);
  1607. }
  1608. }
  1609. $form->addText($specific_field['name'], $specific_field['code']);
  1610. $defaults[$specific_field['name']] = $default_values;
  1611. }
  1612. }
  1613. $form->addHidden('lp_id', $lpId);
  1614. $form->addButtonSave(get_lang('SaveLink'), 'submitLink');
  1615. $form->setDefaults($defaults);
  1616. return $form;
  1617. }
  1618. /**
  1619. * @param int $id
  1620. * @param string $action
  1621. *
  1622. * @return FormValidator
  1623. */
  1624. public static function getCategoryForm($id, $action)
  1625. {
  1626. $form = new FormValidator(
  1627. 'category',
  1628. 'post',
  1629. api_get_self().'?action='.$action.'&'.api_get_cidreq()
  1630. );
  1631. $defaults = [];
  1632. if ($action == 'addcategory') {
  1633. $form->addHeader(get_lang('CategoryAdd'));
  1634. $my_cat_title = get_lang('CategoryAdd');
  1635. } else {
  1636. $form->addHeader(get_lang('CategoryMod'));
  1637. $my_cat_title = get_lang('CategoryMod');
  1638. $defaults = self::getCategory($id);
  1639. }
  1640. $form->addHidden('id', $id);
  1641. $form->addText('category_title', get_lang('CategoryName'));
  1642. $form->addTextarea('description', get_lang('Description'));
  1643. $form->addButtonSave($my_cat_title, 'submitCategory');
  1644. $form->setDefaults($defaults);
  1645. return $form;
  1646. }
  1647. /**
  1648. * @param int $id
  1649. * @return array
  1650. */
  1651. public static function getCategory($id)
  1652. {
  1653. $table = Database::get_course_table(TABLE_LINK_CATEGORY);
  1654. $id = intval($id);
  1655. $courseId = api_get_course_int_id();
  1656. if (empty($id) || empty($courseId)) {
  1657. return [];
  1658. }
  1659. $sql = "SELECT * FROM $table
  1660. WHERE id = $id AND c_id = $courseId";
  1661. $result = Database::query($sql);
  1662. $category = Database::fetch_array($result, 'ASSOC');
  1663. return $category;
  1664. }
  1665. /**
  1666. * Move a link inside its category (display_order field)
  1667. * @param int $id The link ID
  1668. * @param string $direction The direction to sort the links
  1669. * @return bool
  1670. */
  1671. private static function moveLinkDisplayOrder($id, $direction)
  1672. {
  1673. $em = Database::getManager();
  1674. /** @var CLink $link */
  1675. $link = $em->find('ChamiloCourseBundle:CLink', $id);
  1676. if (!$link) {
  1677. return false;
  1678. }
  1679. $compareLinks = $em
  1680. ->getRepository('ChamiloCourseBundle:CLink')
  1681. ->findBy(
  1682. [
  1683. 'cId' => $link->getCId(),
  1684. 'categoryId' => $link->getCategoryId()
  1685. ],
  1686. ['displayOrder' => $direction]
  1687. );
  1688. /** @var CLink $prevLink */
  1689. $prevLink = null;
  1690. /** @var CLink $compareLink */
  1691. foreach ($compareLinks as $compareLink) {
  1692. if ($compareLink->getId() !== $link->getId()) {
  1693. $prevLink = $compareLink;
  1694. continue;
  1695. }
  1696. if (!$prevLink) {
  1697. return false;
  1698. }
  1699. $newPrevLinkDisplayOrder = $link->getDisplayOrder();
  1700. $newLinkDisplayOrder = $prevLink->getDisplayOrder();
  1701. $link->setDisplayOrder($newLinkDisplayOrder);
  1702. $prevLink->setDisplayOrder($newPrevLinkDisplayOrder);
  1703. $em->merge($prevLink);
  1704. $em->merge($link);
  1705. break;
  1706. }
  1707. $em->flush();
  1708. return true;
  1709. }
  1710. /**
  1711. * Move a link up in its category
  1712. * @param int $id
  1713. * @return bool
  1714. */
  1715. public static function moveLinkUp($id)
  1716. {
  1717. return self::moveLinkDisplayOrder($id, 'ASC');
  1718. }
  1719. /**
  1720. * Move a link down in its category
  1721. * @param int $id
  1722. * @return bool
  1723. */
  1724. public static function moveLinkDown($id)
  1725. {
  1726. return self::moveLinkDisplayOrder($id, 'DESC');
  1727. }
  1728. }