add_course.lib.inc.php 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CoreBundle\Framework\Container;
  4. use Chamilo\CourseBundle\Entity\CToolIntro;
  5. /**
  6. * Class AddCourse.
  7. */
  8. class AddCourse
  9. {
  10. public const FIRST_EXPIRATION_DATE = 31536000; // 365 days in seconds
  11. /**
  12. * Defines the four needed keys to create a course based on several parameters.
  13. *
  14. * @param string The code you want for this course
  15. * @param string Prefix added for ALL keys
  16. * @param string Prefix added for databases only
  17. * @param string Prefix added for paths only
  18. * @param bool Add unique prefix
  19. * @param bool Use code-independent keys
  20. *
  21. * @return array An array with the needed keys ['currentCourseCode'], ['currentCourseId'], ['currentCourseDbName'],
  22. * ['currentCourseRepository']
  23. *
  24. * @todo Eliminate the global variables.
  25. * @assert (null) === false
  26. */
  27. public static function define_course_keys(
  28. $wanted_code,
  29. $prefix_for_all = '',
  30. $prefix_for_base_name = '',
  31. $prefix_for_path = '',
  32. $add_unique_prefix = false,
  33. $use_code_indepedent_keys = true
  34. ) {
  35. $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
  36. $wanted_code = CourseManager::generate_course_code($wanted_code);
  37. $keys_course_code = $wanted_code;
  38. if (!$use_code_indepedent_keys) {
  39. $wanted_code = '';
  40. }
  41. if ($add_unique_prefix) {
  42. $unique_prefix = substr(md5(uniqid(rand())), 0, 10);
  43. } else {
  44. $unique_prefix = '';
  45. }
  46. $keys = [];
  47. $final_suffix = ['CourseId' => '', 'CourseDb' => '', 'CourseDir' => ''];
  48. $limit_numb_try = 100;
  49. $keys_are_unique = false;
  50. $try_new_fsc_id = $try_new_fsc_db = $try_new_fsc_dir = 0;
  51. while (!$keys_are_unique) {
  52. $keys_course_id = $prefix_for_all.$unique_prefix.$wanted_code.$final_suffix['CourseId'];
  53. $keys_course_repository = $prefix_for_path.$unique_prefix.$wanted_code.$final_suffix['CourseDir'];
  54. $keys_are_unique = true;
  55. // Check whether they are unique.
  56. $query = "SELECT 1 FROM $course_table
  57. WHERE code='".$keys_course_id."'
  58. LIMIT 0, 1";
  59. $result = Database::query($query);
  60. if (Database::num_rows($result)) {
  61. $keys_are_unique = false;
  62. $try_new_fsc_id++;
  63. $final_suffix['CourseId'] = substr(md5(uniqid(rand())), 0, 4);
  64. }
  65. if (file_exists(api_get_path(SYS_COURSE_PATH).$keys_course_repository)) {
  66. $keys_are_unique = false;
  67. $try_new_fsc_dir++;
  68. $final_suffix['CourseDir'] = substr(md5(uniqid(rand())), 0, 4);
  69. }
  70. if (($try_new_fsc_id + $try_new_fsc_db + $try_new_fsc_dir) > $limit_numb_try) {
  71. return $keys;
  72. }
  73. }
  74. $keys['currentCourseCode'] = $keys_course_code;
  75. $keys['currentCourseId'] = $keys_course_id;
  76. $keys['currentCourseRepository'] = $keys_course_repository;
  77. return $keys;
  78. }
  79. /**
  80. * Initializes a file repository for a newly created course.
  81. *
  82. * @param string Course repository
  83. * @param string Course code
  84. *
  85. * @return int
  86. * @assert (null,null) === false
  87. */
  88. public static function prepare_course_repository($course_repository)
  89. {
  90. return true;
  91. $perm = api_get_permissions_for_new_directories();
  92. $perm_file = api_get_permissions_for_new_files();
  93. $htmlpage = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>Not authorized</title>\n </head>\n <body>\n </body>\n</html>";
  94. $cp = api_get_path(SYS_COURSE_PATH).$course_repository;
  95. //Creating document folder
  96. mkdir($cp, $perm);
  97. mkdir($cp.'/document', $perm);
  98. $cpt = $cp.'/document/index.html';
  99. $fd = fopen($cpt, 'w');
  100. fwrite($fd, $htmlpage);
  101. fclose($fd);
  102. /*
  103. @chmod($cpt, $perm_file);
  104. @copy($cpt, $cp . '/document/index.html');
  105. mkdir($cp . '/document/images', $perm);
  106. @copy($cpt, $cp . '/document/images/index.html');
  107. mkdir($cp . '/document/images/gallery/', $perm);
  108. @copy($cpt, $cp . '/document/images/gallery/index.html');
  109. mkdir($cp . '/document/shared_folder/', $perm);
  110. @copy($cpt, $cp . '/document/shared_folder/index.html');
  111. mkdir($cp . '/document/audio', $perm);
  112. @copy($cpt, $cp . '/document/audio/index.html');
  113. mkdir($cp . '/document/flash', $perm);
  114. @copy($cpt, $cp . '/document/flash/index.html');
  115. mkdir($cp . '/document/video', $perm);
  116. @copy($cpt, $cp . '/document/video/index.html'); */
  117. //Creatind dropbox folder
  118. mkdir($cp.'/dropbox', $perm);
  119. $cpt = $cp.'/dropbox/index.html';
  120. $fd = fopen($cpt, 'w');
  121. fwrite($fd, $htmlpage);
  122. fclose($fd);
  123. @chmod($cpt, $perm_file);
  124. mkdir($cp.'/group', $perm);
  125. @copy($cpt, $cp.'/group/index.html');
  126. mkdir($cp.'/page', $perm);
  127. @copy($cpt, $cp.'/page/index.html');
  128. mkdir($cp.'/scorm', $perm);
  129. @copy($cpt, $cp.'/scorm/index.html');
  130. mkdir($cp.'/upload', $perm);
  131. @copy($cpt, $cp.'/upload/index.html');
  132. mkdir($cp.'/upload/forum', $perm);
  133. @copy($cpt, $cp.'/upload/forum/index.html');
  134. mkdir($cp.'/upload/forum/images', $perm);
  135. @copy($cpt, $cp.'/upload/forum/images/index.html');
  136. mkdir($cp.'/upload/test', $perm);
  137. @copy($cpt, $cp.'/upload/test/index.html');
  138. mkdir($cp.'/upload/blog', $perm);
  139. @copy($cpt, $cp.'/upload/blog/index.html');
  140. mkdir($cp.'/upload/learning_path', $perm);
  141. @copy($cpt, $cp.'/upload/learning_path/index.html');
  142. mkdir($cp.'/upload/learning_path/images', $perm);
  143. @copy($cpt, $cp.'/upload/learning_path/images/index.html');
  144. mkdir($cp.'/upload/calendar', $perm);
  145. @copy($cpt, $cp.'/upload/calendar/index.html');
  146. mkdir($cp.'/upload/calendar/images', $perm);
  147. @copy($cpt, $cp.'/upload/calendar/images/index.html');
  148. mkdir($cp.'/work', $perm);
  149. @copy($cpt, $cp.'/work/index.html');
  150. mkdir($cp.'/upload/announcements', $perm);
  151. @copy($cpt, $cp.'/upload/announcements/index.html');
  152. mkdir($cp.'/upload/announcements/images', $perm);
  153. @copy($cpt, $cp.'/upload/announcements/images/index.html');
  154. //Oral expression question type
  155. mkdir($cp.'/exercises', $perm);
  156. @copy($cpt, $cp.'/exercises/index.html');
  157. // Create .htaccess in the dropbox directory.
  158. $fp = fopen($cp.'/dropbox/.htaccess', 'w');
  159. fwrite(
  160. $fp,
  161. "AuthName AllowLocalAccess
  162. AuthType Basic
  163. order deny,allow
  164. deny from all
  165. php_flag zlib.output_compression off"
  166. );
  167. fclose($fp);
  168. // Build index.php of the course.
  169. /*$fd = fopen($cp . '/index.php', 'w');
  170. // str_replace() removes \r that cause squares to appear at the end of each line
  171. //@todo fix the harcoded include
  172. $string = str_replace(
  173. "\r",
  174. "",
  175. "<?" . "php
  176. \$cidReq = \"$course_code\";
  177. \$dbname = \"$course_code\";
  178. include(\"" . api_get_path(SYS_CODE_PATH) . "course_home/course_home.php\");
  179. ?>"
  180. );
  181. fwrite($fd, $string);
  182. @chmod($cp . '/index.php', $perm_file);*/
  183. return 0;
  184. }
  185. /**
  186. * Gets an array with all the course tables (deprecated?).
  187. *
  188. * @return array
  189. *
  190. * @assert (null) !== null
  191. */
  192. public static function get_course_tables()
  193. {
  194. $tables = [];
  195. $tables[] = 'item_property';
  196. $tables[] = 'tool';
  197. $tables[] = 'tool_intro';
  198. $tables[] = 'group_info';
  199. $tables[] = 'group_category';
  200. $tables[] = 'group_rel_user';
  201. $tables[] = 'group_rel_tutor';
  202. $tables[] = 'userinfo_content';
  203. $tables[] = 'userinfo_def';
  204. $tables[] = 'course_description';
  205. $tables[] = 'calendar_event';
  206. $tables[] = 'calendar_event_repeat';
  207. $tables[] = 'calendar_event_repeat_not';
  208. $tables[] = 'calendar_event_attachment';
  209. $tables[] = 'announcement';
  210. $tables[] = 'announcement_attachment';
  211. //$tables[] = 'resource';
  212. $tables[] = 'student_publication';
  213. $tables[] = 'student_publication_assignment';
  214. $tables[] = 'document';
  215. $tables[] = 'forum_category';
  216. $tables[] = 'forum_forum';
  217. $tables[] = 'forum_thread';
  218. $tables[] = 'forum_post';
  219. $tables[] = 'forum_mailcue';
  220. $tables[] = 'forum_attachment';
  221. $tables[] = 'forum_notification';
  222. $tables[] = 'forum_thread_qualify';
  223. $tables[] = 'forum_thread_qualify_log';
  224. $tables[] = 'link';
  225. $tables[] = 'link_category';
  226. $tables[] = 'online_connected';
  227. $tables[] = 'online_link';
  228. $tables[] = 'chat_connected';
  229. $tables[] = 'quiz';
  230. $tables[] = 'quiz_rel_question';
  231. $tables[] = 'quiz_question';
  232. $tables[] = 'quiz_answer';
  233. $tables[] = 'quiz_question_option';
  234. $tables[] = 'quiz_question_category';
  235. $tables[] = 'quiz_question_rel_category';
  236. $tables[] = 'dropbox_post';
  237. $tables[] = 'dropbox_file';
  238. $tables[] = 'dropbox_person';
  239. $tables[] = 'dropbox_category';
  240. $tables[] = 'dropbox_feedback';
  241. $tables[] = 'lp';
  242. $tables[] = 'lp_item';
  243. $tables[] = 'lp_view';
  244. $tables[] = 'lp_item_view';
  245. $tables[] = 'lp_iv_interaction';
  246. $tables[] = 'lp_iv_objective';
  247. $tables[] = 'blog';
  248. $tables[] = 'blog_comment';
  249. $tables[] = 'blog_post';
  250. $tables[] = 'blog_rating';
  251. $tables[] = 'blog_rel_user';
  252. $tables[] = 'blog_task';
  253. $tables[] = 'blog_task_rel_user';
  254. $tables[] = 'blog_attachment';
  255. $tables[] = 'permission_group';
  256. $tables[] = 'permission_user';
  257. $tables[] = 'permission_task';
  258. $tables[] = 'role';
  259. $tables[] = 'role_group';
  260. $tables[] = 'role_permissions';
  261. $tables[] = 'role_user';
  262. $tables[] = 'survey';
  263. $tables[] = 'survey_question';
  264. $tables[] = 'survey_question_option';
  265. $tables[] = 'survey_invitation';
  266. $tables[] = 'survey_answer';
  267. $tables[] = 'survey_group';
  268. $tables[] = 'wiki';
  269. $tables[] = 'wiki_conf';
  270. $tables[] = 'wiki_discuss';
  271. $tables[] = 'wiki_mailcue';
  272. $tables[] = 'course_setting';
  273. $tables[] = 'glossary';
  274. $tables[] = 'notebook';
  275. $tables[] = 'attendance';
  276. $tables[] = 'attendance_sheet';
  277. $tables[] = 'attendance_calendar';
  278. $tables[] = 'attendance_result';
  279. $tables[] = 'attendance_sheet_log';
  280. $tables[] = 'thematic';
  281. $tables[] = 'thematic_plan';
  282. $tables[] = 'thematic_advance';
  283. return $tables;
  284. }
  285. /**
  286. * Executed only before create_course_tables().
  287. *
  288. * @assert (null) === null
  289. */
  290. public static function drop_course_tables()
  291. {
  292. $list = self::get_course_tables();
  293. foreach ($list as $table) {
  294. $sql = "DROP TABLE IF EXISTS ".DB_COURSE_PREFIX.$table;
  295. Database::query($sql);
  296. }
  297. }
  298. /**
  299. * Sorts pictures by type (used?).
  300. *
  301. * @param array List of files (sthg like array(0=>array('png'=>1)))
  302. * @param string $type
  303. *
  304. * @return array The received array without files not matching type
  305. * @assert (array(),null) === array()
  306. */
  307. public static function sort_pictures($files, $type)
  308. {
  309. $pictures = [];
  310. foreach ($files as $value) {
  311. if (isset($value[$type]) && $value[$type] != '') {
  312. $pictures[][$type] = $value[$type];
  313. }
  314. }
  315. return $pictures;
  316. }
  317. /**
  318. * Fills the course database with some required content and example content.
  319. *
  320. * @param array $courseInfo
  321. * @param bool Whether to fill the course with example content
  322. * @param int $authorId
  323. *
  324. * @return bool False on error, true otherwise
  325. *
  326. * @version 1.2
  327. * @assert (null, '', '', null) === false
  328. * @assert (1, 'ABC', null, null) === false
  329. * @assert (1, 'TEST', 'spanish', true) === true
  330. */
  331. public static function fillCourse(
  332. $courseInfo,
  333. $fill_with_exemplary_content = null,
  334. $authorId = 0
  335. ) {
  336. if (is_null($fill_with_exemplary_content)) {
  337. $fill_with_exemplary_content = api_get_setting('example_material_course_creation') !== 'false';
  338. }
  339. $course_id = (int) $courseInfo['real_id'];
  340. if (empty($courseInfo)) {
  341. return false;
  342. }
  343. $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
  344. $TABLEGROUPCATEGORIES = Database::get_course_table(TABLE_GROUP_CATEGORY);
  345. $TABLESETTING = Database::get_course_table(TABLE_COURSE_SETTING);
  346. $TABLEGRADEBOOK = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  347. $TABLEGRADEBOOKLINK = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
  348. $visible_for_course_admin = 0;
  349. $em = Database::getManager();
  350. $course = api_get_course_entity($course_id);
  351. $settingsManager = CourseManager::getCourseSettingsManager();
  352. $settingsManager->setCourse($course);
  353. $alert = api_get_setting('email_alert_manager_on_new_quiz');
  354. $defaultEmailExerciseAlert = 0;
  355. if ($alert === 'true') {
  356. $defaultEmailExerciseAlert = 1;
  357. }
  358. /* course_setting table (courseinfo tool) */
  359. $settings = [
  360. 'email_alert_manager_on_new_doc' => ['title' => '', 'default' => 0, 'category' => 'work'],
  361. 'email_alert_on_new_doc_dropbox' => ['default' => 0, 'category' => 'dropbox'],
  362. 'allow_user_edit_agenda' => ['default' => 0, 'category' => 'agenda'],
  363. 'allow_user_edit_announcement' => ['default' => 0, 'category' => 'announcement'],
  364. 'email_alert_manager_on_new_quiz' => ['default' => $defaultEmailExerciseAlert, 'category' => 'quiz'],
  365. 'allow_user_image_forum' => ['default' => 1, 'category' => 'forum'],
  366. 'course_theme' => ['default' => '', 'category' => 'theme'],
  367. 'allow_learning_path_theme' => ['default' => 1, 'category' => 'theme'],
  368. 'allow_open_chat_window' => ['default' => 1, 'category' => 'chat'],
  369. 'email_alert_to_teacher_on_new_user_in_course' => ['default' => 0, 'category' => 'registration'],
  370. 'allow_user_view_user_list' => ['default' => 1, 'category' => 'user'],
  371. 'display_info_advance_inside_homecourse' => ['default' => 1, 'category' => 'thematic_advance'],
  372. 'email_alert_students_on_new_homework' => ['default' => 0, 'category' => 'work'],
  373. 'enable_lp_auto_launch' => ['default' => 0, 'category' => 'learning_path'],
  374. 'enable_exercise_auto_launch' => ['default' => 0, 'category' => 'exercise'],
  375. 'enable_document_auto_launch' => ['default' => 0, 'category' => 'document'],
  376. 'pdf_export_watermark_text' => ['default' => '', 'category' => 'learning_path'],
  377. 'allow_public_certificates' => [
  378. 'default' => api_get_setting('allow_public_certificates') === 'true' ? 1 : '',
  379. 'category' => 'certificates',
  380. ],
  381. 'documents_default_visibility' => ['default' => 'visible', 'category' => 'document'],
  382. 'show_course_in_user_language' => ['default' => 2, 'category' => null],
  383. 'email_to_teachers_on_new_work_feedback' => ['default' => 1, 'category' => null],
  384. ];
  385. $counter = 1;
  386. foreach ($settings as $variable => $setting) {
  387. $title = $setting['title'] ?? '';
  388. Database::query(
  389. "INSERT INTO $TABLESETTING (id, c_id, title, variable, value, category)
  390. VALUES ($counter, $course_id, '".$title."', '".$variable."', '".$setting['default']."', '".$setting['category']."')"
  391. );
  392. $counter++;
  393. }
  394. /* Course homepage tools for platform admin only */
  395. /* Group tool */
  396. Database::insert(
  397. $TABLEGROUPCATEGORIES,
  398. [
  399. 'c_id' => $course_id,
  400. 'id' => 2,
  401. 'title' => get_lang('Default groups'),
  402. 'description' => '',
  403. 'max_student' => 0,
  404. 'self_reg_allowed' => 0,
  405. 'self_unreg_allowed' => 0,
  406. 'groups_per_user' => 0,
  407. 'display_order' => 0,
  408. 'doc_state' => 1,
  409. 'calendar_state' => 1,
  410. 'work_state' => 1,
  411. 'announcements_state' => 1,
  412. 'forum_state' => 1,
  413. 'wiki_state' => 1,
  414. 'chat_state' => 1,
  415. ]
  416. );
  417. $now = api_get_utc_datetime();
  418. $files = [
  419. ['path' => '/shared_folder', 'title' => get_lang('Folders of users'), 'filetype' => 'folder', 'size' => 0],
  420. ['path' => '/chat_files', 'title' => get_lang('Chat conversations history'), 'filetype' => 'folder', 'size' => 0],
  421. ['path' => '/certificates', 'title' => get_lang('Certificates'), 'filetype' => 'folder', 'size' => 0],
  422. ];
  423. $counter = 1;
  424. foreach ($files as $file) {
  425. self::insertDocument($courseInfo, $counter, $file, $authorId);
  426. $counter++;
  427. }
  428. $certificateId = 'NULL';
  429. /* Documents */
  430. if ($fill_with_exemplary_content) {
  431. $files = [
  432. ['path' => '/images', 'title' => get_lang('Images'), 'filetype' => 'folder', 'size' => 0],
  433. ['path' => '/images/gallery', 'title' => get_lang('Gallery'), 'filetype' => 'folder', 'size' => 0],
  434. ['path' => '/audio', 'title' => get_lang('Audio'), 'filetype' => 'folder', 'size' => 0],
  435. ['path' => '/flash', 'title' => get_lang('Flash'), 'filetype' => 'folder', 'size' => 0],
  436. ['path' => '/video', 'title' => get_lang('Video'), 'filetype' => 'folder', 'size' => 0],
  437. ];
  438. foreach ($files as $file) {
  439. self::insertDocument($courseInfo, $counter, $file, $authorId);
  440. $counter++;
  441. }
  442. $finder = new Symfony\Component\Finder\Finder();
  443. $defaultPath = api_get_path(SYS_PUBLIC_PATH).'img/document';
  444. $finder->in($defaultPath);
  445. /** @var SplFileInfo $file */
  446. foreach ($finder as $file) {
  447. $path = str_replace($defaultPath, '', $file->getRealPath());
  448. $parentName = dirname(str_replace($defaultPath, '', $file->getRealPath()));
  449. $title = $file->getFilename();
  450. if ($file->isDir()) {
  451. create_unexisting_directory(
  452. $courseInfo,
  453. api_get_user_id(),
  454. 0,
  455. 0,
  456. 0,
  457. $path,
  458. $path,
  459. $title
  460. );
  461. } else {
  462. $parent = DocumentManager::getDocumentByPathInCourse($courseInfo, $parentName);
  463. $parentId = 0;
  464. if (!empty($parent)) {
  465. $parent = $parent[0];
  466. $parentId = $parent['iid'];
  467. }
  468. $realPath = str_replace($defaultPath, '', $file->getRealPath());
  469. $document = DocumentManager::addDocument(
  470. $courseInfo,
  471. $realPath,
  472. 'file',
  473. $file->getSize(),
  474. $title,
  475. '',
  476. null,
  477. null,
  478. null,
  479. null,
  480. null,
  481. false,
  482. null,
  483. $parentId,
  484. $file->getRealPath()
  485. );
  486. if ($document && $document->getTitle() === 'default.html') {
  487. $certificateId = $document->getIid();
  488. }
  489. }
  490. }
  491. $agenda = new Agenda('course');
  492. $agenda->set_course($courseInfo);
  493. $agenda->addEvent(
  494. $now,
  495. $now,
  496. 0,
  497. get_lang('Course creation'),
  498. get_lang('This course was created at this time')
  499. );
  500. /* Links tool */
  501. $link = new Link();
  502. $link->setCourse($courseInfo);
  503. $links = [
  504. [
  505. 'c_id' => $course_id,
  506. 'url' => 'http://www.google.com',
  507. 'title' => 'Quick and powerful search engine',
  508. 'description' => get_lang('Quick and powerful search engine'),
  509. 'category_id' => 0,
  510. 'on_homepage' => 0,
  511. 'target' => '_self',
  512. 'session_id' => 0,
  513. ],
  514. [
  515. 'c_id' => $course_id,
  516. 'url' => 'http://www.wikipedia.org',
  517. 'title' => 'Free online encyclopedia',
  518. 'description' => get_lang('Free online encyclopedia'),
  519. 'category_id' => 0,
  520. 'on_homepage' => 0,
  521. 'target' => '_self',
  522. 'session_id' => 0,
  523. ],
  524. ];
  525. foreach ($links as $params) {
  526. $link->save($params);
  527. }
  528. /* Announcement tool */
  529. AnnouncementManager::add_announcement(
  530. $courseInfo,
  531. 0,
  532. get_lang('This is an announcement example'),
  533. get_lang('This is an announcement example. Only trainers are allowed to publish announcements.'),
  534. ['everyone' => 'everyone'],
  535. null,
  536. null,
  537. $now
  538. );
  539. $manager = Database::getManager();
  540. /* Introduction text */
  541. $intro_text = '<p style="text-align: center;">
  542. <img src="'.api_get_path(REL_CODE_PATH).'img/mascot.png" alt="Mr. Chamilo" title="Mr. Chamilo" />
  543. <h2>'.get_lang('Introduction text').'</h2>
  544. </p>';
  545. $toolIntro = new CToolIntro();
  546. $toolIntro
  547. ->setCId($course_id)
  548. ->setId(TOOL_COURSE_HOMEPAGE)
  549. ->setSessionId(0)
  550. ->setIntroText($intro_text);
  551. $manager->persist($toolIntro);
  552. $toolIntro = new CToolIntro();
  553. $toolIntro
  554. ->setCId($course_id)
  555. ->setId(TOOL_STUDENTPUBLICATION)
  556. ->setSessionId(0)
  557. ->setIntroText(get_lang('This page allows users and groups to publish documents.'));
  558. $manager->persist($toolIntro);
  559. $toolIntro = new CToolIntro();
  560. $toolIntro
  561. ->setCId($course_id)
  562. ->setId(TOOL_WIKI)
  563. ->setSessionId(0)
  564. ->setIntroText(get_lang('The word Wiki is short for WikiWikiWeb. Wikiwiki is a Hawaiian word, meaning "fast" or "speed". In a wiki, people write pages together. If one person writes something wrong, the next person can correct it. The next person can also add something new to the page. Because of this, the pages improve continuously.'));
  565. $manager->persist($toolIntro);
  566. $manager->flush();
  567. /* Exercise tool */
  568. $exercise = new Exercise($course_id);
  569. $exercise->exercise = get_lang('Sample test');
  570. $html = '<table width="100%" border="0" cellpadding="0" cellspacing="0">
  571. <tr>
  572. <td width="220" valign="top" align="left">
  573. <img src="'.api_get_path(WEB_PUBLIC_PATH).'img/document/images/mr_chamilo/doubts.png">
  574. </td>
  575. <td valign="top" align="left">'.get_lang('Irony').'</td></tr>
  576. </table>';
  577. $exercise->type = 1;
  578. $exercise->setRandom(0);
  579. $exercise->active = 1;
  580. $exercise->results_disabled = 0;
  581. $exercise->description = $html;
  582. $exercise->save();
  583. $exercise_id = $exercise->id;
  584. $question = new MultipleAnswer();
  585. $question->question = get_lang('Socratic irony is...');
  586. $question->description = get_lang('(more than one answer can be true)');
  587. $question->weighting = 10;
  588. $question->position = 1;
  589. $question->course = $courseInfo;
  590. $question->save($exercise);
  591. $questionId = $question->id;
  592. $answer = new Answer($questionId, $courseInfo['real_id']);
  593. $answer->createAnswer(get_lang('Ridiculise one\'s interlocutor in order to have him concede he is wrong.'), 0, get_lang('No. Socratic irony is not a matter of psychology, it concerns argumentation.'), -5, 1);
  594. $answer->createAnswer(get_lang('Admit one\'s own errors to invite one\'s interlocutor to do the same.'), 0, get_lang('No. Socratic irony is not a seduction strategy or a method based on the example.'), -5, 2);
  595. $answer->createAnswer(get_lang('Compell one\'s interlocutor, by a series of questions and sub-questions, to admit he doesn\'t know what he claims to know.'), 1, get_lang('Indeed'), 5, 3);
  596. $answer->createAnswer(get_lang('Use the Principle of Non Contradiction to force one\'s interlocutor into a dead end.'), 1, get_lang('This answer is not false. It is true that the revelation of the interlocutor\'s ignorance means showing the contradictory conclusions where lead his premisses.'), 5, 4);
  597. $answer->save();
  598. /* Forum tool */
  599. require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
  600. $params = [
  601. 'forum_category_title' => get_lang('Example Forum Category'),
  602. 'forum_category_comment' => '',
  603. ];
  604. $forumCategoryId = store_forumcategory($params, $courseInfo, false);
  605. $params = [
  606. 'forum_category' => $forumCategoryId,
  607. 'forum_title' => get_lang('Example Forum'),
  608. 'forum_comment' => '',
  609. 'default_view_type_group' => ['default_view_type' => 'flat'],
  610. ];
  611. $forumId = store_forum($params, $courseInfo, true);
  612. $forumInfo = get_forum_information($forumId, $courseInfo['real_id']);
  613. $params = [
  614. 'post_title' => get_lang('Example Thread'),
  615. 'forum_id' => $forumId,
  616. 'post_text' => get_lang('Example ThreadContent'),
  617. 'calification_notebook_title' => '',
  618. 'numeric_calification' => '',
  619. 'weight_calification' => '',
  620. 'forum_category' => $forumCategoryId,
  621. 'thread_peer_qualify' => 0,
  622. ];
  623. store_thread($forumInfo, $params, $courseInfo, false);
  624. /* Gradebook tool */
  625. $course_code = $courseInfo['code'];
  626. // father gradebook
  627. Database::query(
  628. "INSERT INTO $TABLEGRADEBOOK (name, locked, generate_certificates, description, user_id, c_id, parent_id, weight, visible, certif_min_score, session_id, document_id)
  629. VALUES ('$course_code','0',0,'',1,$course_id,0,100,0,75,NULL,$certificateId)"
  630. );
  631. $gbid = Database:: insert_id();
  632. Database::query(
  633. "INSERT INTO $TABLEGRADEBOOK (name, locked, generate_certificates, description, user_id, c_id, parent_id, weight, visible, certif_min_score, session_id, document_id)
  634. VALUES ('$course_code','0',0,'',1,$course_id,$gbid,100,1,75,NULL,$certificateId)"
  635. );
  636. $gbid = Database:: insert_id();
  637. Database::query(
  638. "INSERT INTO $TABLEGRADEBOOKLINK (type, ref_id, user_id, c_id, category_id, created_at, weight, visible, locked)
  639. VALUES (1,$exercise_id,1,$course_id,$gbid,'$now',100,1,0)"
  640. );
  641. }
  642. // Installing plugins in course
  643. $app_plugin = new AppPlugin();
  644. $app_plugin->install_course_plugins($course_id);
  645. return true;
  646. }
  647. /**
  648. * @param array $courseInfo
  649. * @param int $counter
  650. * @param array $file
  651. * @param int $authorId
  652. */
  653. public static function insertDocument($courseInfo, $counter, $file, $authorId = 0)
  654. {
  655. DocumentManager::addDocument(
  656. $courseInfo,
  657. $file['path'],
  658. $file['filetype'],
  659. $file['size'],
  660. $file['title'],
  661. null,
  662. 0,
  663. null,
  664. 0,
  665. 0,
  666. 0,
  667. false
  668. );
  669. }
  670. /**
  671. * string2binary converts the string "true" or "false" to the boolean true false (0 or 1)
  672. * This is used for the Chamilo Config Settings as these store true or false as string
  673. * and the api_get_setting('course_create_active_tools') should be 0 or 1 (used for
  674. * the visibility of the tool).
  675. *
  676. * @param string $variable
  677. *
  678. * @return bool
  679. *
  680. * @author Patrick Cool, patrick.cool@ugent.be
  681. * @assert ('true') === true
  682. * @assert ('false') === false
  683. */
  684. public static function string2binary($variable)
  685. {
  686. if ($variable == 'true') {
  687. return true;
  688. }
  689. if ($variable == 'false') {
  690. return false;
  691. }
  692. }
  693. /**
  694. * Function register_course to create a record in the course table of the main database.
  695. *
  696. * @param array $params Course details (see code for details).
  697. * @param int $accessUrlId Optional.
  698. *
  699. * @return int Created course ID
  700. *
  701. * @todo use an array called $params instead of lots of params
  702. * @assert (null) === false
  703. */
  704. public static function register_course($params, $accessUrlId = 1)
  705. {
  706. global $error_msg;
  707. $title = $params['title'];
  708. // Fix amp
  709. $title = str_replace('&amp;', '&', $title);
  710. $code = $params['code'];
  711. $visual_code = $params['visual_code'];
  712. $directory = $params['directory'];
  713. $tutor_name = isset($params['tutor_name']) ? $params['tutor_name'] : null;
  714. $category_code = isset($params['course_category']) ? $params['course_category'] : '';
  715. $course_language = isset($params['course_language']) && !empty($params['course_language']) ? $params['course_language'] : api_get_setting(
  716. 'platformLanguage'
  717. );
  718. $user_id = empty($params['user_id']) ? api_get_user_id() : intval($params['user_id']);
  719. $department_name = isset($params['department_name']) ? $params['department_name'] : null;
  720. $department_url = isset($params['department_url']) ? $params['department_url'] : null;
  721. $disk_quota = isset($params['disk_quota']) ? $params['disk_quota'] : null;
  722. if (!isset($params['visibility'])) {
  723. $default_course_visibility = api_get_setting(
  724. 'courses_default_creation_visibility'
  725. );
  726. if (isset($default_course_visibility)) {
  727. $visibility = $default_course_visibility;
  728. } else {
  729. $visibility = COURSE_VISIBILITY_OPEN_PLATFORM;
  730. }
  731. } else {
  732. $visibility = $params['visibility'];
  733. }
  734. $subscribe = isset($params['subscribe']) ? (int) $params['subscribe'] : $visibility == COURSE_VISIBILITY_OPEN_PLATFORM ? 1 : 0;
  735. $unsubscribe = isset($params['unsubscribe']) ? (int) $params['unsubscribe'] : 0;
  736. $expiration_date = isset($params['expiration_date']) ? $params['expiration_date'] : null;
  737. $teachers = isset($params['teachers']) ? $params['teachers'] : null;
  738. $status = isset($params['status']) ? $params['status'] : null;
  739. $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
  740. $ok_to_register_course = true;
  741. // Check whether all the needed parameters are present.
  742. if (empty($code)) {
  743. $error_msg[] = 'courseSysCode is missing';
  744. $ok_to_register_course = false;
  745. }
  746. if (empty($visual_code)) {
  747. $error_msg[] = 'courseScreenCode is missing';
  748. $ok_to_register_course = false;
  749. }
  750. if (empty($directory)) {
  751. $error_msg[] = 'courseRepository is missing';
  752. $ok_to_register_course = false;
  753. }
  754. if (empty($title)) {
  755. $error_msg[] = 'title is missing';
  756. $ok_to_register_course = false;
  757. }
  758. if (empty($expiration_date)) {
  759. $expiration_date = api_get_utc_datetime(
  760. time() + self::FIRST_EXPIRATION_DATE
  761. );
  762. } else {
  763. $expiration_date = api_get_utc_datetime($expiration_date);
  764. }
  765. if ($visibility < 0 || $visibility > 4) {
  766. $error_msg[] = 'visibility is invalid';
  767. $ok_to_register_course = false;
  768. }
  769. if (empty($disk_quota)) {
  770. $disk_quota = api_get_setting('default_document_quotum');
  771. }
  772. if (stripos($department_url, 'http://') === false && stripos(
  773. $department_url,
  774. 'https://'
  775. ) === false
  776. ) {
  777. $department_url = 'http://'.$department_url;
  778. }
  779. // just in case
  780. if ($department_url == 'http://') {
  781. $department_url = '';
  782. }
  783. $course_id = 0;
  784. if ($ok_to_register_course) {
  785. $repo = Container::getCourseRepository();
  786. $course = new \Chamilo\CoreBundle\Entity\Course();
  787. $urlId = 1;
  788. if (api_get_current_access_url_id() !== -1) {
  789. $urlId = api_get_current_access_url_id();
  790. }
  791. $url = api_get_url_entity($urlId);
  792. $course
  793. ->setCode($code)
  794. ->setDirectory($directory)
  795. ->setCourseLanguage($course_language)
  796. ->setTitle($title)
  797. ->setDescription(get_lang('Course Description'))
  798. ->setCategoryCode($category_code)
  799. ->setVisibility($visibility)
  800. ->setShowScore(1)
  801. ->setDiskQuota($disk_quota)
  802. ->setCreationDate(new \DateTime())
  803. ->setExpirationDate(new \DateTime($expiration_date))
  804. ->setDepartmentName($department_name)
  805. ->setDepartmentUrl($department_url)
  806. ->setSubscribe($subscribe)
  807. ->setUnsubscribe($unsubscribe)
  808. ->setVisualCode($visual_code)
  809. ->addUrl($url)
  810. ;
  811. $repo->getEntityManager()->persist($course);
  812. $repo->getEntityManager()->flush();
  813. $course_id = $course->getId();
  814. if ($course_id) {
  815. $repo->addResourceNode(
  816. $course,
  817. api_get_user_entity(api_get_user_id()),
  818. $url
  819. );
  820. $sort = api_max_sort_value('0', api_get_user_id());
  821. // Default true
  822. $addTeacher = isset($params['add_user_as_teacher']) ? $params['add_user_as_teacher'] : true;
  823. if ($addTeacher) {
  824. $i_course_sort = CourseManager::userCourseSort(
  825. $user_id,
  826. $code
  827. );
  828. if (!empty($user_id)) {
  829. $sql = "INSERT INTO ".$TABLECOURSUSER." SET
  830. c_id = '".$course_id."',
  831. user_id = '".intval($user_id)."',
  832. status = '1',
  833. is_tutor = '0',
  834. sort = '".($i_course_sort)."',
  835. relation_type = 0,
  836. user_course_cat = '0'";
  837. Database::query($sql);
  838. }
  839. }
  840. if (!empty($teachers)) {
  841. if (!is_array($teachers)) {
  842. $teachers = [$teachers];
  843. }
  844. foreach ($teachers as $key) {
  845. //just in case
  846. if ($key == $user_id) {
  847. continue;
  848. }
  849. if (empty($key)) {
  850. continue;
  851. }
  852. $sql = "INSERT INTO ".$TABLECOURSUSER." SET
  853. c_id = '".Database::escape_string($course_id)."',
  854. user_id = '".Database::escape_string($key)."',
  855. status = '1',
  856. is_tutor = '0',
  857. sort = '".($sort + 1)."',
  858. relation_type = 0,
  859. user_course_cat = '0'";
  860. Database::query($sql);
  861. }
  862. }
  863. // Adding the course to an URL.
  864. UrlManager::add_course_to_url($course_id, $accessUrlId);
  865. // Add event to the system log.
  866. $user_id = api_get_user_id();
  867. Event::addEvent(
  868. LOG_COURSE_CREATE,
  869. LOG_COURSE_CODE,
  870. $code,
  871. api_get_utc_datetime(),
  872. $user_id,
  873. $course_id
  874. );
  875. $send_mail_to_admin = api_get_setting('send_email_to_admin_when_create_course');
  876. // @todo Improve code to send to all current portal administrators.
  877. if ($send_mail_to_admin === 'true') {
  878. $siteName = api_get_setting('siteName');
  879. $recipient_email = api_get_setting('emailAdministrator');
  880. $recipient_name = api_get_person_name(
  881. api_get_setting('administratorName'),
  882. api_get_setting('administratorSurname')
  883. );
  884. $iname = api_get_setting('Institution');
  885. $subject = get_lang(
  886. 'NewCourseCreatedIn'
  887. ).' '.$siteName.' - '.$iname;
  888. $message = get_lang(
  889. 'Dear'
  890. ).' '.$recipient_name.",\n\n".get_lang(
  891. 'MessageOfNewCourseToAdmin'
  892. ).' '.$siteName.' - '.$iname."\n";
  893. $message .= get_lang('Course name').' '.$title."\n";
  894. $message .= get_lang(
  895. 'Category'
  896. ).' '.$category_code."\n";
  897. $message .= get_lang('Coach').' '.$tutor_name."\n";
  898. $message .= get_lang('Language').' '.$course_language;
  899. $userInfo = api_get_user_info($user_id);
  900. $additionalParameters = [
  901. 'smsType' => SmsPlugin::NEW_COURSE_BEEN_CREATED,
  902. 'userId' => $user_id,
  903. 'courseName' => $title,
  904. 'creatorUsername' => $userInfo['username'],
  905. ];
  906. api_mail_html(
  907. $recipient_name,
  908. $recipient_email,
  909. $subject,
  910. $message,
  911. $siteName,
  912. $recipient_email,
  913. null,
  914. null,
  915. null,
  916. $additionalParameters
  917. );
  918. }
  919. }
  920. }
  921. return $course_id;
  922. }
  923. /**
  924. * Generate a new id for c_tool table.
  925. *
  926. * @param int $courseId The course id
  927. *
  928. * @return int the new id
  929. */
  930. public static function generateToolId($courseId)
  931. {
  932. $newIdResultData = Database::select(
  933. 'id + 1 AS new_id',
  934. Database::get_course_table(TABLE_TOOL_LIST),
  935. [
  936. 'where' => ['c_id = ?' => intval($courseId)],
  937. 'order' => 'id',
  938. 'limit' => 1,
  939. ],
  940. 'first'
  941. );
  942. if ($newIdResultData === false) {
  943. return 1;
  944. }
  945. return $newIdResultData['new_id'] > 0 ? $newIdResultData['new_id'] : 1;
  946. }
  947. }