Merge branch 'MDL-63116-master-1' of git://github.com/mihailges/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 18 Sep 2018 21:26:51 +0000 (23:26 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 18 Sep 2018 21:26:51 +0000 (23:26 +0200)
1  2 
admin/tool/dataprivacy/classes/api.php
admin/tool/dataprivacy/classes/external.php
admin/tool/dataprivacy/db/services.php
admin/tool/dataprivacy/lang/en/tool_dataprivacy.php
admin/tool/dataprivacy/tests/external_test.php
admin/tool/dataprivacy/version.php

@@@ -227,7 -224,8 +232,9 @@@ $string['requestdenied'] = 'The reques
  $string['requestemailintro'] = 'You have received a data request:';
  $string['requestfor'] = 'Requesting for';
  $string['requestmarkedcomplete'] = 'The request has been marked as complete';
 +$string['requestorigin'] = 'Request origin';
+ $string['requestsapproved'] = 'The requests have been approved';
+ $string['requestsdenied'] = 'The requests have been denied';
  $string['requeststatus'] = 'Status';
  $string['requestsubmitted'] = 'Your request has been submitted to the privacy officer';
  $string['requesttype'] = 'Type';
@@@ -284,280 -283,105 +284,382 @@@ class tool_dataprivacy_external_testcas
          external::get_data_request($this->requestid + 1);
      }
  
 +    /**
 +     * Test for \tool_dataprivacy\external::set_context_defaults()
 +     * when called by a user that doesn't have the manage registry capability.
 +     */
 +    public function test_set_context_defaults_no_capability() {
 +        $generator = $this->getDataGenerator();
 +        $user = $generator->create_user();
 +        $this->setUser($user);
 +        $this->expectException(required_capability_exception::class);
 +        external::set_context_defaults(CONTEXT_COURSECAT, context_instance::INHERIT, context_instance::INHERIT, '', false);
 +    }
 +
 +    /**
 +     * Test for \tool_dataprivacy\external::set_context_defaults().
 +     *
 +     * We're just checking the module context level here to test the WS function.
 +     * More testing is done in \tool_dataprivacy_api_testcase::test_set_context_defaults().
 +     *
 +     * @dataProvider get_options_provider
 +     * @param bool $modulelevel Whether defaults are to be applied on the module context level or for an activity only.
 +     * @param bool $override Whether to override instances.
 +     */
 +    public function test_set_context_defaults($modulelevel, $override) {
 +        $this->setAdminUser();
 +        $generator = $this->getDataGenerator();
 +
 +        // Generate course cat, course, block, assignment, forum instances.
 +        $coursecat = $generator->create_category();
 +        $course = $generator->create_course(['category' => $coursecat->id]);
 +        $assign = $generator->create_module('assign', ['course' => $course->id]);
 +        list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign');
 +        $assigncontext = context_module::instance($assigncm->id);
 +
 +        // Generate purpose and category.
 +        $category1 = api::create_category((object)['name' => 'Test category 1']);
 +        $category2 = api::create_category((object)['name' => 'Test category 2']);
 +        $purpose1 = api::create_purpose((object)[
 +            'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
 +        ]);
 +        $purpose2 = api::create_purpose((object)[
 +            'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
 +        ]);
 +
 +        // Set a custom purpose and ID for this assignment instance.
 +        $assignctxinstance = api::set_context_instance((object) [
 +            'contextid' => $assigncontext->id,
 +            'purposeid' => $purpose1->get('id'),
 +            'categoryid' => $category1->get('id'),
 +        ]);
 +
 +        $modulename = $modulelevel ? 'assign' : '';
 +        $categoryid = $category2->get('id');
 +        $purposeid = $purpose2->get('id');
 +        $result = external::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, $modulename, $override);
 +
 +        // Extract the result.
 +        $return = external_api::clean_returnvalue(external::set_context_defaults_returns(), $result);
 +        $this->assertTrue($return['result']);
 +
 +        // Check the assignment context instance.
 +        $instanceexists = context_instance::record_exists($assignctxinstance->get('id'));
 +        if ($override) {
 +            // The custom assign instance should have been deleted.
 +            $this->assertFalse($instanceexists);
 +        } else {
 +            // The custom assign instance should still exist.
 +            $this->assertTrue($instanceexists);
 +        }
 +
 +        // Check the saved defaults.
 +        list($savedpurpose, $savedcategory) = \tool_dataprivacy\data_registry::get_defaults(CONTEXT_MODULE, $modulename);
 +        $this->assertEquals($categoryid, $savedcategory);
 +        $this->assertEquals($purposeid, $savedpurpose);
 +    }
 +
 +    /**
 +     * Test for \tool_dataprivacy\external::get_category_options()
 +     * when called by a user that doesn't have the manage registry capability.
 +     */
 +    public function test_get_category_options_no_capability() {
 +        $generator = $this->getDataGenerator();
 +        $user = $generator->create_user();
 +        $this->setUser($user);
 +        $this->expectException(required_capability_exception::class);
 +        external::get_category_options(true, true);
 +    }
 +
 +    /**
 +     * Data provider for \tool_dataprivacy_external_testcase::test_XX_options().
 +     */
 +    public function get_options_provider() {
 +        return [
 +            [false, false],
 +            [false, true],
 +            [true, false],
 +            [true, true],
 +        ];
 +    }
 +
 +    /**
 +     * Test for \tool_dataprivacy\external::get_category_options().
 +     *
 +     * @dataProvider get_options_provider
 +     * @param bool $includeinherit Whether "Inherit" would be included to the options.
 +     * @param bool $includenotset Whether "Not set" would be included to the options.
 +     */
 +    public function test_get_category_options($includeinherit, $includenotset) {
 +        $this->setAdminUser();
 +
 +        // Prepare our expected options.
 +        $expectedoptions = [];
 +        if ($includeinherit) {
 +            $expectedoptions[] = [
 +                'id' => context_instance::INHERIT,
 +                'name' => get_string('inherit', 'tool_dataprivacy'),
 +            ];
 +        }
 +
 +        if ($includenotset) {
 +            $expectedoptions[] = [
 +                'id' => context_instance::NOTSET,
 +                'name' => get_string('notset', 'tool_dataprivacy'),
 +            ];
 +        }
 +
 +        for ($i = 1; $i <= 3; $i++) {
 +            $category = api::create_category((object)['name' => 'Category ' . $i]);
 +            $expectedoptions[] = [
 +                'id' => $category->get('id'),
 +                'name' => $category->get('name'),
 +            ];
 +        }
 +
 +        // Call the WS function.
 +        $result = external::get_category_options($includeinherit, $includenotset);
 +
 +        // Extract the options.
 +        $return = (object) external_api::clean_returnvalue(external::get_category_options_returns(), $result);
 +        $options = $return->options;
 +
 +        // Make sure everything checks out.
 +        $this->assertCount(count($expectedoptions), $options);
 +        foreach ($options as $option) {
 +            $this->assertContains($option, $expectedoptions);
 +        }
 +    }
 +
 +    /**
 +     * Test for \tool_dataprivacy\external::get_purpose_options()
 +     * when called by a user that doesn't have the manage registry capability.
 +     */
 +    public function test_get_purpose_options_no_capability() {
 +        $generator = $this->getDataGenerator();
 +        $user = $generator->create_user();
 +        $this->setUser($user);
 +        $this->expectException(required_capability_exception::class);
 +        external::get_category_options(true, true);
 +    }
 +
 +    /**
 +     * Test for \tool_dataprivacy\external::get_purpose_options().
 +     *
 +     * @dataProvider get_options_provider
 +     * @param bool $includeinherit Whether "Inherit" would be included to the options.
 +     * @param bool $includenotset Whether "Not set" would be included to the options.
 +     */
 +    public function test_get_purpose_options($includeinherit, $includenotset) {
 +        $this->setAdminUser();
 +
 +        // Prepare our expected options.
 +        $expectedoptions = [];
 +        if ($includeinherit) {
 +            $expectedoptions[] = [
 +                'id' => context_instance::INHERIT,
 +                'name' => get_string('inherit', 'tool_dataprivacy'),
 +            ];
 +        }
 +
 +        if ($includenotset) {
 +            $expectedoptions[] = [
 +                'id' => context_instance::NOTSET,
 +                'name' => get_string('notset', 'tool_dataprivacy'),
 +            ];
 +        }
 +
 +        for ($i = 1; $i <= 3; $i++) {
 +            $purpose = api::create_purpose((object)[
 +                'name' => 'Purpose ' . $i, 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
 +            ]);
 +            $expectedoptions[] = [
 +                'id' => $purpose->get('id'),
 +                'name' => $purpose->get('name'),
 +            ];
 +        }
 +
 +        // Call the WS function.
 +        $result = external::get_purpose_options($includeinherit, $includenotset);
 +
 +        // Extract the options.
 +        $return = (object) external_api::clean_returnvalue(external::get_purpose_options_returns(), $result);
 +        $options = $return->options;
 +
 +        // Make sure everything checks out.
 +        $this->assertCount(count($expectedoptions), $options);
 +        foreach ($options as $option) {
 +            $this->assertContains($option, $expectedoptions);
 +        }
 +    }
 +
 +    /**
 +     * Data provider for \tool_dataprivacy_external_testcase::get_activity_options().
 +     */
 +    public function get_activity_options_provider() {
 +        return [
 +            [false, false, true],
 +            [false, true, true],
 +            [true, false, true],
 +            [true, true, true],
 +            [false, false, false],
 +            [false, true, false],
 +            [true, false, false],
 +            [true, true, false],
 +        ];
 +    }
 +
 +    /**
 +     * Test for \tool_dataprivacy\external::get_activity_options().
 +     *
 +     * @dataProvider get_activity_options_provider
 +     * @param bool $inheritcategory Whether the category would be set to "Inherit".
 +     * @param bool $inheritpurpose Whether the purpose would be set to "Inherit".
 +     * @param bool $nodefaults Whether to fetch only activities that don't have defaults.
 +     */
 +    public function test_get_activity_options($inheritcategory, $inheritpurpose, $nodefaults) {
 +        $this->setAdminUser();
 +
 +        $category = api::create_category((object)['name' => 'Test category']);
 +        $purpose = api::create_purpose((object)[
 +            'name' => 'Test purpose ', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a'
 +        ]);
 +        $categoryid = $category->get('id');
 +        $purposeid = $purpose->get('id');
 +
 +        if ($inheritcategory) {
 +            $categoryid = context_instance::INHERIT;
 +        }
 +        if ($inheritpurpose) {
 +            $purposeid = context_instance::INHERIT;
 +        }
 +
 +        // Set the context default for the assignment module.
 +        api::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, 'assign');
 +
 +        // Call the WS function.
 +        $result = external::get_activity_options($nodefaults);
 +
 +        // Extract the options.
 +        $return = (object) external_api::clean_returnvalue(external::get_activity_options_returns(), $result);
 +        $options = $return->options;
 +
 +        // Make sure the options list is not empty.
 +        $this->assertNotEmpty($options);
 +
 +        $pluginwithdefaults = [
 +            'name' => 'assign',
 +            'displayname' => get_string('pluginname', 'assign')
 +        ];
 +
 +        // If we don't want plugins with defaults to be listed or if both of the category and purpose are set to inherit,
 +        // the assign module should be listed.
 +        if (!$nodefaults || ($inheritcategory && $inheritpurpose)) {
 +            $this->assertContains($pluginwithdefaults, $options);
 +        } else {
 +            $this->assertNotContains($pluginwithdefaults, $options);
 +        }
 +    }
