Skip to content

Commit 38f6cc5

Browse files
authored
Merge pull request #79 from topcoder-platform/develop
Version 1.4
2 parents 3b7d667 + dd92114 commit 38f6cc5

File tree

9 files changed

+391
-64
lines changed

9 files changed

+391
-64
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
use Garden\Web\Exception\ClientException;
4+
use Garden\Schema\Schema;
5+
use Vanilla\Utility\InstanceValidatorSchema;
6+
use Garden\Web\Data;
7+
use Garden\Web\Exception\NotFoundException;
8+
use Garden\Web\Exception\ServerException;
9+
use Vanilla\ApiUtils;
10+
11+
/**
12+
* Permission API Controller for the `/permission` resource.
13+
*/
14+
class PermissionApiController extends AbstractApiController {
15+
16+
/**
17+
* Get default user permissions
18+
* @param $userID
19+
* @return Data
20+
* @throws \Garden\Web\Exception\HttpException
21+
* @throws \Vanilla\Exception\PermissionException
22+
*/
23+
public function index($userID) {
24+
$this->permission('Garden.Settings.Manage');
25+
if (!Gdn::userModel()->getID($userID)) {
26+
throw notFoundException('User');
27+
}
28+
$userPermissions = Gdn::userModel()->getPermissions($userID);
29+
$data = [
30+
'userPermissions' => $userPermissions,
31+
];
32+
return $data;
33+
}
34+
35+
/**
36+
* Get user permissions for a category
37+
* @param $userID
38+
* @param $categoryID
39+
* @return Data
40+
* @throws \Garden\Web\Exception\HttpException
41+
* @throws \Vanilla\Exception\PermissionException
42+
*/
43+
public function get($userID, $categoryID) {
44+
$this->permission('Garden.Settings.Manage');
45+
46+
if (!Gdn::userModel()->getID($userID)) {
47+
throw notFoundException('User');
48+
}
49+
50+
$category = CategoryModel::categories($categoryID);
51+
if (!$category) {
52+
throw notFoundException('Category');
53+
}
54+
$groupID = val('GroupID', $category, null);
55+
$data = [
56+
'GroupID' => $groupID,
57+
'PermsGroupView' => $groupID? GroupModel::getGroupRoleFor($userID, $groupID) : null,
58+
'PermsDiscussionsView' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.View', true, $userID),
59+
'PermsDiscussionsAdd' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.Add', true, $userID),
60+
'PermsDiscussionsEdit' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.Edit', true, $userID),
61+
'PermsCommentsAdd' => CategoryModel::checkPermission($category, 'Vanilla.Comments.Add', true, $userID),
62+
'PermsDiscussionsUploads' => CategoryModel::checkPermission($category, 'Vanilla.Discussions.Uploads', true, $userID),
63+
'PermsCommentsUploads' => CategoryModel::checkPermission($category, 'Vanilla.Comments.Uploads', true, $userID)
64+
];
65+
return $data;
66+
}
67+
}

DebugPlugin/openapi/permission.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
openapi: 3.0.2
2+
info: Vanilla Permission API
3+
paths:
4+
/permission/{userID}/{categoryID}:
5+
get:
6+
parameters:
7+
- description: UserID to check.
8+
in: path
9+
name: userID
10+
schema:
11+
type: integer
12+
- description: CategoryID to check.
13+
in: path
14+
name: categoryID
15+
schema:
16+
type: integer
17+
responses:
18+
'200':
19+
content:
20+
'application/json':
21+
schema:
22+
items:
23+
$ref: '#/components/schemas/Records'
24+
type: array
25+
description: Success
26+
tags:
27+
- Data
28+
summary: List records.
29+
/permission/{userID}:
30+
get:
31+
parameters:
32+
- description: UserID to check.
33+
in: path
34+
name: userID
35+
schema:
36+
type: integer
37+
responses:
38+
'200':
39+
content:
40+
'application/json':
41+
schema:
42+
items:
43+
$ref: '#/components/schemas/Records'
44+
type: array
45+
description: Success
46+
tags:
47+
- Data
48+
summary: List records.
49+
components:
50+
schemas:
51+
Records:
52+
type: object

ReplyTo/class.replyto.plugin.php

