Skip to content

v1.5 #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 9, 2021
Merged

v1.5 #85

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions DebugPlugin/controllers/api/ServiceApiController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

use Garden\Web\Exception\ClientException;
use Garden\Schema\Schema;
use Vanilla\Utility\InstanceValidatorSchema;
use Garden\Web\Data;
use Garden\Web\Exception\NotFoundException;
use Garden\Web\Exception\ServerException;
use Vanilla\ApiUtils;

/**
* SQL API Controller for the `/service` resource.
*/
class ServiceApiController extends AbstractApiController {
/**
*
* @param array $query The query string.
* @return Data
*/
public function get_tidewayslog($path='/var/log/tideways/daemon.log') {
$this->permission('Garden.Settings.Manage');

if (file_exists($path)) {
//Get file type and set it as Content Type
$finfo = finfo_open(FILEINFO_MIME_TYPE);
header('Content-Type: ' . finfo_file($finfo, $path));
finfo_close($finfo);

header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.basename($path));
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
ob_clean();
flush();
readfile($path);
exit;
} else {
throw notFoundException('File');
}
}

}
12 changes: 7 additions & 5 deletions DebugPlugin/controllers/api/SqlApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,19 @@ public function index(array $query) {
$this->permission('Garden.Settings.Manage');

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

$query = $in->validate($query);
$sql = $query['sql'];
$type = $query['type'];

if (strpos(strtolower($sql), 'select') !== 0) {
throw new ClientException('Unable to execute this query.');
}
// if (strpos(strtolower($sql), 'select') !== 0) {
// throw new ClientException('Unable to execute this query.');
// }

$data = Gdn::sql()->query($sql, 'select')->resultArray();
$data = Gdn::sql()->query($sql, $type)->resultArray();
return $data;
}

Expand Down
15 changes: 15 additions & 0 deletions DebugPlugin/openapi/service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
openapi: 3.0.2
info: Vanilla Service API
paths:
/service/tidewayslog:
get:
responses:
'200':
content:
'text/plain':
schema:
type: string
description: Success
tags:
- Services
summary: File.
7 changes: 6 additions & 1 deletion DebugPlugin/openapi/sql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ paths:
/sql:
get:
parameters:
- description: SQL select query.
- description: SQL query.
in: query
name: sql
schema:
type: string
- description: SQL type query.
in: query
name: type
schema:
type: string
responses:
'200':
content:
Expand Down
126 changes: 105 additions & 21 deletions ReplyTo/class.replyto.plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ReplyToPlugin extends Gdn_Plugin {
const QUERY_PARAMETER_VIEW='view';
const VIEW_FLAT = 'flat';
const VIEW_THREADED = 'threaded';
const VIEW_MODE = 'ReplyTo.ViewMode';

private $replyToModel;
/**
Expand Down Expand Up @@ -56,32 +57,110 @@ public function assetModel_styleCss_handler($sender) {
// Set JS for this plugin.
protected function prepareController(&$sender) {
$sender->addJsFile('replyto.js', 'plugins/ReplyTo');
}

/**
* Set a view mode for Discussion Controller
* View Mode is calculated from request url.
* Flat mode is used - '/discussion/{DiscussionID}/p{Page}
* Threaded mode is used by default
*
* @param $sender
* @param $args
*/
public function discussionController_initialize_handler($sender, $args) {
$viewMode = self::getViewMode();
$sender->setData(self::VIEW_MODE, $viewMode);

}

/**
* Set a view mode for Post Controller
* Replying to a comment and leaving a comment are processed by Post Controller.
* (the url 'post/comment/, 'post' method).
* Use HTTP_REFERER to get the current view mode
* @param $sender
* @param $args
*/
public function postController_initialize_handler($sender, $args) {
if(isset($_SERVER['HTTP_REFERER'])) {
$url = $_SERVER['HTTP_REFERER'];
}
parse_str( parse_url( $url, PHP_URL_QUERY), $array );
$viewMode = $array[self::QUERY_PARAMETER_VIEW];
if(!$viewMode) {
$viewMode = self::isPagingUrl($url)? self::VIEW_FLAT: self::VIEW_THREADED;
}
$sender->setData(self::VIEW_MODE, $viewMode);
}

public function discussionController_render_before(&$sender) {
$this->prepareController($sender);
}

/**
* After deleting a comment in a threaded view, the comment tree should be re-rendered
* because tree left/right might be changed if a parent comment has been deleted.
* deliveryType is VIEW in a threaded view
* deliveryType is BOOL in a flat view. Don't re-render a view. Deleted comment
* is hidden on the client.
*
* @param $sender
* @param $args
*/
public function discussionController_AfterCommentDeleted_handler($sender, $args) {
$viewMode = $sender->data('ReplyTo.ViewMode');
if($sender->deliveryMethod() == DELIVERY_METHOD_JSON) {
$discussionID = $args['DiscussionID'];
$sender->json(self::VIEW_MODE, $viewMode);
if ($viewMode == self::VIEW_THREADED) {
// Show all comments
$commentModel = new CommentModel();
$CountComments = $commentModel->getCountByDiscussion($discussionID);
$sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $CountComments, 0));
$sender->ClassName = 'DiscussionController';
$sender->ControllerName = 'discussion';
$sender->View = 'comments';
}
}
}

