PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/grade/report/user/externallib.php

http://github.com/moodle/moodle
PHP | 528 lines | 333 code | 56 blank | 139 comment | 31 complexity | 35925f3b8d0c5c121409092724a12d64 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  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. 'userid' => $userid)
  132. );
  133. $reportdata = array();
  134. // Just one user.
  135. if ($user) {
  136. $report = new grade_report_user($course->id, $gpr, $context, $userid);
  137. $report->fill_table();
  138. $gradeuserdata = array(
  139. 'courseid' => $course->id,
  140. 'userid' => $user->id,
  141. 'userfullname' => fullname($user),
  142. 'maxdepth' => $report->maxdepth,
  143. );
  144. if ($tabledata) {
  145. $gradeuserdata['tabledata'] = $report->tabledata;
  146. } else {
  147. $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
  148. }
  149. $reportdata[] = $gradeuserdata;
  150. } else {
  151. $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
  152. $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
  153. $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context);
  154. $gui = new graded_users_iterator($course, null, $groupid);
  155. $gui->require_active_enrolment($showonlyactiveenrol);
  156. $gui->init();
  157. while ($userdata = $gui->next_user()) {
  158. $currentuser = $userdata->user;
  159. $report = new grade_report_user($course->id, $gpr, $context, $currentuser->id);
  160. $report->fill_table();
  161. $gradeuserdata = array(
  162. 'courseid' => $course->id,
  163. 'userid' => $currentuser->id,
  164. 'userfullname' => fullname($currentuser),
  165. 'maxdepth' => $report->maxdepth,
  166. );
  167. if ($tabledata) {
  168. $gradeuserdata['tabledata'] = $report->tabledata;
  169. } else {
  170. $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
  171. }
  172. $reportdata[] = $gradeuserdata;
  173. }
  174. $gui->close();
  175. }
  176. return array($reportdata, $warnings);
  177. }
  178. /**
  179. * Describes the parameters for get_grades_table.
  180. *
  181. * @return external_function_parameters
  182. * @since Moodle 2.9
  183. */
  184. public static function get_grades_table_parameters() {
  185. return new external_function_parameters (
  186. array(
  187. 'courseid' => new external_value(PARAM_INT, 'Course Id', VALUE_REQUIRED),
  188. 'userid' => new external_value(PARAM_INT, 'Return grades only for this user (optional)', VALUE_DEFAULT, 0),
  189. 'groupid' => new external_value(PARAM_INT, 'Get users from this group only', VALUE_DEFAULT, 0)
  190. )
  191. );
  192. }
  193. /**
  194. * Returns a list of grades tables for users in a course.
  195. *
  196. * @param int $courseid Course Id
  197. * @param int $userid Only this user (optional)
  198. * @param int $groupid Get users from this group only
  199. *
  200. * @return array the grades tables
  201. * @since Moodle 2.9
  202. */
  203. public static function get_grades_table($courseid, $userid = 0, $groupid = 0) {
  204. global $CFG, $USER;
  205. list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
  206. $userid = $params['userid'];
  207. // We pass userid because it can be still 0.
  208. list($tables, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid);
  209. $result = array();
  210. $result['tables'] = $tables;
  211. $result['warnings'] = $warnings;
  212. return $result;
  213. }
  214. /**
  215. * Creates a table column structure
  216. *
  217. * @return array
  218. * @since Moodle 2.9
  219. */
  220. private static function grades_table_column() {
  221. return array (
  222. 'class' => new external_value(PARAM_RAW, 'class'),
  223. 'content' => new external_value(PARAM_RAW, 'cell content'),
  224. 'headers' => new external_value(PARAM_RAW, 'headers')
  225. );
  226. }
  227. /**
  228. * Describes tget_grades_table return value.
  229. *
  230. * @return external_single_structure
  231. * @since Moodle 2.9
  232. */
  233. public static function get_grades_table_returns() {
  234. return new external_single_structure(
  235. array(
  236. 'tables' => new external_multiple_structure(
  237. new external_single_structure(
  238. array(
  239. 'courseid' => new external_value(PARAM_INT, 'course id'),
  240. 'userid' => new external_value(PARAM_INT, 'user id'),
  241. 'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
  242. 'maxdepth' => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
  243. 'tabledata' => new external_multiple_structure(
  244. new external_single_structure(
  245. array(
  246. 'itemname' => new external_single_structure(
  247. array (
  248. 'class' => new external_value(PARAM_RAW, 'class'),
  249. 'colspan' => new external_value(PARAM_INT, 'col span'),
  250. 'content' => new external_value(PARAM_RAW, 'cell content'),
  251. 'celltype' => new external_value(PARAM_RAW, 'cell type'),
  252. 'id' => new external_value(PARAM_ALPHANUMEXT, 'id')
  253. ), 'The item returned data', VALUE_OPTIONAL
  254. ),
  255. 'leader' => new external_single_structure(
  256. array (
  257. 'class' => new external_value(PARAM_RAW, 'class'),
  258. 'rowspan' => new external_value(PARAM_INT, 'row span')
  259. ), 'The item returned data', VALUE_OPTIONAL
  260. ),
  261. 'weight' => new external_single_structure(
  262. self::grades_table_column(), 'weight column', VALUE_OPTIONAL
  263. ),
  264. 'grade' => new external_single_structure(
  265. self::grades_table_column(), 'grade column', VALUE_OPTIONAL
  266. ),
  267. 'range' => new external_single_structure(
  268. self::grades_table_column(), 'range column', VALUE_OPTIONAL
  269. ),
  270. 'percentage' => new external_single_structure(
  271. self::grades_table_column(), 'percentage column', VALUE_OPTIONAL
  272. ),
  273. 'lettergrade' => new external_single_structure(
  274. self::grades_table_column(), 'lettergrade column', VALUE_OPTIONAL
  275. ),
  276. 'rank' => new external_single_structure(
  277. self::grades_table_column(), 'rank column', VALUE_OPTIONAL
  278. ),
  279. 'average' => new external_single_structure(
  280. self::grades_table_column(), 'average column', VALUE_OPTIONAL
  281. ),
  282. 'feedback' => new external_single_structure(
  283. self::grades_table_column(), 'feedback column', VALUE_OPTIONAL
  284. ),
  285. 'contributiontocoursetotal' => new external_single_structure(
  286. self::grades_table_column(), 'contributiontocoursetotal column', VALUE_OPTIONAL
  287. ),
  288. ), 'table'
  289. )
  290. )
  291. )
  292. )
  293. ),
  294. 'warnings' => new external_warnings()
  295. )
  296. );
  297. }
  298. /**
  299. * Returns description of method parameters
  300. *
  301. * @return external_function_parameters
  302. * @since Moodle 2.9
  303. */
  304. public static function view_grade_report_parameters() {
  305. return new external_function_parameters(
  306. array(
  307. 'courseid' => new external_value(PARAM_INT, 'id of the course'),
  308. 'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0),
  309. )
  310. );
  311. }
  312. /**
  313. * Trigger the user report events, do the same that the web interface view of the report
  314. *
  315. * @param int $courseid id of course
  316. * @param int $userid id of the user the report belongs to
  317. * @return array of warnings and status result
  318. * @since Moodle 2.9
  319. * @throws moodle_exception
  320. */
  321. public static function view_grade_report($courseid, $userid = 0) {
  322. global $CFG, $USER;
  323. require_once($CFG->dirroot . "/grade/lib.php");
  324. require_once($CFG->dirroot . "/grade/report/user/lib.php");
  325. $params = self::validate_parameters(self::view_grade_report_parameters(),
  326. array(
  327. 'courseid' => $courseid,
  328. 'userid' => $userid
  329. ));
  330. $warnings = array();
  331. $course = get_course($params['courseid']);
  332. $context = context_course::instance($course->id);
  333. self::validate_context($context);
  334. $userid = $params['userid'];
  335. if (empty($userid)) {
  336. $userid = $USER->id;
  337. } else {
  338. $user = core_user::get_user($userid, '*', MUST_EXIST);
  339. core_user::require_active_user($user);
  340. }
  341. $access = false;
  342. if (has_capability('moodle/grade:viewall', $context)) {
  343. // Can view all course grades (any user).
  344. $access = true;
  345. } else if ($userid == $USER->id and has_capability('moodle/grade:view', $context) and $course->showgrades) {
  346. // View own grades.
  347. $access = true;
  348. }
  349. if (!$access) {
  350. throw new moodle_exception('nopermissiontoviewgrades', 'error');
  351. }
  352. // Create a report instance. We don't need the gpr second parameter.
  353. $report = new grade_report_user($course->id, null, $context, $userid);
  354. $report->viewed();
  355. $result = array();
  356. $result['status'] = true;
  357. $result['warnings'] = $warnings;
  358. return $result;
  359. }
  360. /**
  361. * Returns description of method result value
  362. *
  363. * @return external_description
  364. * @since Moodle 2.9
  365. */
  366. public static function view_grade_report_returns() {
  367. return new external_single_structure(
  368. array(
  369. 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
  370. 'warnings' => new external_warnings()
  371. )
  372. );
  373. }
  374. /**
  375. * Describes the parameters for get_grade_items.
  376. *
  377. * @return external_function_parameters
  378. * @since Moodle 3.2
  379. */
  380. public static function get_grade_items_parameters() {
  381. return self::get_grades_table_parameters();
  382. }
  383. /**
  384. * Returns the complete list of grade items for users in a course.
  385. *
  386. * @param int $courseid Course Id
  387. * @param int $userid Only this user (optional)
  388. * @param int $groupid Get users from this group only
  389. *
  390. * @return array the grades tables
  391. * @since Moodle 3.2
  392. */
  393. public static function get_grade_items($courseid, $userid = 0, $groupid = 0) {
  394. global $CFG, $USER;
  395. list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
  396. $userid = $params['userid'];
  397. // We pass userid because it can be still 0.
  398. list($gradeitems, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid, false);
  399. foreach ($gradeitems as $gradeitem) {
  400. if (isset($gradeitem['feedback']) and isset($gradeitem['feedbackformat'])) {
  401. list($gradeitem['feedback'], $gradeitem['feedbackformat']) =
  402. external_format_text($gradeitem['feedback'], $gradeitem['feedbackformat'], $context->id);
  403. }
  404. }
  405. $result = array();
  406. $result['usergrades'] = $gradeitems;
  407. $result['warnings'] = $warnings;
  408. return $result;
  409. }
  410. /**
  411. * Describes tget_grade_items return value.
  412. *
  413. * @return external_single_structure
  414. * @since Moodle 3.2
  415. */
  416. public static function get_grade_items_returns() {
  417. return new external_single_structure(
  418. array(
  419. 'usergrades' => new external_multiple_structure(
  420. new external_single_structure(
  421. array(
  422. 'courseid' => new external_value(PARAM_INT, 'course id'),
  423. 'userid' => new external_value(PARAM_INT, 'user id'),
  424. 'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
  425. 'maxdepth' => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
  426. 'gradeitems' => new external_multiple_structure(
  427. new external_single_structure(
  428. array(
  429. 'id' => new external_value(PARAM_INT, 'Grade item id'),
  430. 'itemname' => new external_value(PARAM_TEXT, 'Grade item name'),
  431. 'itemtype' => new external_value(PARAM_ALPHA, 'Grade item type'),
  432. 'itemmodule' => new external_value(PARAM_PLUGIN, 'Grade item module'),
  433. 'iteminstance' => new external_value(PARAM_INT, 'Grade item instance'),
  434. 'itemnumber' => new external_value(PARAM_INT, 'Grade item item number'),
  435. 'categoryid' => new external_value(PARAM_INT, 'Grade item category id'),
  436. 'outcomeid' => new external_value(PARAM_INT, 'Outcome id'),
  437. 'scaleid' => new external_value(PARAM_INT, 'Scale id'),
  438. 'locked' => new external_value(PARAM_BOOL, 'Grade item for user locked?', VALUE_OPTIONAL),
  439. 'cmid' => new external_value(PARAM_INT, 'Course module id (if type mod)', VALUE_OPTIONAL),
  440. 'weightraw' => new external_value(PARAM_FLOAT, 'Weight raw', VALUE_OPTIONAL),
  441. 'weightformatted' => new external_value(PARAM_NOTAGS, 'Weight', VALUE_OPTIONAL),
  442. 'status' => new external_value(PARAM_ALPHA, 'Status', VALUE_OPTIONAL),
  443. 'graderaw' => new external_value(PARAM_FLOAT, 'Grade raw', VALUE_OPTIONAL),
  444. 'gradedatesubmitted' => new external_value(PARAM_INT, 'Grade submit date', VALUE_OPTIONAL),
  445. 'gradedategraded' => new external_value(PARAM_INT, 'Grade graded date', VALUE_OPTIONAL),
  446. 'gradehiddenbydate' => new external_value(PARAM_BOOL, 'Grade hidden by date?', VALUE_OPTIONAL),
  447. 'gradeneedsupdate' => new external_value(PARAM_BOOL, 'Grade needs update?', VALUE_OPTIONAL),
  448. 'gradeishidden' => new external_value(PARAM_BOOL, 'Grade is hidden?', VALUE_OPTIONAL),
  449. 'gradeislocked' => new external_value(PARAM_BOOL, 'Grade is locked?', VALUE_OPTIONAL),
  450. 'gradeisoverridden' => new external_value(PARAM_BOOL, 'Grade overridden?', VALUE_OPTIONAL),
  451. 'gradeformatted' => new external_value(PARAM_NOTAGS, 'The grade formatted', VALUE_OPTIONAL),
  452. 'grademin' => new external_value(PARAM_FLOAT, 'Grade min', VALUE_OPTIONAL),
  453. 'grademax' => new external_value(PARAM_FLOAT, 'Grade max', VALUE_OPTIONAL),
  454. 'rangeformatted' => new external_value(PARAM_NOTAGS, 'Range formatted', VALUE_OPTIONAL),
  455. 'percentageformatted' => new external_value(PARAM_NOTAGS, 'Percentage', VALUE_OPTIONAL),
  456. 'lettergradeformatted' => new external_value(PARAM_NOTAGS, 'Letter grade', VALUE_OPTIONAL),
  457. 'rank' => new external_value(PARAM_INT, 'Rank in the course', VALUE_OPTIONAL),
  458. 'numusers' => new external_value(PARAM_INT, 'Num users in course', VALUE_OPTIONAL),
  459. 'averageformatted' => new external_value(PARAM_NOTAGS, 'Grade average', VALUE_OPTIONAL),
  460. 'feedback' => new external_value(PARAM_RAW, 'Grade feedback', VALUE_OPTIONAL),
  461. 'feedbackformat' => new external_format_value('feedback', VALUE_OPTIONAL),
  462. ), 'Grade items'
  463. )
  464. )
  465. )
  466. )
  467. ),
  468. 'warnings' => new external_warnings()
  469. )
  470. );
  471. }
  472. }