MDL-62060 core_privacy: Make sure the exported json is human readable
authorShamim Rezaie <shamim@moodle.com>
Sun, 22 Apr 2018 18:45:50 +0000 (04:45 +1000)
committerShamim Rezaie <shamim@moodle.com>
Tue, 1 May 2018 02:35:00 +0000 (12:35 +1000)
privacy/classes/local/request/moodle_content_writer.php
privacy/tests/moodle_content_writer_test.php

index 8e77256..de607cc 100644 (file)
@@ -79,11 +79,12 @@ class moodle_content_writer implements content_writer {
      *
      * @param   array           $subcontext The location within the current context that this data belongs.
      * @param   \stdClass       $data       The data to be exported
+     * @return  content_writer
      */
     public function export_data(array $subcontext, \stdClass $data) : content_writer {
         $path = $this->get_path($subcontext, 'data.json');
 
-        $this->write_data($path, json_encode($data));
+        $this->write_data($path, json_encode($data, JSON_UNESCAPED_UNICODE));
 
         return $this;
     }
@@ -97,6 +98,7 @@ class moodle_content_writer implements content_writer {
      * @param   string          $key        The metadata name.
      * @param   string          $value      The metadata value.
      * @param   string          $description    The description of the value.
+     * @return  content_writer
      */
     public function export_metadata(array $subcontext, string $key, $value, string $description) : content_writer {
         $path = $this->get_full_path($subcontext, 'metadata.json');
@@ -113,7 +115,7 @@ class moodle_content_writer implements content_writer {
         ];
 
         $path = $this->get_path($subcontext, 'metadata.json');
-        $this->write_data($path, json_encode($data));
+        $this->write_data($path, json_encode($data, JSON_UNESCAPED_UNICODE));
 
         return $this;
     }
@@ -124,11 +126,12 @@ class moodle_content_writer implements content_writer {
      * @param   array           $subcontext The location within the current context that this data belongs.
      * @param   string          $name       The name of the file to be exported.
      * @param   \stdClass       $data       The related data to export.
+     * @return  content_writer
      */
     public function export_related_data(array $subcontext, $name, $data) : content_writer {
         $path = $this->get_path($subcontext, "{$name}.json");
 
-        $this->write_data($path, json_encode($data));
+        $this->write_data($path, json_encode($data, JSON_UNESCAPED_UNICODE));
 
         return $this;
     }
@@ -227,7 +230,7 @@ class moodle_content_writer implements content_writer {
             'value' => $value,
             'description' => $description,
         ];
-        $this->write_data($path, json_encode($data));
+        $this->write_data($path, json_encode($data, JSON_UNESCAPED_UNICODE));
 
         return $this;
     }
index f919bfd..b683348 100644 (file)
@@ -417,6 +417,8 @@ class moodle_content_writer_test extends advanced_testcase {
      * Exporting a single stored_file should cause that file to be output in the files directory.
      *
      * @dataProvider    export_file_provider
+     * @param   string  $filearea File area
+     * @param   int     $itemid Item ID
      * @param   string  $filepath File path
      * @param   string  $filename File name
      * @param   string  $content Content
@@ -794,6 +796,123 @@ class moodle_content_writer_test extends advanced_testcase {
         ];
     }
 
+    /**
+     * Test that exported data is human readable.
+     *
+     * @dataProvider unescaped_unicode_export_provider
+     * @param string $text
+     */
+    public function test_export_data_unescaped_unicode($text) {
+        $context = \context_system::instance();
+        $subcontext = [];
+        $data = (object) ['key' => $text];
+
+        $writer = $this->get_writer_instance()
+                ->set_context($context)
+                ->export_data($subcontext, $data);
+
+        $fileroot = $this->fetch_exported_content($writer);
+
+        $contextpath = $this->get_context_path($context, $subcontext, 'data.json');
+
+        $json = $fileroot->getChild($contextpath)->getContent();
+        $this->assertRegExp("/$text/", $json);
+
+        $expanded = json_decode($json);
+        $this->assertEquals($data, $expanded);
+    }
+
+    /**
+     * Test that exported metadata is human readable.
+     *
+     * @dataProvider unescaped_unicode_export_provider
+     * @param string $text
+     */
+    public function test_export_metadata_unescaped_unicode($text) {
+        $context = \context_system::instance();
+        $subcontext = ['a', 'b', 'c'];
+
+        $writer = $this->get_writer_instance()
+                ->set_context($context)
+                ->export_metadata($subcontext, $text, $text, $text);
+
+        $fileroot = $this->fetch_exported_content($writer);
+
+        $contextpath = $this->get_context_path($context, $subcontext, 'metadata.json');
+
+        $json = $fileroot->getChild($contextpath)->getContent();
+        $this->assertRegExp("/$text.*$text.*$text/", $json);
+
+        $expanded = json_decode($json);
+        $this->assertTrue(isset($expanded->$text));
+        $this->assertEquals($text, $expanded->$text->value);
+        $this->assertEquals($text, $expanded->$text->description);
+    }
+
+    /**
+     * Test that exported related data is human readable.
+     *
+     * @dataProvider unescaped_unicode_export_provider
+     * @param string $text
+     */
+    public function test_export_related_data_unescaped_unicode($text) {
+        $context = \context_system::instance();
+        $subcontext = [];
+        $data = (object) ['key' => $text];
+
+        $writer = $this->get_writer_instance()
+                ->set_context($context)
+                ->export_related_data($subcontext, 'name', $data);
+
+        $fileroot = $this->fetch_exported_content($writer);
+
+        $contextpath = $this->get_context_path($context, $subcontext, 'name.json');
+
+        $json = $fileroot->getChild($contextpath)->getContent();
+        $this->assertRegExp("/$text/", $json);
+
+        $expanded = json_decode($json);
+        $this->assertEquals($data, $expanded);
+    }
+
+    /**
+     * Test that exported user preference is human readable.
+     *
+     * @dataProvider unescaped_unicode_export_provider
+     * @param string $text
+     */
+    public function test_export_user_preference_unescaped_unicode($text) {
+        $context = \context_system::instance();
+        $component = 'core_privacy';
+
+        $writer = $this->get_writer_instance()
+                ->set_context($context)
+                ->export_user_preference($component, $text, $text, $text);
+
+        $fileroot = $this->fetch_exported_content($writer);
+
+        $contextpath = $this->get_context_path($context, [get_string('userpreferences')], "{$component}.json");
+
+        $json = $fileroot->getChild($contextpath)->getContent();
+        $this->assertRegExp("/$text.*$text.*$text/", $json);
+
+        $expanded = json_decode($json);
+        $this->assertTrue(isset($expanded->$text));
+        $this->assertEquals($text, $expanded->$text->value);
+        $this->assertEquals($text, $expanded->$text->description);
+    }
+
+    /**
+     * Provider for various user preferences.
+     *
+     * @return array
+     */
+    public function unescaped_unicode_export_provider() {
+        return [
+            'Unicode' => ['ةكءيٓ‌پچژکگیٹڈڑہھےâîûğŞAaÇÖáǽ你好!'],
+        ];
+    }
+
     /**
      * Get a fresh content writer.
      *