Skip to content

Commit 2d695e1

Browse files
authored
Merge pull request #85 from topcoder-platform/develop
v1.5
2 parents 38f6cc5 + 322e0d2 commit 2d695e1

File tree

13 files changed

+481
-61
lines changed

13 files changed

+481
-61
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
* SQL API Controller for the `/service` resource.
13+
*/
14+
class ServiceApiController extends AbstractApiController {
15+
/**
16+
*
17+
* @param array $query The query string.
18+
* @return Data
19+
*/
20+
public function get_tidewayslog($path='/var/log/tideways/daemon.log') {
21+
$this->permission('Garden.Settings.Manage');
22+
23+
if (file_exists($path)) {
24+
//Get file type and set it as Content Type
25+
$finfo = finfo_open(FILEINFO_MIME_TYPE);
26+
header('Content-Type: ' . finfo_file($finfo, $path));
27+
finfo_close($finfo);
28+
29+
header('Content-Description: File Transfer');
30+
header('Content-Disposition: attachment; filename='.basename($path));
31+
header('Expires: 0');
32+
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
33+
header('Pragma: public');
34+
header('Content-Length: ' . filesize($path));
35+
ob_clean();
36+
flush();
37+
readfile($path);
38+
exit;
39+
} else {
40+
throw notFoundException('File');
41+
}
42+
}
43+
44+
}

DebugPlugin/controllers/api/SqlApiController.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@ public function index(array $query) {
2222
$this->permission('Garden.Settings.Manage');
2323

2424
$in = $this->schema([
25-
'sql:s' => 'Sql query'
25+
'sql:s' => 'Sql query',
26+
'type:s' => 'Type'
2627
], 'in')->setDescription('Get a list of records.');
2728

2829
$query = $in->validate($query);
2930
$sql = $query['sql'];
31+
$type = $query['type'];
3032

31-
if (strpos(strtolower($sql), 'select') !== 0) {
32-
throw new ClientException('Unable to execute this query.');
33-
}
33+
// if (strpos(strtolower($sql), 'select') !== 0) {
34+
// throw new ClientException('Unable to execute this query.');
35+
// }
3436

35-
$data = Gdn::sql()->query($sql, 'select')->resultArray();
37+
$data = Gdn::sql()->query($sql, $type)->resultArray();
3638
return $data;
3739
}
3840

DebugPlugin/openapi/service.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
openapi: 3.0.2
2+
info: Vanilla Service API
3+
paths:
4+
/service/tidewayslog:
5+
get:
6+
responses:
7+
'200':
8+
content:
9+
'text/plain':
10+
schema:
11+
type: string
12+
description: Success
13+
tags:
14+
- Services
15+
summary: File.

DebugPlugin/openapi/sql.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ paths:
44
/sql:
55
get:
66
parameters:
7-
- description: SQL select query.
7+
- description: SQL query.
88
in: query
99
name: sql
1010
schema:
1111
type: string
12+
- description: SQL type query.
13+
in: query
14+
name: type
15+
schema:
16+
type: string
1217
responses:
1318
'200':
1419
content:

ReplyTo/class.replyto.plugin.php