Lines changed: 101 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ class ReplyToPlugin extends Gdn_Plugin {
99

1010
const QUERY_PARAMETER_VIEW='view';
1111
const VIEW_FLAT = 'flat';
12-
const VIEW_TREE = 'tree';
1312
const VIEW_THREADED = 'threaded';
1413

1514
private $replyToModel;
@@ -67,12 +66,22 @@ public function postController_render_before($sender) {
6766
$this->prepareController($sender);
6867
}
6968

69+
/**
70+
* Add View Mode before rendering comments
71+
* @param $sender
72+
* @param $args
73+
*/
74+
public function base_beforeCommentsRender_handler($sender, $args) {
75+
$viewMode = self::getViewMode();
76+
$sender->setData('ViewMode', $viewMode);
77+
}
78+
7079
/**
7180
* Render View options for a discussion
7281
* @param $sender
7382
* @param $args
7483
*/
75-
public function base_Replies_handler($sender, $args){
84+
public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
7685
$discussion = $sender->data('Discussion');
7786
if (!$discussion) {
7887
return;
@@ -83,13 +92,13 @@ public function base_Replies_handler($sender, $args){
8392
}
8493

8594
$discussionUrl = discussionUrl($discussion, '', '/');
86-
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT);
95+
$viewMode = self::getViewMode();
8796

88-
echo '<div class="ReplyViewOptions"><span class="MLabel">View:&nbsp</span>';
89-
echo anchor('Flat', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_FLAT, $viewMode == self::VIEW_FLAT?'Active':'').'&nbsp;&nbsp;|&nbsp;&nbsp;';
90-
echo anchor('Threaded', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_THREADED, $viewMode == self::VIEW_THREADED?'Active':'').'&nbsp;&nbsp;|&nbsp;&nbsp;';
91-
echo anchor('Tree', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_TREE, $viewMode == self::VIEW_TREE?'Active':'');
92-
echo '</div>';
97+
echo '<span class="ReplyViewOptions">';
98+
echo '<span class="MLabel">View:&nbsp</span>';
99+
echo anchor('Threaded', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_THREADED, $viewMode == self::VIEW_THREADED?'ReplyViewOptionLink Active':'ReplyViewOptionLink').'&nbsp;&nbsp;|&nbsp;&nbsp;';
100+
echo anchor('Flat', $discussionUrl.'?'.self::QUERY_PARAMETER_VIEW.'='.self::VIEW_FLAT, $viewMode == self::VIEW_FLAT?'ReplyViewOptionLink Active':'ReplyViewOptionLink');
101+
echo '</span>';
93102
}
94103

95104
/**
@@ -98,9 +107,9 @@ public function base_Replies_handler($sender, $args){
98107
* @param $sender
99108
*/
100109
public function commentModel_afterConstruct_handler(&$sender) {
101-
self::log('commentModel_afterConstruct_handler', ['path'=> Gdn::request()->pathAndQuery()]);
102-
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT);
103-
if($viewMode == self::VIEW_TREE || $viewMode == self::VIEW_THREADED) {
110+
$viewMode = self::getViewMode();
111+
112+
if($viewMode == self::VIEW_THREADED) {
104113
$sender->orderBy(array('TreeLeft asc', 'DateInserted asc'));
105114
}
106115
}
@@ -135,13 +144,8 @@ public function commentModel_deleteComment_handler(&$Sender) {
135144
}
136145

137146
public function discussionController_BeforeCalculatingOffsetLimit_handler($sender, $args) {
138-
if (!Gdn::session()->isValid()) {
139-
return;
140-
}
141-
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW);
142-
if(!$viewMode) {
143-
return;
144-
}
147+
$viewMode = self::getViewMode();
148+
// $offsetProvided = $args['OffsetProvided'];
145149
$discussion = $args['Discussion'];
146150
$offset = & $args['Offset'];
147151
$limit = & $args['Limit'];
@@ -152,7 +156,6 @@ public function discussionController_BeforeCalculatingOffsetLimit_handler($sende
152156
}
153157

154158
if($viewMode === self::VIEW_FLAT) {
155-
$offset = 0;
156159
$enableAutoOffset = false;
157160
} else {
158161
// Show all comment on one offset for Tree/Threaded View
@@ -176,7 +179,7 @@ public function discussionController_beforeDiscussionRender_handler($sender, $ar
176179
return;
177180
}
178181

179-
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT);
182+
$viewMode = self::getViewMode();
180183
if($viewMode == self::VIEW_FLAT) {
181184
return;
182185
}
@@ -196,32 +199,30 @@ public function base_commentOptions_handler($sender, $args) {
196199
return;
197200
}
198201
$discussion = $sender->data('Discussion');
199-
$isClosed = ((int)$discussion->Closed) == 1;
200-
if ($isClosed) {
201-
return;
202-
}
203202

204203
//Check permission
205-
if (isset($discussion->PermissionCategoryID)) {
206-
$CategoryID = val('PermissionCategoryID', $discussion);
207-
} else {
208-
$CategoryID = $discussion->CategoryID;
209-
}
204+
$CategoryID = val('PermissionCategoryID', $discussion)? val('PermissionCategoryID', $discussion):val('CategoryID', $discussion);
205+
$userCanClose = CategoryModel::checkPermission($CategoryID, 'Vanilla.Discussions.Close');
206+
$userCanComment = CategoryModel::checkPermission($CategoryID, 'Vanilla.Comments.Add');
210207

211-
// Can the user comment on this category, and is the discussion open for comments?
212-
if (!Gdn::Session()->CheckPermission('Vanilla.Comments.Add', TRUE, 'Category', $CategoryID)) {
208+
$canAddComment = ($discussion->Closed == '1' && $userCanClose) || ($discussion->Closed == '0' && $userCanComment);
209+
if (!$canAddComment) {
213210
return;
214211
}
212+
// Can the user comment on this category, and is the discussion open for comments?
213+
// if (!Gdn::Session()->CheckPermission('Vanilla.Comments.Add', TRUE, 'Category', $CategoryID)) {
214+
// return;
215+
// }
215216

216217
$options = &$args['CommentOptions'];
217-
$comment = &$args['Comment'];
218+
$comment = $args['Comment'];
218219
$options['ReplyToComment'] = [
219220
'Label' => t('Reply'),
220221
'Url' => '/?ParentCommentID='.$comment->CommentID,
221222
'Class' => 'ReplyComment'
222223
];
223224

224-
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT);
225+
$viewMode = self::getViewMode();
225226
foreach ($options as $key => $value) {
226227
$currentUrl = $options[$key]['Url'];
227228
if (strpos($currentUrl, '?') !== false ) {
@@ -236,26 +237,70 @@ public function base_commentOptions_handler($sender, $args) {
236237
}
237238
}
238239

240+
/**
241+
* Add 'Reply' option to discussion.
242+
*
243+
* @param Gdn_Controller $sender
244+
* @param array $args
245+
*/
246+
public function base_inlineDiscussionOptions_handler($sender, $args) {
247+
$discussion = $args['Discussion'];
248+
if (!$discussion) {
249+
return;
250+
}
251+
252+
if (!Gdn::session()->UserID) {
253+
return;
254+
}
255+
256+
//Check permission
257+
$CategoryID = val('PermissionCategoryID', $discussion)? val('PermissionCategoryID', $discussion):val('CategoryID', $discussion);
258+
$userCanClose = CategoryModel::checkPermission($CategoryID, 'Vanilla.Discussions.Close');
259+
$userCanComment = CategoryModel::checkPermission($CategoryID, 'Vanilla.Comments.Add');
260+
261+
// See the 'writeCommentForm' method vanilla/applications/vanilla/views/discussion/helper_functions.php
262+
$canAddComment = ($discussion->Closed == '1' && $userCanClose) || ($discussion->Closed == '0' && $userCanComment);
263+
if (!$canAddComment) {
264+
return;
265+
}
266+
267+
// DropdownModule options
268+
$options = & $args['DiscussionOptions'];
269+
$options->addLink('Reply', url("/", true), 'reply', 'ReplyComment');
270+
}
271+
239272
/**
240273
* Insert the indentation classes into the comment.
274+
* All rendering options should be set before displaying comments
241275
* @param $sender
242276
* @param $args
243277
*/
244278
public function base_beforeCommentDisplay_handler($sender, $args) {
245-
ReplyToPlugin::log('base_beforeCommentDisplay_handler', []);
246-
247-
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW, self::VIEW_FLAT);
248-
if($viewMode == self::VIEW_FLAT) {
249-
return;
250-
}
251279
if($sender->deliveryType() != DELIVERY_TYPE_ALL) {
252-
ReplyToPlugin::log('base_beforeCommentDisplay_handler', ['']);
253-
$this->buildCommentReplyToCssClasses($sender);
280+
// Ajax request to post new comments or update comments
281+
if(isset($_SERVER['HTTP_REFERER'])) {
282+
$previous = $_SERVER['HTTP_REFERER'];
283+
$query = parse_url($previous, PHP_URL_QUERY);
284+
parse_str($query, $params);
285+
$viewMode = $params['view'];
286+
if(!$viewMode) {
287+
$viewMode = self::isPagingUrl($previous) ? self::VIEW_FLAT : self::VIEW_THREADED;
288+
}
289+
$sender->setData('ViewMode', $viewMode);
290+
if($viewMode == self::VIEW_THREADED) {
291+
$this->buildCommentReplyToCssClasses($sender);
292+
}
293+
}
294+
} else {
295+
$viewMode = self::getViewMode();
296+
if($viewMode == self::VIEW_THREADED) {
297+
$this->buildCommentReplyToCssClasses($sender);
298+
}
254299
}
255300
$comment = &$args['Comment'];
256301
$cssClass = &$args['CssClass'];
257-
$displayBody = &$args['DisplayBody'];
258-
$displayBody = $viewMode == self::VIEW_FLAT || $viewMode == self::VIEW_THREADED;
302+
// $displayBody = &$args['DisplayBody'];
303+
// $displayBody = $viewMode == self::VIEW_FLAT || $viewMode == self::VIEW_THREADED;
259304
$cssClass .= (!empty($comment->ReplyToClass)? ' ' . $comment->ReplyToClass : '');
260305
}
261306

@@ -330,6 +375,19 @@ private function buildCommentReplyToCssClasses(&$sender){
330375
}
331376
}
332377

378+
private static function isPagingUrl($url) {
379+
return preg_match('/\/p\d+$/', $url);
380+
}
381+
382+
private static function getViewMode(){
383+
$viewMode = getIncomingValue(self::QUERY_PARAMETER_VIEW);
384+
if(!$viewMode) {
385+
$viewMode = self::isPagingUrl(Gdn::request()->path())? self::VIEW_FLAT: self::VIEW_THREADED;
386+
}
387+
388+
return $viewMode;
389+
}
390+
333391
public static function log($message, $data) {
334392
if (c('Debug')) {
335393
Logger::event(

0 commit comments

Comments
 (0)