++
+     /**
+      * Test for external::bulk_approve_data_requests().
+      */
+     public function test_bulk_approve_data_requests() {
+         $generator = new testing_data_generator();
+         $requester1 = $generator->create_user();
+         $comment1 = 'sample comment';
+         // Login as requester2.
+         $this->setUser($requester1->id);
+         // Create delete data request.
+         $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, $comment1);
+         $requestid1 = $datarequest1->get('id');
+         $requestid2 = $this->requestid;
+         $this->setAdminUser();
+         api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         $result = external::bulk_approve_data_requests([$requestid1, $requestid2]);
+         $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result);
+         $this->assertTrue($return->result);
+         $this->assertEmpty($return->warnings);
+     }
+     /**
+      * Test for external::bulk_approve_data_requests() for a non-existent request ID.
+      */
+     public function test_bulk_approve_data_requests_non_existent() {
+         $generator = new testing_data_generator();
+         $requester1 = $generator->create_user();
+         $comment1 = 'sample comment';
+         // Login as requester2.
+         $this->setUser($requester1->id);
+         // Create delete data request.
+         $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, $comment1);
+         $requestid1 = $datarequest1->get('id');
+         $requestid2 = $this->requestid;
+         $this->setAdminUser();
+         api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         $result = external::bulk_approve_data_requests([$requestid1 + 1, $requestid2]);
+         $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result);
+         $this->assertFalse($return->result);
+         $this->assertCount(1, $return->warnings);
+         $warning = reset($return->warnings);
+         $this->assertEquals('errorrequestnotfound', $warning['warningcode']);
+         $this->assertEquals($requestid1 + 1, $warning['item']);
+     }
+     /**
+      * Test for external::bulk_deny_data_requests().
+      */
+     public function test_bulk_deny_data_requests() {
+         $generator = new testing_data_generator();
+         $requester1 = $generator->create_user();
+         $comment1 = 'sample comment';
+         // Login as requester2.
+         $this->setUser($requester1->id);
+         // Create delete data request.
+         $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, $comment1);
+         $requestid1 = $datarequest1->get('id');
+         $requestid2 = $this->requestid;
+         $this->setAdminUser();
+         api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         $result = external::bulk_deny_data_requests([$requestid1, $requestid2]);
+         $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result);
+         $this->assertTrue($return->result);
+         $this->assertEmpty($return->warnings);
+     }
+     /**
+      * Test for external::bulk_deny_data_requests() for a non-existent request ID.
+      */
+     public function test_bulk_deny_data_requests_non_existent() {
+         $generator = new testing_data_generator();
+         $requester1 = $generator->create_user();
+         $comment1 = 'sample comment';
+         // Login as requester2.
+         $this->setUser($requester1->id);
+         // Create delete data request.
+         $datarequest1 = api::create_data_request($requester1->id, api::DATAREQUEST_TYPE_DELETE, $comment1);
+         $requestid1 = $datarequest1->get('id');
+         $requestid2 = $this->requestid;
+         $this->setAdminUser();
+         api::update_request_status($requestid1, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         api::update_request_status($requestid2, api::DATAREQUEST_STATUS_AWAITING_APPROVAL);
+         $result = external::bulk_deny_data_requests([$requestid1 + 1, $requestid2]);
+         $return = (object) external_api::clean_returnvalue(external::bulk_approve_data_requests_returns(), $result);
+         $this->assertFalse($return->result);
+         $this->assertCount(1, $return->warnings);
+         $warning = reset($return->warnings);
+         $this->assertEquals('errorrequestnotfound', $warning['warningcode']);
+         $this->assertEquals($requestid1 + 1, $warning['item']);
+     }
  }
@@@ -24,6 -24,6 +24,6 @@@
  
  defined('MOODLE_INTERNAL') || die;
  
- $plugin->version   = 2018091000;
 -$plugin->version   = 2018082101;
++$plugin->version   = 2018091100;
  $plugin->requires  = 2018050800;        // Moodle 3.5dev (Build 2018031600) and upwards.
  $plugin->component = 'tool_dataprivacy';