add_course.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CoreBundle\Entity\CourseCategory;
  4. use Chamilo\CoreBundle\Framework\Container;
  5. use Chamilo\CoreBundle\Repository\CourseCategoryRepository;
  6. /**
  7. * This script allows professors and administrative staff to create course sites.
  8. *
  9. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  10. * @author Roan Embrechts, refactoring
  11. *
  12. * @package chamilo.create_course
  13. * "Course validation" feature:
  14. *
  15. * @author Jose Manuel Abuin Mosquera <chema@cesga.es>, Centro de Supercomputacion de Galicia
  16. * "Course validation" feature, technical adaptation for Chamilo 1.8.8:
  17. * @author Ivan Tcholakov <ivantcholakov@gmail.com>
  18. */
  19. // Flag forcing the "current course" reset.
  20. $cidReset = true;
  21. require_once __DIR__.'/../inc/global.inc.php';
  22. // Check access rights.
  23. if (!api_is_allowed_to_create_course()) {
  24. api_not_allowed(true);
  25. exit;
  26. }
  27. // Section for the tabs.
  28. $this_section = SECTION_COURSES;
  29. $em = Database::getManager();
  30. /** @var CourseCategoryRepository $courseCategoriesRepo */
  31. $courseCategoriesRepo = $em->getRepository('ChamiloCoreBundle:CourseCategory');
  32. // Get all possible teachers.
  33. $accessUrlId = api_get_current_access_url_id();
  34. // "Course validation" feature. This value affects the way of a new course creation:
  35. // true - the new course is requested only and it is created after approval;
  36. // false - the new course is created immediately, after filling this form.
  37. $course_validation_feature = false;
  38. if (api_get_setting('course_validation') === 'true' &&
  39. !api_is_platform_admin()
  40. ) {
  41. $course_validation_feature = true;
  42. }
  43. $htmlHeadXtra[] = '<script>
  44. function setFocus(){
  45. $("#title").focus();
  46. }
  47. $(window).on("load", function () {
  48. setFocus();
  49. });
  50. </script>';
  51. $interbreadcrumb[] = [
  52. 'url' => api_get_path(WEB_PATH).'user_portal.php',
  53. 'name' => get_lang('My courses'),
  54. ];
  55. // Displaying the header.
  56. $tool_name = $course_validation_feature ? get_lang('Create a course request') : get_lang('Add a new course');
  57. $tpl = new Template($tool_name);
  58. // Build the form.
  59. $form = new FormValidator('add_course');
  60. // Form title
  61. $form->addElement('header', $tool_name);
  62. // Title
  63. $form->addText(
  64. 'title',
  65. [
  66. get_lang('Course Name'),
  67. get_lang('Write a short and striking course name, For example: Innovation Management'),
  68. ],
  69. true);
  70. $form->applyFilter('title', 'html_filter');
  71. $form->addButtonAdvancedSettings('advanced_params');
  72. $form->addElement(
  73. 'html',
  74. '<div id="advanced_params_options" style="display:none">'
  75. );
  76. // Picture
  77. $form->addFile(
  78. 'picture',
  79. [
  80. get_lang('Add a picture'),
  81. ],
  82. [
  83. 'id' => 'picture',
  84. 'class' => 'picture-form',
  85. 'crop_image' => true,
  86. ]
  87. );
  88. $allowed_picture_types = api_get_supported_image_extensions(false);
  89. $form->addRule(
  90. 'picture',
  91. get_lang('Only PNG, JPG or GIF images allowed').' ('.implode(',', $allowed_picture_types).')',
  92. 'filetype',
  93. $allowed_picture_types
  94. );
  95. $countCategories = $courseCategoriesRepo->countAllInAccessUrl(
  96. $accessUrlId,
  97. api_get_configuration_value('allow_base_course_category')
  98. );
  99. if ($countCategories >= 100) {
  100. // Category code
  101. $url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_category';
  102. $form->addElement(
  103. 'select_ajax',
  104. 'category_code',
  105. get_lang('Category'),
  106. null,
  107. ['url' => $url]
  108. );
  109. } else {
  110. $categories = $courseCategoriesRepo->findAllInAccessUrl(
  111. $accessUrlId,
  112. api_get_configuration_value('allow_base_course_category')
  113. );
  114. $categoriesOptions = [null => get_lang('none')];
  115. /** @var CourseCategory $category */
  116. foreach ($categories as $category) {
  117. $categoriesOptions[$category->getCode()] = $category->__toString();
  118. }
  119. $form->addSelect(
  120. 'category_code',
  121. get_lang('Category'),
  122. $categoriesOptions
  123. );
  124. }
  125. // Course code
  126. $form->addText(
  127. 'wanted_code',
  128. [
  129. get_lang('Course code'),
  130. get_lang('Only letters (a-z) and numbers (0-9)'),
  131. ],
  132. '',
  133. [
  134. 'maxlength' => CourseManager::MAX_COURSE_LENGTH_CODE,
  135. 'pattern' => '[a-zA-Z0-9]+',
  136. 'title' => get_lang('Only letters (a-z) and numbers (0-9)'),
  137. ]
  138. );
  139. $form->applyFilter('wanted_code', 'html_filter');
  140. $form->addRule(
  141. 'wanted_code',
  142. get_lang('max. 20 characters, e.g. <i>INNOV21</i>'),
  143. 'maxlength',
  144. CourseManager::MAX_COURSE_LENGTH_CODE
  145. );
  146. // The teacher
  147. $titular = &$form->addElement('hidden', 'tutor_name', '');
  148. if ($course_validation_feature) {
  149. // Description of the requested course.
  150. $form->addElement(
  151. 'textarea',
  152. 'description',
  153. get_lang('Description'),
  154. ['rows' => '3']
  155. );
  156. // Objectives of the requested course.
  157. $form->addElement(
  158. 'textarea',
  159. 'objetives',
  160. get_lang('Objectives'),
  161. ['rows' => '3']
  162. );
  163. // Target audience of the requested course.
  164. $form->addElement(
  165. 'textarea',
  166. 'target_audience',
  167. get_lang('Target audience'),
  168. ['rows' => '3']
  169. );
  170. }
  171. // Course language.
  172. $languages = api_get_languages();
  173. if (count($languages) === 1) {
  174. // If there's only one language available, there's no point in asking
  175. $form->addElement('hidden', 'course_language', $languages['folder'][0]);
  176. } else {
  177. $form->addSelectLanguage(
  178. 'course_language',
  179. get_lang('Language'),
  180. [],
  181. ['style' => 'width:150px']
  182. );
  183. }
  184. // Exemplary content checkbox.
  185. $form->addElement(
  186. 'checkbox',
  187. 'exemplary_content',
  188. null,
  189. get_lang('Fill with demo content')
  190. );
  191. if ($course_validation_feature) {
  192. // A special URL to terms and conditions that is set
  193. // in the platform settings page.
  194. $terms_and_conditions_url = trim(
  195. api_get_setting('course_validation_terms_and_conditions_url')
  196. );
  197. // If the special setting is empty,
  198. // then we may get the URL from Chamilo's module "Terms and conditions",
  199. // if it is activated.
  200. if (empty($terms_and_conditions_url)) {
  201. if (api_get_setting('allow_terms_conditions') === 'true') {
  202. $terms_and_conditions_url = api_get_path(WEB_CODE_PATH).'auth/inscription.php?legal';
  203. }
  204. }
  205. if (!empty($terms_and_conditions_url)) {
  206. // Terms and conditions to be accepted before sending a course request.
  207. $form->addElement(
  208. 'checkbox',
  209. 'legal',
  210. null,
  211. get_lang('I have read and I accept the Terms and Conditions'),
  212. 1
  213. );
  214. $form->addRule(
  215. 'legal',
  216. get_lang('You have to accept our Terms and Conditions to proceed.'),
  217. 'required'
  218. );
  219. // Link to terms and conditions.
  220. $link_terms_and_conditions = '
  221. <script>
  222. function MM_openBrWindow(theURL, winName, features) { //v2.0
  223. window.open(theURL,winName,features);
  224. }
  225. </script>
  226. ';
  227. $link_terms_and_conditions .= Display::url(
  228. get_lang('Read the Terms and Conditions'),
  229. '#',
  230. ['onclick' => "javascript:MM_openBrWindow('$terms_and_conditions_url', 'Conditions', 'scrollbars=yes, width=800');"]
  231. );
  232. $form->addElement('label', null, $link_terms_and_conditions);
  233. }
  234. }
  235. $obj = new GradeModel();
  236. $obj->fill_grade_model_select_in_form($form);
  237. if (api_get_setting('teacher_can_select_course_template') === 'true') {
  238. $form->addElement(
  239. 'select_ajax',
  240. 'course_template',
  241. [
  242. get_lang('Course template'),
  243. get_lang('Pick a course as template for this new course'),
  244. ],
  245. null,
  246. ['url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_course']
  247. );
  248. }
  249. $form->addElement('html', '</div>');
  250. // Submit button.
  251. $form->addButtonCreate($course_validation_feature ? get_lang('Create this course request') : get_lang('Create this course'));
  252. // The progress bar of this form.
  253. $form->addProgress();
  254. // Set default values.
  255. if (isset($_user['language']) && $_user['language'] != '') {
  256. $values['course_language'] = $_user['language'];
  257. } else {
  258. $values['course_language'] = api_get_setting('platformLanguage');
  259. }
  260. $form->setDefaults($values);
  261. $message = null;
  262. $formContent = null;
  263. // Validate the form.
  264. if ($form->validate()) {
  265. $course_values = $form->exportValues();
  266. $wanted_code = $course_values['wanted_code'];
  267. $category_code = isset($course_values['category_code']) ? $course_values['category_code'] : '';
  268. $title = $course_values['title'];
  269. $course_language = $course_values['course_language'];
  270. $exemplary_content = !empty($course_values['exemplary_content']);
  271. if ($course_validation_feature) {
  272. $description = $course_values['description'];
  273. $objetives = $course_values['objetives'];
  274. $target_audience = $course_values['target_audience'];
  275. }
  276. if ($wanted_code == '') {
  277. $wanted_code = CourseManager::generate_course_code(
  278. api_substr($title, 0, CourseManager::MAX_COURSE_LENGTH_CODE)
  279. );
  280. }
  281. // Check whether the requested course code has already been occupied.
  282. if (!$course_validation_feature) {
  283. $course_code_ok = !CourseManager::course_code_exists($wanted_code);
  284. } else {
  285. $course_code_ok = !CourseRequestManager::course_code_exists($wanted_code);
  286. }
  287. if ($course_code_ok) {
  288. if (!$course_validation_feature) {
  289. $params = [];
  290. $params['title'] = $title;
  291. $params['exemplary_content'] = $exemplary_content;
  292. $params['wanted_code'] = $wanted_code;
  293. $params['course_category'] = $category_code;
  294. $params['course_language'] = $course_language;
  295. $params['gradebook_model_id'] = isset($course_values['gradebook_model_id']) ? $course_values['gradebook_model_id'] : null;
  296. $params['course_template'] = isset($course_values['course_template']) ? $course_values['course_template'] : '';
  297. /*include_once api_get_path(SYS_CODE_PATH).'lang/english/trad4all.inc.php';
  298. $file_to_include = api_get_path(SYS_CODE_PATH).'lang/'.$course_language.'/trad4all.inc.php';
  299. if (file_exists($file_to_include)) {
  300. include $file_to_include;
  301. }*/
  302. $course_info = CourseManager::create_course($params);
  303. if (!empty($course_info)) {
  304. $request = Container::getRequest();
  305. if ($request->files->has('picture')) {
  306. $uploadFile = $request->files->get('picture');
  307. $repo = Container::getCourseRepository();
  308. $em = $repo->getEntityManager();
  309. // @todo add in repository
  310. $course = $repo->find($course_info['real_id']);
  311. $illustration = new \Chamilo\CoreBundle\Entity\Illustration();
  312. $repo->addResourceNode($illustration, api_get_user_entity(api_get_user_id()), $course);
  313. $file = $repo->addFileToResource($illustration, $uploadFile);
  314. $file->setCrop($course_values['picture_crop_result']);
  315. $em->persist($file);
  316. $em->persist($illustration);
  317. $em->flush();
  318. }
  319. $splash = api_get_setting('course_creation_splash_screen');
  320. if ($splash === 'true') {
  321. $url = Container::getRouter()->generate('chamilo_core_course_welcome', ['course' =>$course_info['code']]);
  322. header('Location: '.$url);
  323. exit;
  324. } else {
  325. $url = api_get_path(WEB_COURSE_PATH).$course_info['directory'].'/';
  326. header('Location: '.$url);
  327. exit;
  328. }
  329. } else {
  330. $message = Display::return_message(
  331. get_lang('The course has not been created due to an internal error.'),
  332. 'error',
  333. false
  334. );
  335. // Display the form.
  336. $formContent = $form->returnForm();
  337. }
  338. } else {
  339. // Create a request for a new course.
  340. $request_id = CourseRequestManager::create_course_request(
  341. $wanted_code,
  342. $title,
  343. $description,
  344. $category_code,
  345. $course_language,
  346. $objetives,
  347. $target_audience,
  348. api_get_user_id(),
  349. $exemplary_content
  350. );
  351. if ($request_id) {
  352. $course_request_info = CourseRequestManager::get_course_request_info($request_id);
  353. $message = (is_array($course_request_info) ? '<strong>'.$course_request_info['code'].'</strong> : ' : '').get_lang('Your request for a new course has been sent successfully. You may receive a reply soon, within one or two days.');
  354. $message = Display::return_message(
  355. $message,
  356. 'confirmation',
  357. false
  358. );
  359. $message .= Display::tag(
  360. 'div',
  361. Display::url(
  362. get_lang('Back to courses list'),
  363. api_get_path(WEB_PATH).'user_portal.php',
  364. ['class' => 'btn btn-primary']
  365. ),
  366. ['style' => 'float: left; margin:0px; padding: 0px;']
  367. );
  368. } else {
  369. $message = Display::return_message(
  370. get_lang('The course request has not been created due to an internal error.'),
  371. 'error',
  372. false
  373. );
  374. // Display the form.
  375. $formContent = $form->returnForm();
  376. }
  377. }
  378. } else {
  379. $message = Display::return_message(
  380. get_lang('CourseCourse codeAlreadyExists'),
  381. 'error',
  382. false
  383. );
  384. // Display the form.
  385. $formContent = $form->returnForm();
  386. }
  387. } else {
  388. if (!$course_validation_feature) {
  389. $message = Display::return_message(get_lang('Once you click on "Create a course", a course is created with a section for Tests, Project based learning, Assessments, Courses, Dropbox, Agenda and much more. Logging in as teacher provides you with editing privileges for this course.'));
  390. }
  391. // Display the form.
  392. $formContent = $form->returnForm();
  393. }
  394. $tpl->assign('form', $formContent);
  395. $layout = $tpl->fetch($tpl->get_template('create_course/add_course.html.twig'));
  396. $tpl->assign('message', $message);
  397. $tpl->assign('content', $layout);
  398. $tpl->display_one_col_template();