public function postController_render_before($sender) {
$this->prepareController($sender);
}

/**
* Add View Mode before rendering comments
* The 'beforeCommentRender' are fired by DiscussionController and PostController.
* Re-render a comment tree if new comment is added in threaded view.
*
* @param $sender
* @param $args
*/
public function base_beforeCommentsRender_handler($sender, $args) {
$viewMode = self::getViewMode();
$sender->setData('ViewMode', $viewMode);
public function base_beforeCommentRender_handler($sender, $args) {
// Editing existing comment or new comment added
if ($sender->deliveryType() != DELIVERY_TYPE_DATA) {
$sender->json('ReplyTo.ViewMode', $sender->data(self::VIEW_MODE));
$isNewComment = $sender->data('NewComments');
if($isNewComment) {
$discussionID = val('DiscussionID', $args['Discussion']);
$commentModel = new CommentModel();
$countComments = $commentModel->getCountByDiscussion($discussionID);
// FIX: https://github.com/topcoder-platform/forums/issues/511
// Render a full comment tree in threaded mode
if($sender->data(self::VIEW_MODE) == self::VIEW_THREADED) {
// Show all comments
$sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $countComments, 0));
}
}
}
}

/**
* Render View options for a discussion
* @param $sender
* @param $args
*/
public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
public function discussionController_InlineDiscussionOptionsLeft_handler($sender, $args){
$discussion = $sender->data('Discussion');
if (!$discussion) {
return;
Expand All @@ -92,7 +171,7 @@ public function base_InlineDiscussionOptionsLeft_handler($sender, $args){
}

$discussionUrl = discussionUrl($discussion, '', '/');
$viewMode = self::getViewMode();
$viewMode = $sender->data(self::VIEW_MODE);

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

/**
* Set offset and limit depends on view mode.
* In the threaded mode, all comments are displayed.
* In the flat mode, comments are displayed with pagination.
* The hook is used when rendering a discussion page with comments
* @param $sender
* @param $args
*/
public function discussionController_BeforeCalculatingOffsetLimit_handler($sender, $args) {
$viewMode = self::getViewMode();
$viewMode = $sender->data(self::VIEW_MODE);
// $offsetProvided = $args['OffsetProvided'];
$discussion = $args['Discussion'];
$offset = & $args['Offset'];
Expand Down Expand Up @@ -179,7 +266,7 @@ public function discussionController_beforeDiscussionRender_handler($sender, $ar
return;
}

$viewMode = self::getViewMode();
$viewMode = $sender->data(self::VIEW_MODE);
if($viewMode == self::VIEW_FLAT) {
return;
}
Expand Down Expand Up @@ -222,19 +309,16 @@ public function base_commentOptions_handler($sender, $args) {
'Class' => 'ReplyComment'
];

$viewMode = self::getViewMode();
$viewMode = $sender->data(self::VIEW_MODE);
$deliveryType = $viewMode == self::VIEW_THREADED? DELIVERY_TYPE_VIEW : DELIVERY_TYPE_BOOL;
foreach ($options as $key => $value) {
$currentUrl = $options[$key]['Url'];
if (strpos($currentUrl, '?') !== false ) {
if (strpos($currentUrl, 'Target') !== false) {
$options[$key]['Url'] = $currentUrl.urlencode('?view='.$viewMode);
} else {
$options[$key]['Url'] = $currentUrl. '&view=' . $viewMode;
}
} else {
$options[$key]['Url'] = $currentUrl.'?view='.$viewMode;
$options[$key]['Url'] = strpos($options[$key]['Url'], '?') !== false ? $options[$key]['Url']: $options[$key]['Url'].'?';
$options[$key]['Url'] .= '&view=' . $viewMode;
if($key == 'DeleteComment') {
$options[$key]['Url'] .='&deliveryType='.$deliveryType;
}
}

}

/**
Expand Down Expand Up @@ -276,7 +360,7 @@ public function base_inlineDiscussionOptions_handler($sender, $args) {
* @param $args
*/
public function base_beforeCommentDisplay_handler($sender, $args) {
if($sender->deliveryType() != DELIVERY_TYPE_ALL) {
if($sender->deliveryType() != DELIVERY_TYPE_ALL) { // Editing a comment is processed by PostController
// Ajax request to post new comments or update comments
if(isset($_SERVER['HTTP_REFERER'])) {
$previous = $_SERVER['HTTP_REFERER'];
Expand All @@ -286,13 +370,13 @@ public function base_beforeCommentDisplay_handler($sender, $args) {
if(!$viewMode) {
$viewMode = self::isPagingUrl($previous) ? self::VIEW_FLAT : self::VIEW_THREADED;
}
$sender->setData('ViewMode', $viewMode);
$sender->setData(self::VIEW_MODE, $viewMode);
if($viewMode == self::VIEW_THREADED) {
$this->buildCommentReplyToCssClasses($sender);
}
}
} else {
$viewMode = self::getViewMode();
$viewMode = $sender->data(self::VIEW_MODE);
if($viewMode == self::VIEW_THREADED) {
$this->buildCommentReplyToCssClasses($sender);
}
Expand Down
25 changes: 0 additions & 25 deletions ReplyTo/js/replyto.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ jQuery(document).ready(function($) {
return (href.split(name + '=')[1] || '').split('&')[0];
}

//If view is not flat, reload a page to rebuild a tree
function reloadPage() {
var currentView = param(window.location.href, 'view');
return currentView == 'threaded';
}

$(document).on('click','a.ReplyComment', function(ev) {
var btn = this;
var parent = $(btn).parents('.MainContent');
Expand Down Expand Up @@ -61,25 +55,6 @@ jQuery(document).ready(function($) {
return false;
});


// Comment was added.
$(document).on('CommentAdded',function(ev) {
if (reloadPage() === true) {
window.location.reload();
return false;
}
return false;
});

// Comment was deleted.
$(document).on('CommentDeleted',function(ev) {
if (reloadPage() === true) {
window.location.reload();
return false;
}
return false;
});

$(document).on('click','a.CancelReplyComment', function(ev) {
clearReplyCommentForm(this);
return false;
Expand Down
15 changes: 13 additions & 2 deletions Topcoder/class.topcoder.plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,10 @@ private static function topcoderUserTopcoderCache($userFields) {
return $cached;
}

public static function isUnclickableUser($userName) {
return strtolower($userName) == 'tcadmin';
}

public static function log($message, $data = []) {
if (c('Vanilla.SSO.Debug') || c('Debug')) {
Logger::event(
Expand Down Expand Up @@ -2046,7 +2050,8 @@ function userPhoto($user, $options = []) {

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

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

// Go to Topcoder user profile link instead of Vanilla profile link
$userUrl = topcoderUserUrl($user, $px);
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
$userUrl = $isUnlickableUser? '#' : topcoderUserUrl($user, $px);

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

if($isUnlickableUser) {
$attributes['class'] = $attributes['class'].' '. 'disabledLink' ;
}


Gdn::controller()->EventArguments['User'] = $user;
Gdn::controller()->EventArguments['IsTopcoderAdmin'] =$isTopcoderAdmin;
Gdn::controller()->EventArguments['Text'] =& $text;
Expand Down
Loading