Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

GDPR for plugin developers: Difference between revisions

From MoodleDocs
(content moved from https://docs.google.com/document/d/1Y7n4Qkez4Tl83rWArOQPQCpE2NeSA2bUa8gOR2r_JFE/edit?usp=sharing - wip)
(content moved from https://docs.google.com/document/d/1Y7n4Qkez4Tl83rWArOQPQCpE2NeSA2bUa8gOR2r_JFE/edit?usp=sharing - wip)
Line 182: Line 182:
$string['privacy:metadata:core_files'] = 'The forum stores files which have been uploaded by the user to form part of a forum post.';
$string['privacy:metadata:core_files'] = 'The forum stores files which have been uploaded by the user to form part of a forum post.';
</code>
</code>
===Describing data stored in database tables===
Most Moodle plugins will store some form of user data in their own database tables.
As a plugin developer you will need to describe each database table, and each field which includes user data.
====Example====
''mod/forum/classes/privacy/provider.php''
<code php>
public static function get_metadata(collection $collection) : collection {
    $collection->add_database_table(
        'forum_discussion_subs',
        [
            'userid' => 'privacy:metadata:forum_discussion_subs:userid',
            'discussionid' => 'privacy:metadata:forum_discussion_subs:discussionid',
            'preference' => 'privacy:metadata:forum_discussion_subs:preference',
        ],
        'privacy:metadata:forum_discussion_subs'
    );
    return $collection;
}
</code>
''mod/forum/lang/en/forum.php''
<code php>
<?php
$string['privacy:metadata:forum_discussion_subs'] = 'Information about the subscriptions to individual forum discussions. This includes when a user has chosen to subscribe to a discussion, or to unsubscribe from one where they would otherwise be subscribed.';
$string['privacy:metadata:forum_discussion_subs:userid'] = 'The ID of the user with this subscription preference.';
$string['privacy:metadata:forum_discussion_subs:discussionid'] = 'The ID of the discussion that was subscribed to.';
$string['privacy:metadata:forum_discussion_subs:preference'] = 'The start time of the subscription.';
</code>
===Indicating that you store site-wide user preferences===
Many plugins will include one or more user preferences. Unfortunately this is one of Moodle’s older components and many of the values stored are not pure user preferences. Each plugin should be aware of how it handles its own preferences and is best placed to determine whether they are site-wide preferences, or per-instance preferences.
Whilst most of these will have a fixed name (e.g. ''filepicker_recentrepository''), some will include a variable of some kind (e.g. ''tool_usertours_tour_completion_time_2''). Only the general name needs to be indicated rather than one copy for each preference.
Also, these should only be ''site-wide'' user preferences which do not belong to a specific Moodle context.
In the above examples:
* Preference ''filepicker_recentrepository'' belongs to the file subsystem, and is a site-wide preference affecting the user anywhere that they view the filepicker.
* Preference ''tool_usertours_tour_completion_time_2'' belongs to user tours. User tours are a site-wide feature which can affect many parts of Moodle and cross multiple contexts.
In some cases a value may be stored in the preferences table but is known to belong to a specific context within Moodle. In these cases they should be stored as metadata against that context rather than as a site-wide user preference.
You can indicate this by calling the ''add_user_preference()'' method on the ''collection''.
Any plugin providing user preferences must also implement the ''\core_privacy\local\request\preference_provider''.
====Example====
''admin/tool/usertours/classes/privacy/provider.php''
<code php>
public static function get_metadata(collection $collection) : collection {
    $collection->add_user_preference('tool_usertours_tour_completion_time,
        'privacy:metadata:preference:tool_usertours_tour_completion_time');
    return $collection;
}
</code>
''admin/tool/usertours/lang/en/tool_usertours.php''
<code php>
<?php
$string['privacy:metadata:tool_usertours_tour_completion_time'] = 'The time that a specific user tour was last completed by a user.';
</code>





Revision as of 05:19, 26 March 2018

Personal data in Moodle

From the GDPR Spec, Article 4:

‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person;

In Moodle, we need to consider two main types of personal data; information entered by the user and information stored about the user. The key difference being that information stored about the user will have come from a source other than the user themselves. Both types of data can be used to form a profile of the individual.

The most obvious clue to finding personal data entered by the user is the presence of a userid on a database field. Any data on the record (or linked records) pertaining to that user may be deemed personal data for that user, including things like timestamps and record identification numbers. Additionally, any free text field which allows the user to enter information must also be considered to be the personal data of that user.

Data stored about the user includes things like ratings and comments made on a student submission. These may have been made by an assessor or teacher, but are considered the personal data of the student, as they are considered a reflection of the user’s competency in the subject matter and can be used to form a profile of that individual.

The sections that follow outline what you need to do as a plugin developer to ensure any personal data is advertised and can be accessed and deleted according to the GDPR requirements.

Background

Architecture overview

A new system for Privacy has been created within Moodle. This is broken down into several main parts and forms the core_privacy subsystem:

  • Some metadata providers - a set of PHP interfaces to be implemented by components for that component to describe the kind of data that it stores, and the purpose for its storage;
  • Some request providers - a set of PHP interfaces to be implemented by components to allow that component to act upon user requests such as the Right to be Forgotten, and a Subject Access Request; and
  • A manager - a concrete class used to bridge components which implement the providers with tools which request their data.

All plugins will implement one metadata provider, and zero, one or two request providers.

The fetching of data is broken into two separate steps:

  1. Detecting in which Moodle contexts the user has any data; and
  2. Exporting all data from each of those contexts.

This has been broken into two steps to later allow administrators to exclude certain contexts from an export - e.g. for courses currently in progress.

A third component will later be added to facilitate the deletion of data within these contexts which will help to satisfy the Right to be Forgotten. This will also use the first step.

Implementing a provider

All plugins will need to create a concrete class which implements the relevant metadata and request providers. The exact providers you need to implement will depend on what data you store, and the type of plugin. This is covered in more detail in the following sections of the document.

In order to do so:

  1. You must create a class called provider within the namespace \your_pluginname\privacy.
  2. This class must be created at path/to/your/plugin/classes/privacy/provider.php.
  3. You must have your class implement the relevant metadata and request interfaces.

Plugins which do not store personal data

Many Moodle plugins do not store any personal data. This is usually the case for plugins which just add functionality, or which display the data already stored elsewhere in Moodle.

Some examples of plugin types which might fit this criteria include themes, blocks, filters, editor plugins, etc.

Plugins which cause data to be stored elsewhere in Moodle (e.g. via a subsystem call) are considered to store data.

One examples of a plugin which does not store any data would be the Calendar month block which just displays a view of the user’s calendar. It does not store any data itself.

An example of a plugin which must not use the null provider is the Comments block. The comments block is responsible for data subsequently being stored within Moodle. Although the block doesn’t store anything itself, it interacts with the comments subsystem and is the only component which knows how that data maps to a user.

Implementation requirements

In order to let Moodle know that you have audited your plugin, and that you do not store any personal user data, you must implement the \core_privacy\local\metadata\null_provider interface in your plugin’s provider.

The null_provider requires you to define one function get_reason() which returns the language string identifier within your component.

Example

block/calendar_month/classes/privacy/provider.php

<?php

// …

namespace block_calendar_month\privacy;

class provider implements

   # This plugin does not store any personal user data.
   \core_privacy\local\metadata\null_provider

{

   /**
    * Get the language string identifier with the component's language
    * file to explain why this plugin stores no data.
    *
    * @return  string
    */
   public static function get_reason() : string {
       return 'privacy:null_reason';
   }

}

block/calendar_month/lang/en/block_calendar_month.php

<?php

$string['privacy:null_reason'] = 'The calendar month block displays information from the Calendar, but does not effect or store any data itself. All changes are made via the Calendar.';

That’s it. Congratulations, your plugin now implements the Privacy API.

Plugins which store personal data

Many Moodle plugins do store some form of personal data.

In some cases this will be stored within database tables in your plugin, and in other cases this will be in one of Moodle’s core subsystems - for example your plugin may store files, ratings, comments, or tags.

Plugins which do store data will need to:

  • Describe the type of data that they store;
  • Provide a way to export that data; and
  • Provide a way to delete that data.

Data is described via a metadata provider, and it is both exported and deleted via an implementation of a request provider.

These are both explained in the sections below.

Describing the type of data you store

In order to describe the type of data that you store, you must implement the \core_privacy\local\metadata\provider interface.

This interfaces requires that you define one function: get_metadata.

There are several types of item to describe the data that you store. These are for:

  • Items in the Moodle database;
  • Items stored by you in a Moodle subsystem - for example files, and ratings; and
  • User preferences stored site-wide within Moodle for your plugin

Note: All fields should include a description from a language string within your plugin.

Example

mod/forum/classes/privacy/provider.php

<?php // …

namespace mod_forum\privacy; use \core_privacy\local\metadata\collection;

class provider implements

   # This plugin does store personal user data.
   \core_privacy\local\metadata\provider

{

   public static function get_metadata(collection $collection) : collection {
       return $collection;
   }

}

Indicating that you store content in a Moodle subsystem

Many plugins will use one of the core Moodle subsystems to store data.

As a plugin developer we do not expect you to describe those subsystems in detail, but we do need to know that you use them and to know what you use them for.

You can indicate this by calling the link_subsystem() method on the collection.

Example

mod/forum/classes/privacy/provider.php

public static function get_metadata(collection $collection) : collection {

   $collection->link_subsystem(
       'core_files',
       'privacy:metadata:core_files'
   );
   return $collection;

}

mod/forum/lang/en/forum.php

<?php

$string['privacy:metadata:core_files'] = 'The forum stores files which have been uploaded by the user to form part of a forum post.';

Describing data stored in database tables

Most Moodle plugins will store some form of user data in their own database tables.

As a plugin developer you will need to describe each database table, and each field which includes user data.

Example

mod/forum/classes/privacy/provider.php

public static function get_metadata(collection $collection) : collection {

   $collection->add_database_table(
       'forum_discussion_subs',
        [
           'userid' => 'privacy:metadata:forum_discussion_subs:userid',
           'discussionid' => 'privacy:metadata:forum_discussion_subs:discussionid',
           'preference' => 'privacy:metadata:forum_discussion_subs:preference',
        ],
       'privacy:metadata:forum_discussion_subs'
   );
   return $collection;

}

mod/forum/lang/en/forum.php

<?php

$string['privacy:metadata:forum_discussion_subs'] = 'Information about the subscriptions to individual forum discussions. This includes when a user has chosen to subscribe to a discussion, or to unsubscribe from one where they would otherwise be subscribed.'; $string['privacy:metadata:forum_discussion_subs:userid'] = 'The ID of the user with this subscription preference.'; $string['privacy:metadata:forum_discussion_subs:discussionid'] = 'The ID of the discussion that was subscribed to.'; $string['privacy:metadata:forum_discussion_subs:preference'] = 'The start time of the subscription.';

Indicating that you store site-wide user preferences

Many plugins will include one or more user preferences. Unfortunately this is one of Moodle’s older components and many of the values stored are not pure user preferences. Each plugin should be aware of how it handles its own preferences and is best placed to determine whether they are site-wide preferences, or per-instance preferences.

Whilst most of these will have a fixed name (e.g. filepicker_recentrepository), some will include a variable of some kind (e.g. tool_usertours_tour_completion_time_2). Only the general name needs to be indicated rather than one copy for each preference.

Also, these should only be site-wide user preferences which do not belong to a specific Moodle context.

In the above examples:

  • Preference filepicker_recentrepository belongs to the file subsystem, and is a site-wide preference affecting the user anywhere that they view the filepicker.
  • Preference tool_usertours_tour_completion_time_2 belongs to user tours. User tours are a site-wide feature which can affect many parts of Moodle and cross multiple contexts.

In some cases a value may be stored in the preferences table but is known to belong to a specific context within Moodle. In these cases they should be stored as metadata against that context rather than as a site-wide user preference.

You can indicate this by calling the add_user_preference() method on the collection.

Any plugin providing user preferences must also implement the \core_privacy\local\request\preference_provider.

Example

admin/tool/usertours/classes/privacy/provider.php

public static function get_metadata(collection $collection) : collection {

   $collection->add_user_preference('tool_usertours_tour_completion_time,
       'privacy:metadata:preference:tool_usertours_tour_completion_time');
   return $collection;

}

admin/tool/usertours/lang/en/tool_usertours.php

<?php

$string['privacy:metadata:tool_usertours_tour_completion_time'] = 'The time that a specific user tour was last completed by a user.';




See also