Skip to content

v1.9 - Self service app #115

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 27 commits into from
Feb 2, 2022
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8897d38
MFE-issues-9:redirect to mf forums
atelomycterus Dec 1, 2021
23385fc
Merge pull request #105 from topcoder-platform/mfe-issues-9
jmgasper Dec 1, 2021
0a522f6
mfe-issues-8: Rollback some changes
atelomycterus Dec 4, 2021
4844a9b
Merge pull request #106 from topcoder-platform/mfe-issues-9
jmgasper Dec 5, 2021
ef6270f
Issues-648: disable links for MFE
atelomycterus Jan 6, 2022
df89179
Merge pull request #107 from topcoder-platform/issues-648
jmgasper Jan 6, 2022
7aec19f
Issues-652: Client Manger - no navigation when embedded
atelomycterus Jan 11, 2022
0aba4d2
Merge pull request #108 from topcoder-platform/issues-652
jmgasper Jan 11, 2022
be8d124
Issues-652: fixed Client Manager role
atelomycterus Jan 17, 2022
e2b94b5
Merge pull request #109 from topcoder-platform/issues-652
jmgasper Jan 17, 2022
cddd782
Issues-652: fixed ChallengeID in Vanilla Dispatcher
atelomycterus Jan 18, 2022
d08087a
Merge pull request #110 from topcoder-platform/issues-652
jmgasper Jan 18, 2022
99fd309
Support a self-service flag
atelomycterus Jan 21, 2022
ce71bf1
Merge pull request #111 from topcoder-platform/issues-663
jmgasper Jan 21, 2022
da272cd
Issues-662: email massage tweaks for MFE
atelomycterus Jan 22, 2022
c66e711
Merge pull request #112 from topcoder-platform/issues-662
jmgasper Jan 22, 2022
5d7d277
Use a new email template for Client Manager
atelomycterus Jan 26, 2022
4dbce4b
Merge pull request #113 from topcoder-platform/issues-670
jmgasper Jan 26, 2022
45abf07
Tweak template text
jmgasper Jan 26, 2022
2b4c9f6
Issues-670: Updated email message for Client Manager
atelomycterus Jan 27, 2022
2a496af
Issues-670: Updated email message for Client Manager
atelomycterus Jan 27, 2022
7123413
Merge branch 'develop' into issues-670
atelomycterus Jan 27, 2022
7e59c6d
Merge pull request #114 from topcoder-platform/issues-670
jmgasper Jan 27, 2022
a3c6c03
Template tweak, at Topcoder's request
jmgasper Jan 27, 2022
cf698db
Template fix for compile error
jmgasper Jan 27, 2022
bc8f34d
Template tweak for Topcoder
jmgasper Jan 27, 2022
2b516b5
Issues-674: fix a breadcrumb for sel-service
atelomycterus Jan 28, 2022
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
251 changes: 239 additions & 12 deletions Topcoder/class.topcoder.plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ public function gdn_auth_startAuthenticator_handler() {
if(!c('Garden.Installed')) {
return;
}
self::log('Embedded Settings', ['Garden.Embed.Allow' => c('Garden.Embed.Allow')]);

self::log('Cache', ['Active Cache' => Gdn_Cache::activeCache(), 'Type' =>Gdn::cache()->type()]);

if(!$this->isDefault()) {
Expand Down Expand Up @@ -895,7 +897,7 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
}
} else if($args['Controller'] instanceof GroupController) {
if (array_key_exists('groupid', $methodArgs)) {
$groupID = (int) $methodArgs['groupid'];
$groupID = self::convertToGroupID($methodArgs['groupid']);
}
} else if($args['Controller'] instanceof PostController) {
if (array_key_exists('discussionid', $methodArgs)) {
Expand Down Expand Up @@ -932,19 +934,68 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
$group = $groupModel->getByGroupID($groupID);
$category = $categoryModel->getByCode($group->ChallengeID);
$categoryID= val('CategoryID', $category);
Gdn::controller()->setData('Breadcrumbs.Options.GroupCategoryID', $categoryID);
Gdn::controller()->setData('Breadcrumbs.Options.GroupID', $groupID);
Gdn::controller()->setData('Breadcrumbs.Options.ChallengeID', $group->ChallengeID);
$controller = $args['Controller'];
$controller->setData('BreadcrumbsOptionsGroupCategoryID', $categoryID);
$controller->setData('BreadcrumbsOptionsGroupID', $groupID);
$controller->setData('BreadcrumbsOptionsChallengeID', $group->ChallengeID);
if ($group->ChallengeID) {
$this->setTopcoderProjectData($args['Controller'], $group->ChallengeID);
$this->setTopcoderProjectData($controller, $group->ChallengeID);
}
}
}

