link.lib.php 68 KB

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