Added feature to allow exporting and mass-deleting userdata

This commit is contained in:
Garvin Hicking 2018-04-23 12:03:55 +02:00
parent 7e8ad5365a
commit cf5f4f1430
3 changed files with 137 additions and 2 deletions

View file

@ -1 +1,2 @@
1.0.5: Added ability to export and/or remove comments made by users to comply with the Auskunftsgesuch
1.0.3: Added ability to make themes provide a "legal.txt" with information, and a hard-coded internal array that yields information

View file

@ -122,3 +122,7 @@ Certain plugins can use the session cookie to store additional temporary data.</
@define('PLUGIN_EVENT_DSGVO_GDPR_ANONYMIZE', 'Anonymize IPs?');
@define('PLUGIN_EVENT_DSGVO_GDPR_ANONYMIZE_DESC', 'If enabled, the last parts of the IP address (ipv4 and ipv6) will be replaced with "0". This means, all places where serendipity saves or utilizes the IP address of the visitor (also for anti-spam methods) the recorded IP will not be the actual IP of the user. In case of abuse, you will not be able to tell the actual IP used for a comment, for example.');
@define('PLUGIN_EVENT_DSGVO_GDPR_BACKEND', 'Manage user data');
@define('PLUGIN_EVENT_DSGVO_GDPR_BACKEND_INFO', 'Here you can enter an exactly matching username or e-mail address to remove or export data for that user. You can separate multiple names with a newline.');
@define('PLUGIN_EVENT_DSGVO_GDPR_BACKEND_DELFAIL', 'To export or delete data you must specify at least one username or e-mail address.');

View file

@ -23,7 +23,7 @@ class serendipity_event_dsgvo_gdpr extends serendipity_event
$propbag->add('description', PLUGIN_EVENT_DSGVO_GDPR_DESC);
$propbag->add('stackable', false);
$propbag->add('author', 'Serendipity Team');
$propbag->add('version', '1.0.4');
$propbag->add('version', '1.0.5');
$propbag->add('requirements', array(
'serendipity' => '2.0',
'smarty' => '2.6.7',
@ -39,7 +39,10 @@ class serendipity_event_dsgvo_gdpr extends serendipity_event
'genpage' => true,
'frontend_footer' => true,
'frontend_configure' => true,
'css' => true
'css' => true,
'backend_sidebar_admin' => true,
'backend_sidebar_entries_event_display_dsgvo' => true,
'backend_deletecomment' => true
)
);
@ -335,6 +338,113 @@ class serendipity_event_dsgvo_gdpr extends serendipity_event
return false;
}
function parseParts($string) {
$out = array();
$parts = explode("\n", $string);
foreach($parts AS $part) {
$part = trim($part);
if (empty($part)) continue;
$out[] = "'" . serendipity_db_escape_string($part) . "'";
}
return $out;
}
function showBackend() {
global $serendipity;
if ($serendipity['serendipityUserlevel'] < USERLEVEL_ADMIN) {
return false;
}
$clist = array();
if (isset($serendipity['POST']['delete']) || isset($serendipity['POST']['export'])) {
$author_list = $this->parseParts($serendipity['POST']['filter']['author']);
$email_list = $this->parseParts($serendipity['POST']['filter']['email']);
if (count($author_list) == 0 && count($email_list) == 0) {
echo '<p>' . PLUGIN_EVENT_DSGVO_GDPR_BACKEND_DELFAIL . '</p>';
} else {
$where = array();
if (count($author_list) > 0) {
$where[] = 'author IN (' . implode(', ', $author_list) . ')';
}
if (count($email_list) > 0) {
$where[] = 'email IN (' . implode(', ', $email_list) . ')';
}
$clist = serendipity_db_query("SELECT *
FROM {$serendipity['dbPrefix']}comments
WHERE " . implode(' OR ', $where), false, 'assoc');
}
if (!is_array($clist) || count($clist) == 0) {
echo '<p>' . NO_COMMENTS . '</p>';
} else {
if (isset($serendipity['POST']['delete'])) {
foreach($clist AS $comment) {
echo '<p>' . sprintf(COMMENT_DELETED, $comment['id']) . '</p>';
serendipity_deleteComment($comment['id'], $comment['entry_id']);
}
}
if (isset($serendipity['POST']['export'])) {
header('Content-Type: application/csv; charset=' . LANG_CHARSET);
header('Content-Disposition: attachment; filename=blog-userData.csv');
header('Pragma: no-cache');
echo '#';
foreach($clist[0] AS $key => $val) {
echo '"' . $key . '";';
}
echo "\n";
foreach($clist AS $comment) {
foreach($comment AS $key => $val) {
echo '"' . $val . '";';
}
echo "\n";
}
}
}
}
echo '<form action="?" method="post">';
echo serendipity_setFormToken();
echo '<input type="hidden" name="serendipity[adminModule]" value="event_display" />';
echo '<input type="hidden" name="serendipity[adminAction]" value="dsgvo" />';
echo '<p>' . PLUGIN_EVENT_DSGVO_GDPR_BACKEND_INFO . '</p>';
?>
<fieldset id="filter_dsgvo" class="filter_pane">
<legend class="visuallyhidden"><?php echo PLUGIN_EVENT_DSGVO_GDPR_BACKEND; ?></legend>
<div class="clearfix inputs">
<div class="form_field">
<label for="filter_author"><?php echo AUTHOR; ?></label>
<textarea id="filter_author" name="serendipity[filter][author]"><?php echo serendipity_specialchars($serendipity['POST']['filter']['author']); ?></textarea>
</div>
<div class="form_field">
<label for="filter_email"><?php echo EMAIL; ?></label>
<textarea id="filter_email" name="serendipity[filter][email]"><?php echo serendipity_specialchars($serendipity['POST']['filter']['email']); ?></textarea>
</div>
</div>
<div class="form_buttons">
<input name="serendipity[export]" value="CSV" type="submit">
<input name="serendipity[delete]" class="state_cancel comments_multidelete" data-delmsg="<?php echo COMMENTS_DELETE_CONFIRM; ?>" value="<?php echo DELETE; ?>" type="submit">
</div>
</fieldset>
<?php
echo '</form>';
}
function event_hook($event, &$bag, &$eventData, $addData = null) {
global $serendipity;
@ -342,6 +452,16 @@ class serendipity_event_dsgvo_gdpr extends serendipity_event
if (isset($hooks[$event])) {
switch($event) {
case 'backend_sidebar_admin':
?>
<li><a href="?serendipity[adminModule]=event_display&amp;serendipity[adminAction]=dsgvo"><?php echo PLUGIN_EVENT_DSGVO_GDPR_BACKEND; ?></a></li>
<?php
break;
case 'backend_sidebar_entries_event_display_dsgvo':
$this->showBackend();
break;
case 'frontend_configure':
if (serendipity_db_bool($this->get_config('anonymizeIp'))) {
$_SERVER['REMOTE_ADDR'] = IpAnonymizer::anonymizeIp($_SERVER['REMOTE_ADDR']);
@ -383,6 +503,16 @@ class serendipity_event_dsgvo_gdpr extends serendipity_event
return true;
break;
case 'backend_deletecomment':
// Vanilla s9y does not delete all metadata of a comment that has threaded replies, it only sets the body to "Deleted".
// Here we take care that all metadata is cleared in that case.
serendipity_db_query("UPDATE {$serendipity['dbPrefix']}comments
SET title = '', author = '', email = '', url = '', ip = '', referer = ''
WHERE id = {$addData['cid']}");
return true;
break;
case 'entry_display':
if ($this->isActive()) {
if (is_array($eventData)) {