private static function convertToGroupID($id) {
if(is_numeric($id) && $id > 0) {
return $id;
}

if(self::isValidUuid($id) === true) {
$categoryModel = new CategoryModel();
$category = $categoryModel->getByCode($id);
return val('GroupID', $category, 0);
}

return 0;
}

private static function isValidUuid($uuid) {
if(!is_string($uuid)) {
return false;
}
if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $uuid)) {
return false;
}
return true;
}

public function base_beforeBuildBreadcrumbs_handler($sender, $args) {
if(Gdn::session()->isValid()) {
$showFullBreadcrumbs = & $args['ShowFullBreadcrumbs'];
//FIX Issues-652: Client Manager - no navigation when embedded
$showFullBreadcrumbs = !hideInMFE();
}
}
/**
* Add scripts. Add script to hide iPhone browser bar on pageload.
*/
public function base_render_before($sender) {
if(isset($_SERVER['HTTP_REFERER'])) {
$url = $_SERVER['HTTP_REFERER'];
parse_str( parse_url( $url, PHP_URL_QUERY), $array );
$embedType = $array['mbed_type'];
if($embedType == 'mfe') {
$sender->addDefinition('MFEEmbedded', '1');
$sender->MasterView = 'mfe';
// logMessage(__FILE__,__LINE__,'TopcoderPlugin','base_render_before',"Use Embed Master Template due to HTTP_REFERER".$url);
}
}

// Force view options
if(getIncomingValue('embed_type') == 'mfe') {
$sender->addDefinition('MFEEmbedded', '1');
$sender->MasterView = 'mfe';
// logMessage(__FILE__,__LINE__,'TopcoderPlugin','base_render_before',"Use Embed Master Template due to Query Param");
}
if (is_object($sender->Head)) {
$sender->Head->addString($this->getJS());
}
Expand Down Expand Up @@ -1574,6 +1625,7 @@ public function getChallenge($challengeId) {
$cachedChallenge['StartDate'] = $startDate;
$cachedChallenge['EndDate'] = $endDate;
$cachedChallenge['Track'] = $challenge->track;
$cachedChallenge['IsSelfService'] = $challenge->legacy->selfService;
$termIDs = array_column($challenge->terms, 'id');
$NDA_UUID = c('Plugins.Topcoder.NDA_UUID');
$cachedChallenge['IsNDA'] = in_array($NDA_UUID, $termIDs);
Expand Down Expand Up @@ -1750,6 +1802,39 @@ private static function isTopcoderAdmin($topcoderRoles = false) {
return false;
}

/**
* Check if the list of Topcoder roles includes 'Client Manager' role
* @return bool true, if the list of Topcoder roles includes 'Client Manager'
*/
public static function isTopcoderClientManager() {
if(!Gdn::session()->isValid()) {
return false;
}
$topcoderRoles = Gdn::controller()->data("ChallengeCurrentUserProjectRoles");
if($topcoderRoles) {
$lowerRoleNames = array_map('strtolower', $topcoderRoles);
return count(array_intersect($lowerRoleNames, ["client manager"])) > 0;
}

return false;
}

/**
* Check if the challenge has self-service flag
* @return bool true, if the challenge has self-service flag
*/
public static function isChallengeSelfService() {
if(!Gdn::session()->isValid()) {
return false;
}
$challenge = Gdn::controller()->data("Challenge");
if($challenge) {
return $challenge['IsSelfService'];
}

return false;
}

/**
* Get Topcoder Role names
* @param false $topcoderRoles
Expand Down Expand Up @@ -1871,7 +1956,7 @@ private function setTopcoderProjectData($sender, $challengeID) {
// if($sender->GroupModel) {
// $sender->GroupModel->setCurrentUserTopcoderProjectRoles($currentProjectRoles);
// }
self::log('setTopcoderProjectData', ['ChallengeID' => $challengeID, 'currentUser' => $currentProjectRoles,
self::log('setTopcoderProjectData', ['ChallengeID' => $challengeID, 'CurrentUserProjectRoles' => $currentProjectRoles,
'Topcoder Resources' => $resources , 'Topcoder RoleResources'
=> $roleResources, 'challenge' =>$challenge]);
}
Expand Down Expand Up @@ -1955,11 +2040,21 @@ private static function topcoderUserCache($userFields) {
return $cached;
}

// TODO: Debugging issues-108
// Support Micro-frontends forums app
public function gdn_dispatcher_beforeDispatch_handler($sender, $args) {
self::log('gdn_dispatcher_beforeDispatch_handler', [
$mfeUrl = c("Garden.Embed.RemoteUrl");
$isEmbedded = (bool) c('Garden.Embed.Allow', false);

$data = array(
'Garden.Embed.Allow' => $isEmbedded,
'MFEUrl' => $mfeUrl,
'Request(current fullPath)' => Gdn::request()->getFullPath(),
'Request(pathAndQuery)' => Gdn::request()->pathAndQuery(),
'Request(Method)'=> Gdn::request()->getMethod(),
'Permissions' => Gdn::session()->getPermissionsArray(),
]);
);
// logMessage(__FILE__, __LINE__, 'TopcoderPlugin', "Data", json_encode($data ));
// self::log('gdn_dispatcher_beforeDispatch_handler', $data);
}

// Topcoder Cache is used for caching Topcoder Users by handle.
Expand Down Expand Up @@ -2293,6 +2388,103 @@ public function profileController_preferences_create($sender, $userReference = '
$sender->_setBreadcrumbs($sender->data('Title'), $sender->canonicalUrl());
$sender->render();
}

// All notified users have been added in an activity. This called before adding an activity in an activity Queue and sending+saving it in DB
public function activityModel_BeforeCheckPreference_handler($sender, $args) {
$activity = &$args['Data'];
$notifyUserID = val('NotifyUserID', $activity);
$userModel = new UserModel();
$user = $userModel->getID($notifyUserID);
$data = $activity['Data'];
$challengeID = $data['ChallengeID'];
if($challengeID) {
$activityType = $activity['RecordType'];
if($activityType == 'Discussion' || $activityType == 'Comment') {
$resources = $this->getChallengeResources($challengeID);
$roleResources = $this->getRoleResources();
$currentProjectRoles = $this->getTopcoderProjectRoles($user, $resources, $roleResources);
if($currentProjectRoles) {
$currentProjectRoles = array_map('strtolower', $currentProjectRoles);
$isClientManager = count(array_intersect($currentProjectRoles, ["client manager"])) > 0;
if ($isClientManager) {
$recordID = $activity['RecordID'];
$category = CategoryModel::categories($challengeID);
$categoryName = val('Name', $category);
$userModel = new UserModel();
$discussionModel = new DiscussionModel();
if ($activityType == 'Discussion') {
$discussion = $discussionModel->getID($recordID);
$message = Gdn::formatService()->renderQuote(val('Body', $discussion), val('Format', $discussion));
$author = $userModel->getID(val('InsertUserID', $discussion));
$dateInserted = Gdn_Format::dateFull(val('DateInserted',$discussion));
// $categoryBreadcrumbs = array_column(array_values(CategoryModel::getAncestors(val('CategoryID',$discussion))), 'Name');

$activity['Story'] =
'<p>Hi there,</p>' .
'<p>A new message has been posted on the discussion tied to your Topcoder Work "' . $categoryName . '" ' .
'which was updated ' . $dateInserted . ' by ' . $author->Name . ':<p/>' .
'<hr/>' .
'<div style="padding: 0; margin: 0">' .
'<p><span>Discussion: ' . val('Name', $discussion) . '</p>' .
'<p><span>Author: ' . val('Name', $author) . '</p>' .
// '<p><span>Category: ' . implode('›', $categoryBreadcrumbs) . '</p>' .
'<p><span>Message:</span> ' . $message . '</p>' .
'<hr/>'.
'<p>To answer, click "Open Discussion" below to be taken to this discussion.<br/>
Please do not reply to this email.<br/>
Thank you!
The Topcoder Team</p>' .
'</div>' .
'<hr/>';

} else { // Comment
$commentModel = new CommentModel();
$comment = $commentModel->getID($recordID);
// $discussion = $discussionModel->getID(val('DiscussionID', $comment));
// $discussionName = val('Name',$discussion);
$commentDateInserted = Gdn_Format::dateFull(val('DateInserted',$comment));
$commentAuthor = $userModel->getID(val('InsertUserID',$comment));
$commentStory = Gdn::formatService()->renderQuote(val('Body',$comment), val('Format',$comment));
$activity['Story'] =
'<p>Hi there,</p>' .
'<p>A new message has been posted on the discussion tied to your Topcoder Work "' . $categoryName . '" ' .
'which was updated ' . $commentDateInserted . ' by ' . val('Name',$commentAuthor) . ':</p>' .
'<hr/>' .
'<p class="label"><span style="display: block">Message:</span>'.'</p>' .
$commentStory .
'<br/><hr/>';

$parentCommentID = (int)val('ParentCommentID',$comment);
if($parentCommentID > 0) {
$parentComment = $commentModel->getID($parentCommentID, DATASET_TYPE_ARRAY);
$parentCommentAuthor = $userModel->getID($parentComment['InsertUserID']);
$parentCommentStory = condense(Gdn_Format::to($parentComment['Body'], $parentComment['Format']));
$activity['Story'] .=
'<p class="label">Original Message (by '.$parentCommentAuthor->Name.' ):</p>'.
'<p>' .
$parentCommentStory.
'</p>' .
'<hr/>';
}
$activity['Story'] .= '<p>To answer, click "Open Discussion" below to be taken to this discussion.<br/>
Please do not reply to this email.<br/>
Thank you!
The Topcoder Team</p>';
}

$headline = 'Message From a Topcoder Member on Your Work - Please See';
$activity['HeadlineFormat'] = $headline;
$activity['Headline'] = $headline;
$activity['Data']['EmailUrl'] = val('EmbedUrl', $data);
$activity['Data']['EmailTemplate'] = 'email-selfservice';
return;
}
}
}
}
$activity['Data']['EmailUrl'] = externalUrl(val('Route', $activity) == '' ? '/' : val('Route', $activity));
$activity['Data']['EmailTemplate'] = 'email-basic';
}
}

if(!function_exists('topcoderRatingCssClass')) {
Expand Down Expand Up @@ -2436,9 +2628,11 @@ function userPhoto($user, $options = []) {
}

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

Gdn::controller()->EventArguments['User'] = $user;
Gdn::controller()->EventArguments['Title'] =& $title;
Expand Down Expand Up @@ -2527,11 +2721,14 @@ function userAnchor($user, $cssClass = null, $options = null) {
$attributes['title'] = $options['title'];
}

$topcoderProfile = TopcoderPlugin::getTopcoderUser($userID);

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

$topcoderProfile = TopcoderPlugin::getTopcoderUser($userID);

$topcoderRating = val('Rating',$topcoderProfile, false);
if($topcoderRating != false || $topcoderRating == null) {
$coderStyles = TopcoderPlugin::getRatingCssClass($topcoderRating);
Expand Down Expand Up @@ -2838,4 +3035,34 @@ function watchingSorts($extraClasses = '') {
'Sort'
);
}
}

if (!function_exists('isMFE')) {
function isMFE() {
return getIncomingValue('embed_type') == 'mfe';
}
}

if (!function_exists('hideInMFE')) {
function hideInMFE() {
if (!Gdn::session()->isValid()) {
return false;
}
//FIX Issues-652: Client Manager - no navigation when embedded
$isMFE = isMFE();
$isTopcoderClientManager = TopcoderPlugin::isTopcoderClientManager();
if ($isMFE && $isTopcoderClientManager) {
return true;
}
return false;
}
}

if (!function_exists('isSelfService')) {
function isSelfService() {
if (!Gdn::session()->isValid()) {
return false;
}
return TopcoderPlugin::isChallengeSelfService();
}
}