PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/grade/report/user/externallib.php

https://bitbucket.org/moodle/moodle
PHP | 537 lines | 342 code | 56 blank | 139 comment | 31 complexity | b7c887d51303780cb97d51661f379a8f MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * External grade report user API
  18. *
  19. * @package gradereport_user
  20. * @copyright 2015 Juan Leyva <juan@moodle.com>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. defined('MOODLE_INTERNAL') || die;
  24. require_once("$CFG->libdir/externallib.php");
  25. /**
  26. * External grade report API implementation
  27. *
  28. * @package gradereport_user
  29. * @copyright 2015 Juan Leyva <juan@moodle.com>
  30. * @category external
  31. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32. */
  33. class gradereport_user_external extends external_api {
  34. /**
  35. * Validate access permissions to the report
  36. *
  37. * @param int $courseid the courseid
  38. * @param int $userid the user id to retrieve data from
  39. * @param int $groupid the group id
  40. * @return array with the parameters cleaned and other required information
  41. * @since Moodle 3.2
  42. */
  43. protected static function check_report_access($courseid, $userid, $groupid = 0) {
  44. global $USER;
  45. // Validate the parameter.
  46. $params = self::validate_parameters(self::get_grades_table_parameters(),
  47. array(
  48. 'courseid' => $courseid,
  49. 'userid' => $userid,
  50. 'groupid' => $groupid,
  51. )
  52. );
  53. // Compact/extract functions are not recommended.
  54. $courseid = $params['courseid'];
  55. $userid = $params['userid'];
  56. $groupid = $params['groupid'];
  57. // Function get_course internally throws an exception if the course doesn't exist.
  58. $course = get_course($courseid);
  59. $context = context_course::instance($courseid);
  60. self::validate_context($context);
  61. // Specific capabilities.
  62. require_capability('gradereport/user:view', $context);
  63. $user = null;
  64. if (empty($userid)) {
  65. require_capability('moodle/grade:viewall', $context);
  66. } else {
  67. $user = core_user::get_user($userid, '*', MUST_EXIST);
  68. core_user::require_active_user($user);
  69. // Check if we can view the user group (if any).
  70. // When userid == 0, we are retrieving all the users, we'll check then if a groupid is required.
  71. if (!groups_user_groups_visible($course, $user->id)) {
  72. throw new moodle_exception('notingroup');
  73. }
  74. }
  75. $access = false;
  76. if (has_capability('moodle/grade:viewall', $context)) {
  77. // Can view all course grades.
  78. $access = true;
  79. } else if ($userid == $USER->id and has_capability('moodle/grade:view', $context) and $course->showgrades) {
  80. // View own grades.
  81. $access = true;
  82. }
  83. if (!$access) {
  84. throw new moodle_exception('nopermissiontoviewgrades', 'error');
  85. }
  86. if (!empty($groupid)) {
  87. // Determine is the group is visible to user.
  88. if (!groups_group_visible($groupid, $course)) {
  89. throw new moodle_exception('notingroup');
  90. }
  91. } else {
  92. // Check to see if groups are being used here.
  93. if ($groupmode = groups_get_course_groupmode($course)) {
  94. $groupid = groups_get_course_group($course);
  95. // Determine is the group is visible to user (this is particullary for the group 0).
  96. if (!groups_group_visible($groupid, $course)) {
  97. throw new moodle_exception('notingroup');
  98. }
  99. } else {
  100. $groupid = 0;
  101. }
  102. }
  103. return array($params, $course, $context, $user, $groupid);
  104. }
  105. /**
  106. * Get the report data
  107. * @param stdClass $course course object
  108. * @param stdClass $context context object
  109. * @param stdClass $user user object (it can be null for all the users)
  110. * @param int $userid the user to retrieve data from, 0 for all
  111. * @param int $groupid the group id to filter
  112. * @param bool $tabledata whether to get the table data (true) or the gradeitemdata
  113. * @return array data and possible warnings
  114. * @since Moodle 3.2
  115. */
  116. protected static function get_report_data($course, $context, $user, $userid, $groupid, $tabledata = true) {
  117. global $CFG;
  118. $warnings = array();
  119. // Require files here to save some memory in case validation fails.
  120. require_once($CFG->dirroot . '/group/lib.php');
  121. require_once($CFG->libdir . '/gradelib.php');
  122. require_once($CFG->dirroot . '/grade/lib.php');
  123. require_once($CFG->dirroot . '/grade/report/user/lib.php');
  124. // Force regrade to update items marked as 'needupdate'.
  125. grade_regrade_final_grades($course->id);
  126. $gpr = new grade_plugin_return(
  127. array(
  128. 'type' => 'report',
  129. 'plugin' => 'user',
  130. 'courseid' => $course->id,
  131. 'courseidnumber' => $course->idnumber,
  132. 'userid' => $userid)
  133. );
  134. $reportdata = array();
  135. // Just one user.
  136. if ($user) {
  137. $report = new grade_report_user($course->id, $gpr, $context, $userid);
  138. $report->fill_table();
  139. $gradeuserdata = array(
  140. 'courseid' => $course->id,
  141. 'courseidnumber' => $course->idnumber,
  142. 'userid' => $user->id,
  143. 'userfullname' => fullname($user),
  144. 'useridnumber' => $user->idnumber,
  145. 'maxdepth' => $report->maxdepth,
  146. );
  147. if ($tabledata) {
  148. $gradeuserdata['tabledata'] = $report->tabledata;
  149. } else {
  150. $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
  151. }
  152. $reportdata[] = $gradeuserdata;
  153. } else {
  154. $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
  155. $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
  156. $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context);
  157. $gui = new graded_users_iterator($course, null, $groupid);
  158. $gui->require_active_enrolment($showonlyactiveenrol);
  159. $gui->init();
  160. while ($userdata = $gui->next_user()) {
  161. $currentuser = $userdata->user;
  162. $report = new grade_report_user($course->id, $gpr, $context, $currentuser->id);
  163. $report->fill_table();
  164. $gradeuserdata = array(
  165. 'courseid' => $course->id,
  166. 'courseidnumber' => $course->idnumber,
  167. 'userid' => $currentuser->id,
  168. 'userfullname' => fullname($currentuser),
  169. 'useridnumber' => $currentuser->idnumber,
  170. 'maxdepth' => $report->maxdepth,
  171. );
  172. if ($tabledata) {
  173. $gradeuserdata['tabledata'] = $report->tabledata;
  174. } else {
  175. $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
  176. }
  177. $reportdata[] = $gradeuserdata;
  178. }
  179. $gui->close();
  180. }
  181. return array($reportdata, $warnings);
  182. }
  183. /**
  184. * Describes the parameters for get_grades_table.
  185. *
  186. * @return external_function_parameters
  187. * @since Moodle 2.9
  188. */
  189. public static function get_grades_table_parameters() {
  190. return new external_function_parameters (
  191. array(
  192. 'courseid' => new external_value(PARAM_INT, 'Course Id', VALUE_REQUIRED),
  193. 'userid' => new external_value(PARAM_INT, 'Return grades only for this user (optional)', VALUE_DEFAULT, 0),
  194. 'groupid' => new external_value(PARAM_INT, 'Get users from this group only', VALUE_DEFAULT, 0)
  195. )
  196. );
  197. }
  198. /**
  199. * Returns a list of grades tables for users in a course.
  200. *
  201. * @param int $courseid Course Id
  202. * @param int $userid Only this user (optional)
  203. * @param int $groupid Get users from this group only
  204. *
  205. * @return array the grades tables
  206. * @since Moodle 2.9
  207. */
  208. public static function get_grades_table($courseid, $userid = 0, $groupid = 0) {
  209. global $CFG, $USER;
  210. list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
  211. $userid = $params['userid'];
  212. // We pass userid because it can be still 0.
  213. list($tables, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid);
  214. $result = array();
  215. $result['tables'] = $tables;
  216. $result['warnings'] = $warnings;
  217. return $result;
  218. }
  219. /**
  220. * Creates a table column structure
  221. *
  222. * @return array
  223. * @since Moodle 2.9
  224. */
  225. private static function grades_table_column() {
  226. return array (
  227. 'class' => new external_value(PARAM_RAW, 'class'),
  228. 'content' => new external_value(PARAM_RAW, 'cell content'),
  229. 'headers' => new external_value(PARAM_RAW, 'headers')
  230. );
  231. }
  232. /**
  233. * Describes tget_grades_table return value.
  234. *
  235. * @return external_single_structure
  236. * @since Moodle 2.9
  237. */
  238. public static function get_grades_table_returns() {
  239. return new external_single_structure(
  240. array(
  241. 'tables' => new external_multiple_structure(
  242. new external_single_structure(
  243. array(
  244. 'courseid' => new external_value(PARAM_INT, 'course id'),
  245. 'userid' => new external_value(PARAM_INT, 'user id'),
  246. 'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
  247. 'maxdepth' => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
  248. 'tabledata' => new external_multiple_structure(
  249. new external_single_structure(
  250. array(
  251. 'itemname' => new external_single_structure(
  252. array (
  253. 'class' => new external_value(PARAM_RAW, 'class'),
  254. 'colspan' => new external_value(PARAM_INT, 'col span'),
  255. 'content' => new external_value(PARAM_RAW, 'cell content'),
  256. 'celltype' => new external_value(PARAM_RAW, 'cell type'),
  257. 'id' => new external_value(PARAM_ALPHANUMEXT, 'id')
  258. ), 'The item returned data', VALUE_OPTIONAL
  259. ),
  260. 'leader' => new external_single_structure(
  261. array (
  262. 'class' => new external_value(PARAM_RAW, 'class'),
  263. 'rowspan' => new external_value(PARAM_INT, 'row span')
  264. ), 'The item returned data', VALUE_OPTIONAL
  265. ),
  266. 'weight' => new external_single_structure(
  267. self::grades_table_column(), 'weight column', VALUE_OPTIONAL
  268. ),
  269. 'grade' => new external_single_structure(
  270. self::grades_table_column(), 'grade column', VALUE_OPTIONAL
  271. ),
  272. 'range' => new external_single_structure(
  273. self::grades_table_column(), 'range column', VALUE_OPTIONAL
  274. ),
  275. 'percentage' => new external_single_structure(
  276. self::grades_table_column(), 'percentage column', VALUE_OPTIONAL
  277. ),
  278. 'lettergrade' => new external_single_structure(
  279. self::grades_table_column(), 'lettergrade column', VALUE_OPTIONAL
  280. ),
  281. 'rank' => new external_single_structure(
  282. self::grades_table_column(), 'rank column', VALUE_OPTIONAL
  283. ),
  284. 'average' => new external_single_structure(
  285. self::grades_table_column(), 'average column', VALUE_OPTIONAL
  286. ),
  287. 'feedback' => new external_single_structure(
  288. self::grades_table_column(), 'feedback column', VALUE_OPTIONAL
  289. ),
  290. 'contributiontocoursetotal' => new external_single_structure(
  291. self::grades_table_column(), 'contributiontocoursetotal column', VALUE_OPTIONAL
  292. ),
  293. ), 'table'
  294. )
  295. )
  296. )
  297. )
  298. ),
  299. 'warnings' => new external_warnings()
  300. )
  301. );
  302. }
  303. /**
  304. * Returns description of method parameters
  305. *
  306. * @return external_function_parameters
  307. * @since Moodle 2.9
  308. */
  309. public static function view_grade_report_parameters() {
  310. return new external_function_parameters(
  311. array(
  312. 'courseid' => new external_value(PARAM_INT, 'id of the course'),
  313. 'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0),
  314. )
  315. );
  316. }
  317. /**
  318. * Trigger the user report events, do the same that the web interface view of the report
  319. *
  320. * @param int $courseid id of course
  321. * @param int $userid id of the user the report belongs to
  322. * @return array of warnings and status result
  323. * @since Moodle 2.9
  324. * @throws moodle_exception
  325. */
  326. public static function view_grade_report($courseid, $userid = 0) {
  327. global $CFG, $USER;
  328. require_once($CFG->dirroot . "/grade/lib.php");
  329. require_once($CFG->dirroot . "/grade/report/user/lib.php");
  330. $params = self::validate_parameters(self::view_grade_report_parameters(),
  331. array(
  332. 'courseid' => $courseid,
  333. 'userid' => $userid
  334. ));
  335. $warnings = array();
  336. $course = get_course($params['courseid']);
  337. $context = context_course::instance($course->id);
  338. self::validate_context($context);
  339. $userid = $params['userid'];
  340. if (empty($userid)) {
  341. $userid = $USER->id;
  342. } else {
  343. $user = core_user::get_user($userid, '*', MUST_EXIST);
  344. core_user::require_active_user($user);
  345. }
  346. $access = false;
  347. if (has_capability('moodle/grade:viewall', $context)) {
  348. // Can view all course grades (any user).
  349. $access = true;
  350. } else if ($userid == $USER->id and has_capability('moodle/grade:view', $context) and $course->showgrades) {
  351. // View own grades.
  352. $access = true;
  353. }
  354. if (!$access) {
  355. throw new moodle_exception('nopermissiontoviewgrades', 'error');
  356. }
  357. // Create a report instance. We don't need the gpr second parameter.
  358. $report = new grade_report_user($course->id, null, $context, $userid);
  359. $report->viewed();
  360. $result = array();
  361. $result['status'] = true;
  362. $result['warnings'] = $warnings;
  363. return $result;
  364. }
  365. /**
  366. * Returns description of method result value
  367. *
  368. * @return external_description
  369. * @since Moodle 2.9
  370. */
  371. public static function view_grade_report_returns() {
  372. return new external_single_structure(
  373. array(
  374. 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
  375. 'warnings' => new external_warnings()
  376. )
  377. );
  378. }
  379. /**
  380. * Describes the parameters for get_grade_items.
  381. *
  382. * @return external_function_parameters
  383. * @since Moodle 3.2
  384. */
  385. public static function get_grade_items_parameters() {
  386. return self::get_grades_table_parameters();
  387. }
  388. /**
  389. * Returns the complete list of grade items for users in a course.
  390. *
  391. * @param int $courseid Course Id
  392. * @param int $userid Only this user (optional)
  393. * @param int $groupid Get users from this group only
  394. *
  395. * @return array the grades tables
  396. * @since Moodle 3.2
  397. */
  398. public static function get_grade_items($courseid, $userid = 0, $groupid = 0) {
  399. global $CFG, $USER;
  400. list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
  401. $userid = $params['userid'];
  402. // We pass userid because it can be still 0.
  403. list($gradeitems, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid, false);
  404. foreach ($gradeitems as $gradeitem) {
  405. if (isset($gradeitem['feedback']) and isset($gradeitem['feedbackformat'])) {
  406. list($gradeitem['feedback'], $gradeitem['feedbackformat']) =
  407. external_format_text($gradeitem['feedback'], $gradeitem['feedbackformat'], $context->id);
  408. }
  409. }
  410. $result = array();
  411. $result['usergrades'] = $gradeitems;
  412. $result['warnings'] = $warnings;
  413. return $result;
  414. }
  415. /**
  416. * Describes tget_grade_items return value.
  417. *
  418. * @return external_single_structure
  419. * @since Moodle 3.2
  420. */
  421. public static function get_grade_items_returns() {
  422. return new external_single_structure(
  423. array(
  424. 'usergrades' => new external_multiple_structure(
  425. new external_single_structure(
  426. array(
  427. 'courseid' => new external_value(PARAM_INT, 'course id'),
  428. 'courseidnumber' => new external_value(PARAM_TEXT, 'course idnumber'),
  429. 'userid' => new external_value(PARAM_INT, 'user id'),
  430. 'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
  431. 'useridnumber' => new external_value(
  432. core_user::get_property_type('idnumber'), 'user idnumber'),
  433. 'maxdepth' => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
  434. 'gradeitems' => new external_multiple_structure(
  435. new external_single_structure(
  436. array(
  437. 'id' => new external_value(PARAM_INT, 'Grade item id'),
  438. 'itemname' => new external_value(PARAM_TEXT, 'Grade item name'),
  439. 'itemtype' => new external_value(PARAM_ALPHA, 'Grade item type'),
  440. 'itemmodule' => new external_value(PARAM_PLUGIN, 'Grade item module'),
  441. 'iteminstance' => new external_value(PARAM_INT, 'Grade item instance'),
  442. 'itemnumber' => new external_value(PARAM_INT, 'Grade item item number'),
  443. 'idnumber' => new external_value(PARAM_TEXT, 'Grade item idnumber'),
  444. 'categoryid' => new external_value(PARAM_INT, 'Grade item category id'),
  445. 'outcomeid' => new external_value(PARAM_INT, 'Outcome id'),
  446. 'scaleid' => new external_value(PARAM_INT, 'Scale id'),
  447. 'locked' => new external_value(PARAM_BOOL, 'Grade item for user locked?', VALUE_OPTIONAL),
  448. 'cmid' => new external_value(PARAM_INT, 'Course module id (if type mod)', VALUE_OPTIONAL),
  449. 'weightraw' => new external_value(PARAM_FLOAT, 'Weight raw', VALUE_OPTIONAL),
  450. 'weightformatted' => new external_value(PARAM_NOTAGS, 'Weight', VALUE_OPTIONAL),
  451. 'status' => new external_value(PARAM_ALPHA, 'Status', VALUE_OPTIONAL),
  452. 'graderaw' => new external_value(PARAM_FLOAT, 'Grade raw', VALUE_OPTIONAL),
  453. 'gradedatesubmitted' => new external_value(PARAM_INT, 'Grade submit date', VALUE_OPTIONAL),
  454. 'gradedategraded' => new external_value(PARAM_INT, 'Grade graded date', VALUE_OPTIONAL),
  455. 'gradehiddenbydate' => new external_value(PARAM_BOOL, 'Grade hidden by date?', VALUE_OPTIONAL),
  456. 'gradeneedsupdate' => new external_value(PARAM_BOOL, 'Grade needs update?', VALUE_OPTIONAL),
  457. 'gradeishidden' => new external_value(PARAM_BOOL, 'Grade is hidden?', VALUE_OPTIONAL),
  458. 'gradeislocked' => new external_value(PARAM_BOOL, 'Grade is locked?', VALUE_OPTIONAL),
  459. 'gradeisoverridden' => new external_value(PARAM_BOOL, 'Grade overridden?', VALUE_OPTIONAL),
  460. 'gradeformatted' => new external_value(PARAM_NOTAGS, 'The grade formatted', VALUE_OPTIONAL),
  461. 'grademin' => new external_value(PARAM_FLOAT, 'Grade min', VALUE_OPTIONAL),
  462. 'grademax' => new external_value(PARAM_FLOAT, 'Grade max', VALUE_OPTIONAL),
  463. 'rangeformatted' => new external_value(PARAM_NOTAGS, 'Range formatted', VALUE_OPTIONAL),
  464. 'percentageformatted' => new external_value(PARAM_NOTAGS, 'Percentage', VALUE_OPTIONAL),
  465. 'lettergradeformatted' => new external_value(PARAM_NOTAGS, 'Letter grade', VALUE_OPTIONAL),
  466. 'rank' => new external_value(PARAM_INT, 'Rank in the course', VALUE_OPTIONAL),
  467. 'numusers' => new external_value(PARAM_INT, 'Num users in course', VALUE_OPTIONAL),
  468. 'averageformatted' => new external_value(PARAM_NOTAGS, 'Grade average', VALUE_OPTIONAL),
  469. 'feedback' => new external_value(PARAM_RAW, 'Grade feedback', VALUE_OPTIONAL),
  470. 'feedbackformat' => new external_format_value('feedback', VALUE_OPTIONAL),
  471. ), 'Grade items'
  472. )
  473. )
  474. )
  475. )
  476. ),
  477. 'warnings' => new external_warnings()
  478. )
  479. );
  480. }
  481. }