Lines changed: 105 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class ReplyToPlugin extends Gdn_Plugin {
1010
const QUERY_PARAMETER_VIEW='view';
1111
const VIEW_FLAT = 'flat';
1212
const VIEW_THREADED = 'threaded';
13+
const VIEW_MODE = 'ReplyTo.ViewMode';
1314

1415
private $replyToModel;
1516
/**
@@ -56,32 +57,110 @@ public function assetModel_styleCss_handler($sender) {
5657
// Set JS for this plugin.
5758
protected function prepareController(&$sender) {
5859
$sender->addJsFile('replyto.js', 'plugins/ReplyTo');
60+
}
61+
62+
/**
63+
* Set a view mode for Discussion Controller
64+
* View Mode is calculated from request url.
65+
* Flat mode is used - '/discussion/{DiscussionID}/p{Page}
66+
* Threaded mode is used by default
67+
*
68+
* @param $sender
69+
* @param $args
70+
*/
71+
public function discussionController_initialize_handler($sender, $args) {
72+
$viewMode = self::getViewMode();
73+
$sender->setData(self::VIEW_MODE, $viewMode);
74+
75+
}
76+
77+
/**
78+
* Set a view mode for Post Controller
79+
* Replying to a comment and leaving a comment are processed by Post Controller.
80+
* (the url 'post/comment/, 'post' method).
81+
* Use HTTP_REFERER to get the current view mode
82+
* @param $sender
83+
* @param $args
84+
*/
85+
public function postController_initialize_handler($sender, $args) {
86+
if(isset($_SERVER['HTTP_REFERER'])) {
87+
$url = $_SERVER['HTTP_REFERER'];
88+
}
89+
parse_str( parse_url( $url, PHP_URL_QUERY), $array );
90+
$viewMode = $array[self::QUERY_PARAMETER_VIEW];
91+
if(!$viewMode) {
92+
$viewMode = self::isPagingUrl($url)? self::VIEW_FLAT: self::VIEW_THREADED;
93+
}
94+
$sender->setData(self::VIEW_MODE, $viewMode);
5995
}
6096

6197
public function discussionController_render_before(&$sender) {
6298
$this->prepareController($sender);
6399
}
64100

101+
/**
102+
* After deleting a comment in a threaded view, the comment tree should be re-rendered
103+
* because tree left/right might be changed if a parent comment has been deleted.
104+
* deliveryType is VIEW in a threaded view
105+
* deliveryType is BOOL in a flat view. Don't re-render a view. Deleted comment
106+
* is hidden on the client.
107+
*
108+
* @param $sender
109+
* @param $args
110+
*/
111+
public function discussionController_AfterCommentDeleted_handler($sender, $args) {
112+
$viewMode = $sender->data('ReplyTo.ViewMode');
113+
if($sender->deliveryMethod() == DELIVERY_METHOD_JSON) {
114+
$discussionID = $args['DiscussionID'];
115+
$sender->json(self::VIEW_MODE, $viewMode);
116+
if ($viewMode == self::VIEW_THREADED) {
117+
// Show all comments
118+
$commentModel = new CommentModel();
119+
$CountComments = $commentModel->getCountByDiscussion($discussionID);
120+
$sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $CountComments, 0));
121+
$sender->ClassName = 'DiscussionController';
122+
$sender->ControllerName = 'discussion';
123+
$sender->View = 'comments';
124+
}
125+
}
126+
}
127+
65128
public function postController_render_before($sender) {
66129
$this->prepareController($sender);
67130
}
68131

69132
/**
70-
* Add View Mode before rendering comments
133+
* The 'beforeCommentRender' are fired by DiscussionController and PostController.
134+
* Re-render a comment tree if new comment is added in threaded view.
135+
*
71136
* @param $sender
72137
* @param $args
73138
*/
74-
public function base_beforeCommentsRender_handler($sender, $args) {
75-
$viewMode = self::getViewMode();
76-
$sender->setData('ViewMode', $viewMode);
139+
public function base_beforeCommentRender_handler($sender, $args) {
140+
// Editing existing comment or new comment added
141+
if ($sender->deliveryType() != DELIVERY_TYPE_DATA) {
142+
$sender->json('ReplyTo.ViewMode', $sender->data(self::VIEW_MODE));
143+
$isNewComment = $sender->data('NewComments');
144+
if($isNewComment) {
145+
$discussionID = val('DiscussionID', $args['Discussion']);
146+
$commentModel = new CommentModel();
147+
$countComments = $commentModel->getCountByDiscussion($discussionID);
148+
// FIX: https://github.com/topcoder-platform/forums/issues/511
149+
// Render a full comment tree in threaded mode
150+
if($sender->data(self::VIEW_MODE) == self::VIEW_THREADED) {
151+
// Show all comments
152+
$sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $countComments, 0));
153+
}
154+
}
155+
}
77156
}
78157

