Skip to content

Commit 2297129

Browse files
authored
Merge pull request #16 from topcoder-platform/issues-15
Export user data
2 parents a39f8b4 + 68ba43d commit 2297129

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed

Topcoder/class.topcoder.plugin.php

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
/**
33
* Class TopcoderPlugin
44
*/
5+
6+
use Garden\Schema\Schema;
7+
use Garden\Web\Data;
8+
use Garden\Web\Exception\NotFoundException;
9+
use Vanilla\ApiUtils;
10+
511
class TopcoderPlugin extends Gdn_Plugin {
612

713
/**
@@ -28,9 +34,201 @@ public function settingsController_topcoder_create($sender) {
2834
]);
2935

3036
$sender->setData('Title', sprintf(t('%s Settings'), 'Topcoder'));
37+
saveToConfig('Conversations.Moderation.Allow', true);
3138
$cf->renderAll();
3239
}
3340

41+
/**
42+
* Add the button to generate GDPR report
43+
* @param $sender
44+
* @param $args
45+
*/
46+
public function userController_UserCell_handler($sender, $args) {
47+
?>
48+
<td>
49+
<?php
50+
echo !$args['User']->UserID? '' :'<a class="btn btn-icon-border" href="' . url('/user/export/' . $args['User']->UserID) . '">Export</a>';
51+
?>
52+
</td>
53+
<?php
54+
}
55+
56+
/**
57+
* Generate an export report (/user/export/{:userID})
58+
*
59+
* @param $sender
60+
* @param $args
61+
* @throws Gdn_UserException
62+
*/
63+
public function userController_export_create($sender, $args) {
64+
$userID = $args[0];
65+
66+
if (Gdn::request()->isAuthenticatedPostBack()) {
67+
throw new Exception('Requires GET', 405);
68+
}
69+
70+
$userModel = new UserModel();
71+
$user = $userModel->getID($userID, DATASET_TYPE_ARRAY);
72+
if (!$user) {
73+
throw notFoundException('User');
74+
}
75+
76+
//Max limit for all API controllers;
77+
$MAX_LIMIT = 100;
78+
79+
//$dateInserted = '';
80+
//$dateUpdated = '';
81+
82+
$user = self::getData(UsersApiController::class, array('id' => $userID));
83+
$discussions = TopcoderPlugin::getPagedData(DiscussionsApiController::class, array('page' => 1, 'limit' => $MAX_LIMIT, 'insertUserID'=> $userID));
84+
$comments = TopcoderPlugin::getPagedData(CommentsApiController::class, array('page' => 1, 'limit' => $MAX_LIMIT, 'insertUserID'=> $userID));
85+
$messages = TopcoderPlugin::getPagedData(MessagesApiController::class, array('page' => 1, 'limit' => $MAX_LIMIT, 'insertUserID'=> $userID));
86+
$conversations = TopcoderPlugin::getPagedData(ConversationsApiController::class, array('page' => 1, 'limit' => $MAX_LIMIT, 'insertUserID'=> $userID, 'participantUserID' => $userID));
87+
$drafts = TopcoderPlugin::getPagedData(DraftsApiController::class, array('page' => 1, 'limit' => $MAX_LIMIT, 'insertUserID'=> $userID));
88+
89+
$reportData =new StdClass();
90+
$reportData->user = $user;
91+
$reportData->discussions = $discussions;
92+
$reportData->comments = $comments;
93+
$reportData->conversations = $conversations;
94+
$reportData->messages = $messages;
95+
$reportData->drafts = $drafts;
96+
$reportData->ips = $userModel->getIPs($userID);
97+
98+
$result = json_encode($reportData, JSON_PRETTY_PRINT);
99+
header('Content-Disposition: attachment; filename="user-'.$userID.'.json"');
100+
header('Content-Type: application/json');
101+
header('Content-Length: ' . strlen($result));
102+
header('Connection: close');
103+
echo $result;
104+
105+
}
106+
107+
private static function getData($class, $query) {
108+
if($class === DiscussionsApiController::class) {
109+
$apiControler = Gdn::getContainer()->get(DiscussionsApiController::class);
110+
return $apiControler->index($query);
111+
} else if($class === UsersApiController::class) {
112+
$apiController = Gdn::getContainer()->get(UsersApiController::class);
113+
return $apiController->get($query['id'], array());
114+
} else if($class === CommentsApiController::class) {
115+
$apiControler = Gdn::getContainer()->get(CommentsApiController::class);
116+
return $apiControler->index($query);
117+
} else if($class === MessagesApiController::class) {
118+
$apiControler = Gdn::getContainer()->get(MessagesApiController::class);
119+
return $apiControler->index($query);
120+
} else if($class === ConversationsApiController::class) {
121+
$apiControler = Gdn::getContainer()->get(ConversationsApiController::class);
122+
return $apiControler->index($query);
123+
} else if($class === DraftsApiController::class) {
124+
return self::getDrafts(DraftsApiController::class,$query);
125+
} else {
126+
throw new Exception('API Controller not supported');
127+
}
128+
}
129+
130+
/**
131+
* Get data from REST API without auth tokens
132+
* There are two types of paging meta data
133+
* 1. { "page": 1,
134+
* "pageCount": 7,
135+
* "urlFormat": "\/api\/v2\/discussions?page=%s&limit=1",
136+
* "totalCount": 7
137+
* }
138+
* 2. {
139+
* "page" : 1,
140+
* "more" : 1,
141+
* "urlFormat": /api/v2/discussions?page=%s&amp;limit=1&amp;insertUserID=2,
142+
* }
143+
* @param $class
144+
* @param $query
145+
* @return array
146+
*/
147+
private static function getPagedData($class, $query) {
148+
$result = self::getData($class, $query);
149+
$records = $result->getData();
150+
$meta = $result->getMeta('paging');
151+
if(array_key_exists('totalCount', $meta)) {
152+
$records = $result->getData();
153+
// Load from the next page
154+
for ($i = 2; $i < $meta['totalCount']; $i++) {
155+
$query['page'] = $i;
156+
$nextPageData = self::getData($class, $query);
157+
$records = array_merge($records, $nextPageData->getData());
158+
}
159+
} else {
160+
$currentPage = 2;
161+
$hasNextPage = $meta['more'];
162+
while($hasNextPage === true) {
163+
$query['page'] = $currentPage;
164+
$nextPageData = self::getData($class, $query);
165+
$meta = $nextPageData->getMeta('paging');
166+
$hasNextPage = $meta['more'];
167+
$records = array_merge($records, $nextPageData->getData());
168+
$currentPage++;
169+
}
170+
}
171+
return $records;
172+
}
173+
174+
/**
175+
* List drafts created by the user.
176+
*
177+
* @param array $query The query string.
178+
* @return Data
179+
*/
180+
private static function getDrafts($class, array $query) {
181+
$apiControler = Gdn::getContainer()->get($class);
182+
$in = $apiControler->schema([
183+
'insertUserID:i?' => [
184+
'description' => 'Author',
185+
'default' => 1,
186+
'minimum' => 1
187+
],
188+
'page:i?' => [
189+
'description' => 'Page number.',
190+
'default' => 1,
191+
'minimum' => 1
192+
],
193+
'limit:i?' => [
194+
'description' => 'Desired number of items per page.',
195+
'default' => 30,
196+
'minimum' => 1,
197+
'maximum' => 100
198+
]
199+
], 'in')->setDescription('List drafts created by the user.');
200+
$out = $apiControler->schema([':a' => Schema::parse([
201+
'draftID:i' => 'The unique ID of the draft.',
202+
'recordType:s' => [
203+
'description' => 'The type of record associated with this draft.',
204+
'enum' => ['comment', 'discussion']
205+
],
206+
'parentRecordID:i|n' => 'The unique ID of the intended parent to this record.',
207+
'attributes:o' => 'A free-form object containing all custom data for this draft.',
208+
'insertUserID:i' => 'The unique ID of the user who created this draft.',
209+
'dateInserted:dt' => 'When the draft was created.',
210+
'updateUserID:i|n' => 'The unique ID of the user who updated this draft.',
211+
'dateUpdated:dt|n' => 'When the draft was updated.'
212+
])], 'out');
213+
$query = $in->validate($query);
214+
$where = ['InsertUserID' => $query['insertUserID']];
215+
list($offset, $limit) = offsetLimit("p{$query['page']}", $query['limit']);
216+
$draftModel = new DraftModel();
217+
$rows = $draftModel->getWhere($where, '', 'asc', $limit, $offset)->resultArray();
218+
foreach ($rows as &$row) {
219+
$row = $apiControler->normalizeOutput($row);
220+
}
221+
$result = $out->validate($rows);
222+
$paging = ApiUtils::numberedPagerInfo(
223+
$draftModel->getCount($where),
224+
'/api/v2/drafts',
225+
$query,
226+
$in
227+
);
228+
229+
return new Data($result, ['paging' => $paging]);
230+
}
231+
34232
/**
35233
* Use a Topcoder Photo on the user' profile.
36234
* Add/Remove Links in/from a sided menu.

0 commit comments

Comments
 (0)