webservice_course.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * @package chamilo.webservices
  5. */
  6. require_once __DIR__.'/../inc/global.inc.php';
  7. require_once __DIR__.'/webservice.php';
  8. /**
  9. * Web services available for the Course module. This class extends the WS class.
  10. */
  11. class WSCourse extends WS
  12. {
  13. /**
  14. * Deletes a course.
  15. *
  16. * @param string API secret key
  17. * @param string Course id field name
  18. * @param string Course id value
  19. */
  20. public function DeleteCourse(
  21. $secret_key,
  22. $course_id_field_name,
  23. $course_id_value
  24. ) {
  25. $verifKey = $this->verifyKey($secret_key);
  26. if ($verifKey instanceof WSError) {
  27. $this->handleError($verifKey);
  28. } else {
  29. $result = $this->deleteCourseHelper(
  30. $course_id_field_name,
  31. $course_id_value
  32. );
  33. if ($result instanceof WSError) {
  34. $this->handleError($result);
  35. }
  36. }
  37. }
  38. /**
  39. * Deletes multiple courses.
  40. *
  41. * @param string API secret key
  42. * @param array Array of courses with elements of the form
  43. * array('course_id_field_name' => 'name_of_field', 'course_id_value' => 'value')
  44. *
  45. * @return array Array with elements like
  46. * array('course_id_value' => 'value', 'result' => array('code' => 0, 'message' => 'Operation was successful')).
  47. * Note that if the result array contains a code different
  48. * than 0, an error occured
  49. */
  50. public function DeleteCourses($secret_key, $courses)
  51. {
  52. $verifKey = $this->verifyKey($secret_key);
  53. if ($verifKey instanceof WSError) {
  54. $this->handleError($verifKey);
  55. } else {
  56. $results = [];
  57. foreach ($courses as $course) {
  58. $result_tmp = [];
  59. $result_op = $this->deleteCourseHelper(
  60. $course['course_id_field_name'],
  61. $course['course_id_value']
  62. );
  63. $result_tmp['course_id_value'] = $course['course_id_value'];
  64. if ($result_op instanceof WSError) {
  65. // Return the error in the results
  66. $result_tmp['result'] = $result_op->toArray();
  67. } else {
  68. $result_tmp['result'] = $this->getSuccessfulResult();
  69. }
  70. $results[] = $result_tmp;
  71. }
  72. return $results;
  73. }
  74. }
  75. /**
  76. * Creates a course.
  77. *
  78. * @param string API secret key
  79. * @param string Title
  80. * @param string Category code
  81. * @param string Wanted code. If it's not defined, it will be generated automatically
  82. * @param string Tutor name
  83. * @param string Course admin user id field name
  84. * @param string Course admin user id value
  85. * @param string Course language
  86. * @param string Course id field name
  87. * @param string Course id value
  88. * @param array Course extra fields
  89. *
  90. * @return int Course id generated
  91. */
  92. public function CreateCourse(
  93. $secret_key,
  94. $title,
  95. $category_code,
  96. $wanted_code,
  97. $tutor_name,
  98. $course_admin_user_id_field_name,
  99. $course_admin_user_id_value,
  100. $language,
  101. $course_id_field_name,
  102. $course_id_value,
  103. $extras
  104. ) {
  105. // First, verify the secret key
  106. $verifKey = $this->verifyKey($secret_key);
  107. if ($verifKey instanceof WSError) {
  108. $this->handleError($verifKey);
  109. } else {
  110. $result = $this->createCourseHelper(
  111. $title,
  112. $category_code,
  113. $wanted_code,
  114. $tutor_name,
  115. $course_admin_user_id_field_name,
  116. $course_admin_user_id_value,
  117. $language,
  118. $course_id_field_name,
  119. $course_id_value,
  120. $extras
  121. );
  122. if ($result instanceof WSError) {
  123. $this->handleError($result);
  124. } else {
  125. return $result;
  126. }
  127. }
  128. }
  129. /**
  130. * Create multiple courses.
  131. *
  132. * @param string API secret key
  133. * @param array Courses to be created, with elements following the structure presented in CreateCourse
  134. *
  135. * @return array Array with elements of the form
  136. * array('course_id_value' => 'original value sent', 'course_id_generated' => 'value_generated', 'result' => array('code' => 0, 'message' => 'Operation was successful'))
  137. */
  138. public function CreateCourses($secret_key, $courses)
  139. {
  140. // First, verify the secret key
  141. $verifKey = $this->verifyKey($secret_key);
  142. if ($verifKey instanceof WSError) {
  143. $this->handleError($verifKey);
  144. } else {
  145. $results = [];
  146. foreach ($courses as $course) {
  147. $result_tmp = [];
  148. // re-initialize variables just in case
  149. $title = $category_code = $wanted_code = $tutor_name = $course_admin_user_id_field_name = $course_admin_user_id_value = $language = $course_id_field_name = $course_id_value = $extras = 0;
  150. extract($course);
  151. $result = $this->createCourseHelper(
  152. $title,
  153. $category_code,
  154. $wanted_code,
  155. $tutor_name,
  156. $course_admin_user_id_field_name,
  157. $course_admin_user_id_value,
  158. $language,
  159. $course_id_field_name,
  160. $course_id_value,
  161. $extras
  162. );
  163. if ($result instanceof WSError) {
  164. $result_tmp['result'] = $result->toArray();
  165. $result_tmp['course_id_value'] = $course_id_value;
  166. $result_tmp['course_id_generated'] = 0;
  167. } else {
  168. $result_tmp['result'] = $this->getSuccessfulResult();
  169. $result_tmp['course_id_value'] = $course_id_value;
  170. $result_tmp['course_id_generated'] = $result;
  171. }
  172. $results[] = $result_tmp;
  173. }
  174. return $results;
  175. }
  176. }
  177. /**
  178. * Edits a course.
  179. *
  180. * @param string API secret key
  181. * @param string Course id field name
  182. * @param string Course id value
  183. * @param string Title
  184. * @param string Category code
  185. * @param string Department name
  186. * @param string Department url
  187. * @param string Course language
  188. * @param int Visibility
  189. * @param int Subscribe (0 = denied, 1 = allowed)
  190. * @param int Unsubscribe (0 = denied, 1 = allowed)
  191. * @param string Visual code
  192. * @param array Course extra fields
  193. */
  194. public function EditCourse(
  195. $secret_key,
  196. $course_id_field_name,
  197. $course_id_value,
  198. $title,
  199. $category_code,
  200. $department_name,
  201. $department_url,
  202. $language,
  203. $visibility,
  204. $subscribe,
  205. $unsubscribe,
  206. $visual_code,
  207. $extras
  208. ) {
  209. $verifKey = $this->verifyKey($secret_key);
  210. if ($verifKey instanceof WSError) {
  211. $this->handleError($verifKey);
  212. } else {
  213. $result = $this->editCourseHelper(
  214. $course_id_field_name,
  215. $course_id_value,
  216. $title,
  217. $category_code,
  218. $department_name,
  219. $department_url,
  220. $language,
  221. $visibility,
  222. $subscribe,
  223. $unsubscribe,
  224. $visual_code,
  225. $extras
  226. );
  227. if ($result instanceof WSError) {
  228. $this->handleError($result);
  229. }
  230. }
  231. }
  232. /**
  233. * List courses.
  234. *
  235. * @param string API secret key
  236. * @param string A list of visibility filter we want to apply
  237. *
  238. * @return array An array with elements of the form
  239. * ('id' => 'Course internal id', 'code' => 'Course code', 'title' => 'Course title', 'language' => 'Course language', 'visibility' => 'Course visibility',
  240. * 'category_name' => 'Name of the category of the course', 'number_students' => 'Number of students in the course', 'external_course_id' => 'External course id')
  241. */
  242. public function ListCourses(
  243. $secret_key,
  244. $visibility = 'public,public-registered,private,closed'
  245. ) {
  246. $verifKey = $this->verifyKey($secret_key);
  247. if ($verifKey instanceof WSError) {
  248. $this->handleError($verifKey);
  249. } else {
  250. $visibilities = split(',', $visibility);
  251. $vis = [
  252. 'public' => '3',
  253. 'public-registered' => '2',
  254. 'private' => '1',
  255. 'closed' => '0',
  256. ];
  257. foreach ($visibilities as $p => $visibility) {
  258. $visibilities[$p] = $vis[$visibility];
  259. }
  260. $courses_result = [];
  261. $category_names = [];
  262. $courses = CourseManager::get_courses_list();
  263. foreach ($courses as $course) {
  264. //skip elements that do not match required visibility
  265. if (!in_array($course['visibility'], $visibilities)) {
  266. continue;
  267. }
  268. $course_tmp = [];
  269. $course_tmp['id'] = $course['id'];
  270. $course_tmp['code'] = $course['code'];
  271. $course_tmp['title'] = $course['title'];
  272. $course_tmp['language'] = $course['course_language'];
  273. $course_tmp['visibility'] = $course['visibility'];
  274. // Determining category name
  275. if ($category_names[$course['category_code']]) {
  276. $course_tmp['category_name'] = $category_names[$course['category_code']];
  277. } else {
  278. $category = CourseManager::get_course_category(
  279. $course['category_code']
  280. );
  281. $category_names[$course['category_code']] = $category['name'];
  282. $course_tmp['category_name'] = $category['name'];
  283. }
  284. // Determining number of students registered in course
  285. $user_list = CourseManager::get_user_list_from_course_code(
  286. $course['code'],
  287. 0
  288. );
  289. $course_tmp['number_students'] = count($user_list);
  290. // Determining external course id - this code misses the external course id field name
  291. // $course_tmp['external_course_id'] = CourseManager::get_course_extra_field_value($course_field_name, $course['code']);
  292. $courses_result[] = $course_tmp;
  293. }
  294. return $courses_result;
  295. }
  296. }
  297. /**
  298. * Subscribe user to a course.
  299. *
  300. * @param string API secret key
  301. * @param string Course id field name. Use "chamilo_course_id" to use internal id
  302. * @param string course id value
  303. * @param string User id field name. Use "chamilo_user_id" to use internal id
  304. * @param string User id value
  305. * @param int Status (1 = Teacher, 5 = Student)
  306. */
  307. public function SubscribeUserToCourse(
  308. $secret_key,
  309. $course_id_field_name,
  310. $course_id_value,
  311. $user_id_field_name,
  312. $user_id_value,
  313. $status
  314. ) {
  315. $verifKey = $this->verifyKey($secret_key);
  316. if ($verifKey instanceof WSError) {
  317. $this->handleError($verifKey);
  318. } else {
  319. $result = $this->changeUserSubscription(
  320. $course_id_field_name,
  321. $course_id_value,
  322. $user_id_field_name,
  323. $user_id_value,
  324. 1,
  325. $status
  326. );
  327. if ($result instanceof WSError) {
  328. $this->handleError($result);
  329. }
  330. }
  331. }
  332. /**
  333. * Unsusbscribe user from course.
  334. *
  335. * @param string API secret key
  336. * @param string Course id field name. Use "chamilo_course_id" to use internal id
  337. * @param string course id value
  338. * @param string User id field name. Use "chamilo_user_id" to use internal id
  339. * @param string User id value
  340. */
  341. public function UnsubscribeUserFromCourse(
  342. $secret_key,
  343. $course_id_field_name,
  344. $course_id_value,
  345. $user_id_field_name,
  346. $user_id_value
  347. ) {
  348. $verifKey = $this->verifyKey($secret_key);
  349. if ($verifKey instanceof WSError) {
  350. $this->handleError($verifKey);
  351. } else {
  352. $result = $this->changeUserSubscription(
  353. $course_id_field_name,
  354. $course_id_value,
  355. $user_id_field_name,
  356. $user_id_value,
  357. 0
  358. );
  359. if ($result instanceof WSError) {
  360. $this->handleError($result);
  361. }
  362. }
  363. }
  364. /**
  365. * Returns the descriptions of a course, along with their id.
  366. *
  367. * @param string API secret key
  368. * @param string Course id field name
  369. * @param string Course id value
  370. *
  371. * @return array Returns an array with elements of the form
  372. * array('course_desc_id' => 1, 'course_desc_title' => 'Title', 'course_desc_content' => 'Content')
  373. */
  374. public function GetCourseDescriptions(
  375. $secret_key,
  376. $course_id_field_name,
  377. $course_id_value
  378. ) {
  379. $verifKey = $this->verifyKey($secret_key);
  380. if ($verifKey instanceof WSError) {
  381. $this->handleError($verifKey);
  382. } else {
  383. $course_id = $this->getCourseId(
  384. $course_id_field_name,
  385. $course_id_value
  386. );
  387. if ($course_id instanceof WSError) {
  388. return $course_id;
  389. } else {
  390. // Course exists, get its descriptions
  391. $descriptions = CourseDescription::get_descriptions($course_id);
  392. $results = [];
  393. foreach ($descriptions as $description) {
  394. $results[] = [
  395. 'course_desc_id' => $description->get_description_type(
  396. ),
  397. 'course_desc_title' => $description->get_title(),
  398. 'course_desc_content' => $description->get_content(),
  399. ];
  400. }
  401. return $results;
  402. }
  403. }
  404. }
  405. /**
  406. * Edit course description.
  407. *
  408. * @param string API secret key
  409. * @param string Course id field name
  410. * @param string Course id value
  411. * @param int Category id from course description
  412. * @param string Description title
  413. * @param string Course description content
  414. */
  415. public function EditCourseDescription(
  416. $secret_key,
  417. $course_id_field_name,
  418. $course_id_value,
  419. $course_desc_id,
  420. $course_desc_title,
  421. $course_desc_content
  422. ) {
  423. $verifKey = $this->verifyKey($secret_key);
  424. if ($verifKey instanceof WSError) {
  425. $this->handleError($verifKey);
  426. } else {
  427. $course_id = $this->getCourseId(
  428. $course_id_field_name,
  429. $course_id_value
  430. );
  431. if ($course_id instanceof WSError) {
  432. return $course_id;
  433. } else {
  434. // Create the new course description
  435. $cd = new CourseDescription();
  436. $cd->set_description_type($course_desc_id);
  437. $cd->set_title($course_desc_title);
  438. $cd->set_content($course_desc_content);
  439. $cd->set_session_id(0);
  440. // Get course info
  441. $course_info = CourseManager::get_course_information(
  442. CourseManager::get_course_code_from_course_id($course_id)
  443. );
  444. $cd->set_course_id($course_info['real_id']);
  445. // Check if this course description exists
  446. $descriptions = CourseDescription::get_descriptions($course_id);
  447. $exists = false;
  448. foreach ($descriptions as $description) {
  449. if ($description->get_description_type() == $course_desc_id) {
  450. $exists = true;
  451. }
  452. }
  453. if (!$exists) {
  454. $cd->set_progress(0);
  455. $cd->insert();
  456. } else {
  457. $cd->update();
  458. }
  459. }
  460. }
  461. }
  462. /**
  463. * Deletes a course (helper method).
  464. *
  465. * @param string Course id field name
  466. * @param string Course id value
  467. *
  468. * @return mixed True if the course was successfully deleted, WSError otherwise
  469. */
  470. protected function deleteCourseHelper(
  471. $course_id_field_name,
  472. $course_id_value
  473. ) {
  474. $course_id = $this->getCourseId(
  475. $course_id_field_name,
  476. $course_id_value
  477. );
  478. if ($course_id instanceof WSError) {
  479. return $course_id;
  480. } else {
  481. $course_code = CourseManager::get_course_code_from_course_id(
  482. $course_id
  483. );
  484. CourseManager::delete_course($course_code);
  485. return true;
  486. }
  487. }
  488. /**
  489. * Creates a course (helper method).
  490. *
  491. * @param string Title
  492. * @param string Category code
  493. * @param string Wanted code. If it's not defined, it will be generated automatically
  494. * @param string Tutor name
  495. * @param string Course admin user id field name
  496. * @param string Course admin user id value
  497. * @param string Course language
  498. * @param string Course id field name
  499. * @param string Course id value
  500. * @param array Course extra fields
  501. *
  502. * @return mixed Generated id if creation was successful, WSError otherwise
  503. */
  504. protected function createCourseHelper(
  505. $title,
  506. $category_code,
  507. $wanted_code,
  508. $tutor_name,
  509. $course_admin_user_id_field_name,
  510. $course_admin_user_id_value,
  511. $language,
  512. $course_id_field_name,
  513. $course_id_value,
  514. $extras
  515. ) {
  516. // Add the original course id field name and value to the extra fields if needed
  517. $extras_associative = [];
  518. if ($course_id_field_name != "chamilo_course_id") {
  519. $extras_associative[$course_id_field_name] = $course_id_value;
  520. }
  521. foreach ($extras as $extra) {
  522. $extras_associative[$extra['field_name']] = $extra['field_value'];
  523. }
  524. $course_admin_id = $this->getUserId(
  525. $course_admin_user_id_field_name,
  526. $course_admin_user_id_value
  527. );
  528. if ($course_admin_id instanceof WSError) {
  529. return $course_admin_id;
  530. }
  531. if ($wanted_code == '') {
  532. $wanted_code = CourseManager::generate_course_code($title);
  533. }
  534. $result = create_course(
  535. $wanted_code,
  536. $title,
  537. $tutor_name,
  538. $category_code,
  539. $language,
  540. $course_admin_id,
  541. $this->_configuration['db_prefix'],
  542. 0
  543. );
  544. if (!$result) {
  545. return new WSError(202, 'There was an error creating the course');
  546. } else {
  547. // Update extra fields
  548. foreach ($extras_associative as $fname => $fvalue) {
  549. CourseManager::update_course_extra_field_value(
  550. $result,
  551. $fname,
  552. $fvalue
  553. );
  554. }
  555. // Get course id
  556. $course_info = CourseManager::get_course_information($result);
  557. return $course_info['real_id'];
  558. }
  559. }
  560. /**
  561. * Edits a course (helper method).
  562. *
  563. * @param string Course id field name
  564. * @param string Course id value
  565. * @param string Title
  566. * @param string Category code
  567. * @param string Department name
  568. * @param string Department url
  569. * @param string Course language
  570. * @param int Visibility
  571. * @param int Subscribe (0 = denied, 1 = allowed)
  572. * @param int Unsubscribe (0 = denied, 1 = allowed)
  573. * @param string Visual code
  574. * @param array Course extra fields
  575. *
  576. * @return mixed True in case of success, WSError otherwise
  577. */
  578. protected function editCourseHelper(
  579. $course_id_field_name,
  580. $course_id_value,
  581. $title,
  582. $category_code,
  583. $department_name,
  584. $department_url,
  585. $language,
  586. $visibility,
  587. $subscribe,
  588. $unsubscribe,
  589. $visual_code,
  590. $extras
  591. ) {
  592. $course_id = $this->getCourseId(
  593. $course_id_field_name,
  594. $course_id_value
  595. );
  596. if ($course_id instanceof WSError) {
  597. return $course_id;
  598. } else {
  599. $attributes = [];
  600. if (!empty($title)) {
  601. $attributes['title'] = $title;
  602. }
  603. if (!empty($category_code)) {
  604. $attributes['category_code'] = $category_code;
  605. }
  606. if (!empty($department_name)) {
  607. $attributes['department_name'] = $department_name;
  608. }
  609. if (!empty($department_url)) {
  610. $attributes['department_url'] = $department_url;
  611. }
  612. if (!empty($language)) {
  613. $attributes['course_language'] = $language;
  614. }
  615. if ($visibility != '') {
  616. $attributes['visibility'] = (int) $visibility;
  617. }
  618. if ($subscribe != '') {
  619. $attributes['subscribe'] = (int) $subscribe;
  620. }
  621. if ($unsubscribe != '') {
  622. $attributes['unsubscribe'] = (int) $unsubscribe;
  623. }
  624. if (!empty($visual_code)) {
  625. $attributes['visual_code'] = $visual_code;
  626. }
  627. if (!empty($attributes)) {
  628. CourseManager::update_attributes($course_id, $attributes);
  629. }
  630. if (!empty($extras)) {
  631. $course_code = CourseManager::get_course_code_from_course_id(
  632. $course_id
  633. );
  634. $extras_associative = [];
  635. foreach ($extras as $extra) {
  636. $extras_associative[$extra['field_name']] = $extra['field_value'];
  637. }
  638. foreach ($extras_associative as $fname => $fvalue) {
  639. CourseManager::update_extra_field_value(
  640. $course_code,
  641. $fname,
  642. $fvalue
  643. );
  644. }
  645. }
  646. return true;
  647. }
  648. }
  649. /**
  650. * Subscribe or unsubscribe user to a course (helper method).
  651. *
  652. * @param string Course id field name. Use "chamilo_course_id" to use internal id
  653. * @param string course id value
  654. * @param string User id field name. Use "chamilo_user_id" to use internal id
  655. * @param string User id value
  656. * @param int Set to 1 to subscribe, 0 to unsubscribe
  657. * @param int Status (STUDENT or TEACHER) Used for subscription only
  658. *
  659. * @return mixed True if subscription or unsubscription was successful, false otherwise
  660. */
  661. protected function changeUserSubscription(
  662. $course_id_field_name,
  663. $course_id_value,
  664. $user_id_field_name,
  665. $user_id_value,
  666. $state,
  667. $status = STUDENT
  668. ) {
  669. $course_id = $this->getCourseId(
  670. $course_id_field_name,
  671. $course_id_value
  672. );
  673. if ($course_id instanceof WSError) {
  674. return $course_id;
  675. } else {
  676. $user_id = $this->getUserId($user_id_field_name, $user_id_value);
  677. if ($user_id instanceof WSError) {
  678. return $user_id;
  679. } else {
  680. $course_code = CourseManager::get_course_code_from_course_id(
  681. $course_id
  682. );
  683. if ($state == 0) {
  684. // Unsubscribe user
  685. CourseManager::unsubscribe_user($user_id, $course_code);
  686. return true;
  687. } else {
  688. // Subscribe user
  689. if (CourseManager::subscribeUser(
  690. $user_id,
  691. $course_code,
  692. $status
  693. )
  694. ) {
  695. return true;
  696. } else {
  697. return new WSError(
  698. 203,
  699. 'An error occured subscribing to this course'
  700. );
  701. }
  702. }
  703. }
  704. }
  705. }
  706. }