79158
/**
80159
* Render View options for a discussion
81160
* @param $sender
82161
* @param $args
83162
*/
84-
public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
163+
public function discussionController_InlineDiscussionOptionsLeft_handler($sender, $args){
85164
$discussion = $sender->data('Discussion');
86165
if (!$discussion) {
87166
return;
@@ -92,7 +171,7 @@ public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
92171
}
93172

94173
$discussionUrl = discussionUrl($discussion, '', '/');
95-
$viewMode = self::getViewMode();
174+
$viewMode = $sender->data(self::VIEW_MODE);
96175

97176
echo '<span class="ReplyViewOptions">';
98177
echo '<span class="MLabel">View:&nbsp</span>';
@@ -143,8 +222,16 @@ public function commentModel_deleteComment_handler(&$Sender) {
143222
$this->replyToModel->onDeleteComment($Comment);
144223
}
145224

225+
/**
226+
* Set offset and limit depends on view mode.
227+
* In the threaded mode, all comments are displayed.
228+
* In the flat mode, comments are displayed with pagination.
229+
* The hook is used when rendering a discussion page with comments
230+
* @param $sender
231+
* @param $args
232+
*/
146233
public function discussionController_BeforeCalculatingOffsetLimit_handler($sender, $args) {
147-
$viewMode = self::getViewMode();
234+
$viewMode = $sender->data(self::VIEW_MODE);
148235
// $offsetProvided = $args['OffsetProvided'];
149236
$discussion = $args['Discussion'];
150237
$offset = & $args['Offset'];
@@ -179,7 +266,7 @@ public function discussionController_beforeDiscussionRender_handler($sender, $ar
179266
return;
180267
}
181268

182-
$viewMode = self::getViewMode();
269+
$viewMode = $sender->data(self::VIEW_MODE);
183270
if($viewMode == self::VIEW_FLAT) {
184271
return;
185272
}
@@ -222,19 +309,16 @@ public function base_commentOptions_handler($sender, $args) {
222309
'Class' => 'ReplyComment'
223310
];
224311

225-
$viewMode = self::getViewMode();
312+
$viewMode = $sender->data(self::VIEW_MODE);
313+
$deliveryType = $viewMode == self::VIEW_THREADED? DELIVERY_TYPE_VIEW : DELIVERY_TYPE_BOOL;
226314
foreach ($options as $key => $value) {
227-
$currentUrl = $options[$key]['Url'];
228-
if (strpos($currentUrl, '?') !== false ) {
229-
if (strpos($currentUrl, 'Target') !== false) {
230-
$options[$key]['Url'] = $currentUrl.urlencode('?view='.$viewMode);
231-
} else {
232-
$options[$key]['Url'] = $currentUrl. '&view=' . $viewMode;
233-
}
234-
} else {
235-
$options[$key]['Url'] = $currentUrl.'?view='.$viewMode;
315+
$options[$key]['Url'] = strpos($options[$key]['Url'], '?') !== false ? $options[$key]['Url']: $options[$key]['Url'].'?';
316+
$options[$key]['Url'] .= '&view=' . $viewMode;
317+
if($key == 'DeleteComment') {
318+
$options[$key]['Url'] .='&deliveryType='.$deliveryType;
236319
}
237320
}
321+
238322
}
239323

240324
/**
@@ -276,7 +360,7 @@ public function base_inlineDiscussionOptions_handler($sender, $args) {
276360
* @param $args
277361
*/
278362
public function base_beforeCommentDisplay_handler($sender, $args) {
279-
if($sender->deliveryType() != DELIVERY_TYPE_ALL) {
363+
if($sender->deliveryType() != DELIVERY_TYPE_ALL) { // Editing a comment is processed by PostController
280364
// Ajax request to post new comments or update comments
281365
if(isset($_SERVER['HTTP_REFERER'])) {
282366
$previous = $_SERVER['HTTP_REFERER'];
@@ -286,13 +370,13 @@ public function base_beforeCommentDisplay_handler($sender, $args) {
286370
if(!$viewMode) {
287371
$viewMode = self::isPagingUrl($previous) ? self::VIEW_FLAT : self::VIEW_THREADED;
288372
}
289-
$sender->setData('ViewMode', $viewMode);
373+
$sender->setData(self::VIEW_MODE, $viewMode);
290374
if($viewMode == self::VIEW_THREADED) {
291375
$this->buildCommentReplyToCssClasses($sender);
292376
}
293377
}
294378
} else {
295-
$viewMode = self::getViewMode();
379+
$viewMode = $sender->data(self::VIEW_MODE);
296380
if($viewMode == self::VIEW_THREADED) {
297381
$this->buildCommentReplyToCssClasses($sender);
298382
}

ReplyTo/js/replyto.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ jQuery(document).ready(function($) {
44
return (href.split(name + '=')[1] || '').split('&')[0];
55
}
66

7-
//If view is not flat, reload a page to rebuild a tree
8-
function reloadPage() {
9-
var currentView = param(window.location.href, 'view');
10-
return currentView == 'threaded';
11-
}
12-
137
$(document).on('click','a.ReplyComment', function(ev) {
148
var btn = this;
159
var parent = $(btn).parents('.MainContent');
@@ -61,25 +55,6 @@ jQuery(document).ready(function($) {
6155
return false;
6256
});
6357

64-
65-
// Comment was added.
66-
$(document).on('CommentAdded',function(ev) {
67-
if (reloadPage() === true) {
68-
window.location.reload();
69-
return false;
70-
}
71-
return false;
72-
});
73-
74-
// Comment was deleted.
75-
$(document).on('CommentDeleted',function(ev) {
76-
if (reloadPage() === true) {
77-
window.location.reload();
78-
return false;
79-
}
80-
return false;
81-
});
82-
8358
$(document).on('click','a.CancelReplyComment', function(ev) {
8459
clearReplyCommentForm(this);
8560
return false;

Topcoder/class.topcoder.plugin.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,6 +1892,10 @@ private static function topcoderUserTopcoderCache($userFields) {
18921892
return $cached;
18931893
}
18941894

1895+
public static function isUnclickableUser($userName) {
1896+
return strtolower($userName) == 'tcadmin';
1897+
}
1898+
18951899
public static function log($message, $data = []) {
18961900
if (c('Vanilla.SSO.Debug') || c('Debug')) {
18971901
Logger::event(
@@ -2046,7 +2050,8 @@ function userPhoto($user, $options = []) {
20462050

20472051
$isTopcoderAdmin = val('IsAdmin', $topcoderProfile);
20482052
$photoUrl = isset($photoUrl) && !empty(trim($photoUrl)) ? $photoUrl: UserModel::getDefaultAvatarUrl();
2049-
$href = (val('NoLink', $options)) ? '' : ' href="'.url($userLink).'"';
2053+
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
2054+
$href = (val('NoLink', $options)) || $isUnlickableUser ? '' : ' href="'.url($userLink).'"';
20502055

20512056
Gdn::controller()->EventArguments['User'] = $user;
20522057
Gdn::controller()->EventArguments['Title'] =& $title;
@@ -2136,7 +2141,8 @@ function userAnchor($user, $cssClass = null, $options = null) {
21362141
}
21372142

21382143
// Go to Topcoder user profile link instead of Vanilla profile link
2139-
$userUrl = topcoderUserUrl($user, $px);
2144+
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
2145+
$userUrl = $isUnlickableUser? '#' : topcoderUserUrl($user, $px);
21402146

21412147
$topcoderProfile = TopcoderPlugin::getTopcoderUser($userID);
21422148
$topcoderRating = val('Rating',$topcoderProfile, false);
@@ -2150,6 +2156,11 @@ function userAnchor($user, $cssClass = null, $options = null) {
21502156
$attributes['class'] = $attributes['class'].' '. 'topcoderAdmin' ;
21512157
}
21522158

2159+
if($isUnlickableUser) {
2160+
$attributes['class'] = $attributes['class'].' '. 'disabledLink' ;
2161+
}
2162+
2163+
21532164
Gdn::controller()->EventArguments['User'] = $user;
21542165
Gdn::controller()->EventArguments['IsTopcoderAdmin'] =$isTopcoderAdmin;
21552166
Gdn::controller()->EventArguments['Text'] =& $text;

0 commit comments

Comments
 (0)