Skip to content

Commit 73d9aa1

Browse files
authored
Merge pull request #115 from topcoder-platform/develop
v1.9 - Self service app
2 parents 8dfbf8b + 2b516b5 commit 73d9aa1

File tree

1 file changed

+239
-12
lines changed

1 file changed

+239
-12
lines changed

Topcoder/class.topcoder.plugin.php

Lines changed: 239 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ public function gdn_auth_startAuthenticator_handler() {
284284
if(!c('Garden.Installed')) {
285285
return;
286286
}
287+
self::log('Embedded Settings', ['Garden.Embed.Allow' => c('Garden.Embed.Allow')]);
288+
287289
self::log('Cache', ['Active Cache' => Gdn_Cache::activeCache(), 'Type' =>Gdn::cache()->type()]);
288290

289291
if(!$this->isDefault()) {
@@ -895,7 +897,7 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
895897
}
896898
} else if($args['Controller'] instanceof GroupController) {
897899
if (array_key_exists('groupid', $methodArgs)) {
898-
$groupID = (int) $methodArgs['groupid'];
900+
$groupID = self::convertToGroupID($methodArgs['groupid']);
899901
}
900902
} else if($args['Controller'] instanceof PostController) {
901903
if (array_key_exists('discussionid', $methodArgs)) {
@@ -932,19 +934,68 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
932934
$group = $groupModel->getByGroupID($groupID);
933935
$category = $categoryModel->getByCode($group->ChallengeID);
934936
$categoryID= val('CategoryID', $category);
935-
Gdn::controller()->setData('Breadcrumbs.Options.GroupCategoryID', $categoryID);
936-
Gdn::controller()->setData('Breadcrumbs.Options.GroupID', $groupID);
937-
Gdn::controller()->setData('Breadcrumbs.Options.ChallengeID', $group->ChallengeID);
937+
$controller = $args['Controller'];
938+
$controller->setData('BreadcrumbsOptionsGroupCategoryID', $categoryID);
939+
$controller->setData('BreadcrumbsOptionsGroupID', $groupID);
940+
$controller->setData('BreadcrumbsOptionsChallengeID', $group->ChallengeID);
938941
if ($group->ChallengeID) {
939-
$this->setTopcoderProjectData($args['Controller'], $group->ChallengeID);
942+
$this->setTopcoderProjectData($controller, $group->ChallengeID);
940943
}
941944
}
942945
}
943946

947+
private static function convertToGroupID($id) {
948+
if(is_numeric($id) && $id > 0) {
949+
return $id;
950+
}
951+
952+
if(self::isValidUuid($id) === true) {
953+
$categoryModel = new CategoryModel();
954+
$category = $categoryModel->getByCode($id);
955+
return val('GroupID', $category, 0);
956+
}
957+
958+
return 0;
959+
}
960+
961+
private static function isValidUuid($uuid) {
962+
if(!is_string($uuid)) {
963+
return false;
964+
}
965+
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)) {
966+
return false;
967+
}
968+
return true;
969+
}
970+
971+
public function base_beforeBuildBreadcrumbs_handler($sender, $args) {
972+
if(Gdn::session()->isValid()) {
973+
$showFullBreadcrumbs = & $args['ShowFullBreadcrumbs'];
974+
//FIX Issues-652: Client Manager - no navigation when embedded
975+
$showFullBreadcrumbs = !hideInMFE();
976+
}
977+
}
944978
/**
945979
* Add scripts. Add script to hide iPhone browser bar on pageload.
946980
*/
947981
public function base_render_before($sender) {
982+
if(isset($_SERVER['HTTP_REFERER'])) {
983+
$url = $_SERVER['HTTP_REFERER'];
984+
parse_str( parse_url( $url, PHP_URL_QUERY), $array );
985+
$embedType = $array['mbed_type'];
986+
if($embedType == 'mfe') {
987+
$sender->addDefinition('MFEEmbedded', '1');
988+
$sender->MasterView = 'mfe';
989+
// logMessage(__FILE__,__LINE__,'TopcoderPlugin','base_render_before',"Use Embed Master Template due to HTTP_REFERER".$url);
990+
}
991+
}
992+
993+
// Force view options
994+
if(getIncomingValue('embed_type') == 'mfe') {
995+
$sender->addDefinition('MFEEmbedded', '1');
996+
$sender->MasterView = 'mfe';
997+
// logMessage(__FILE__,__LINE__,'TopcoderPlugin','base_render_before',"Use Embed Master Template due to Query Param");
998+
}
948999
if (is_object($sender->Head)) {
9491000
$sender->Head->addString($this->getJS());
9501001
}
@@ -1574,6 +1625,7 @@ public function getChallenge($challengeId) {
15741625
$cachedChallenge['StartDate'] = $startDate;
15751626
$cachedChallenge['EndDate'] = $endDate;
15761627
$cachedChallenge['Track'] = $challenge->track;
1628+
$cachedChallenge['IsSelfService'] = $challenge->legacy->selfService;
15771629
$termIDs = array_column($challenge->terms, 'id');
15781630
$NDA_UUID = c('Plugins.Topcoder.NDA_UUID');
15791631
$cachedChallenge['IsNDA'] = in_array($NDA_UUID, $termIDs);
@@ -1750,6 +1802,39 @@ private static function isTopcoderAdmin($topcoderRoles = false) {
17501802
return false;
17511803
}
17521804

1805+
/**
1806+
* Check if the list of Topcoder roles includes 'Client Manager' role
1807+
* @return bool true, if the list of Topcoder roles includes 'Client Manager'
1808+
*/
1809+
public static function isTopcoderClientManager() {
1810+
if(!Gdn::session()->isValid()) {
1811+
return false;
1812+
}
1813+
$topcoderRoles = Gdn::controller()->data("ChallengeCurrentUserProjectRoles");
1814+
if($topcoderRoles) {
1815+
$lowerRoleNames = array_map('strtolower', $topcoderRoles);
1816+
return count(array_intersect($lowerRoleNames, ["client manager"])) > 0;
1817+
}
1818+
1819+
return false;
1820+
}
1821+
1822+
/**
1823+
* Check if the challenge has self-service flag
1824+
* @return bool true, if the challenge has self-service flag
1825+
*/
1826+
public static function isChallengeSelfService() {
1827+
if(!Gdn::session()->isValid()) {
1828+
return false;
1829+
}
1830+
$challenge = Gdn::controller()->data("Challenge");
1831+
if($challenge) {
1832+
return $challenge['IsSelfService'];
1833+
}
1834+
1835+
return false;
1836+
}
1837+
17531838
/**
17541839
* Get Topcoder Role names
17551840
* @param false $topcoderRoles
@@ -1871,7 +1956,7 @@ private function setTopcoderProjectData($sender, $challengeID) {
18711956
// if($sender->GroupModel) {
18721957
// $sender->GroupModel->setCurrentUserTopcoderProjectRoles($currentProjectRoles);
18731958
// }
1874-
self::log('setTopcoderProjectData', ['ChallengeID' => $challengeID, 'currentUser' => $currentProjectRoles,
1959+
self::log('setTopcoderProjectData', ['ChallengeID' => $challengeID, 'CurrentUserProjectRoles' => $currentProjectRoles,
18751960
'Topcoder Resources' => $resources , 'Topcoder RoleResources'
18761961
=> $roleResources, 'challenge' =>$challenge]);
18771962
}
@@ -1955,11 +2040,21 @@ private static function topcoderUserCache($userFields) {
19552040
return $cached;
19562041
}
19572042

1958-
// TODO: Debugging issues-108
2043+
// Support Micro-frontends forums app
19592044
public function gdn_dispatcher_beforeDispatch_handler($sender, $args) {
1960-
self::log('gdn_dispatcher_beforeDispatch_handler', [
2045+
$mfeUrl = c("Garden.Embed.RemoteUrl");
2046+
$isEmbedded = (bool) c('Garden.Embed.Allow', false);
2047+
2048+
$data = array(
2049+
'Garden.Embed.Allow' => $isEmbedded,
2050+
'MFEUrl' => $mfeUrl,
2051+
'Request(current fullPath)' => Gdn::request()->getFullPath(),
2052+
'Request(pathAndQuery)' => Gdn::request()->pathAndQuery(),
2053+
'Request(Method)'=> Gdn::request()->getMethod(),
19612054
'Permissions' => Gdn::session()->getPermissionsArray(),
1962-
]);
2055+
);
2056+
// logMessage(__FILE__, __LINE__, 'TopcoderPlugin', "Data", json_encode($data ));
2057+
// self::log('gdn_dispatcher_beforeDispatch_handler', $data);
19632058
}
19642059

19652060
// Topcoder Cache is used for caching Topcoder Users by handle.
@@ -2293,6 +2388,103 @@ public function profileController_preferences_create($sender, $userReference = '
22932388
$sender->_setBreadcrumbs($sender->data('Title'), $sender->canonicalUrl());
22942389
$sender->render();
22952390
}
2391+
2392+
// 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
2393+
public function activityModel_BeforeCheckPreference_handler($sender, $args) {
2394+
$activity = &$args['Data'];
2395+
$notifyUserID = val('NotifyUserID', $activity);
2396+
$userModel = new UserModel();
2397+
$user = $userModel->getID($notifyUserID);
2398+
$data = $activity['Data'];
2399+
$challengeID = $data['ChallengeID'];
2400+
if($challengeID) {
2401+
$activityType = $activity['RecordType'];
2402+
if($activityType == 'Discussion' || $activityType == 'Comment') {
2403+
$resources = $this->getChallengeResources($challengeID);
2404+
$roleResources = $this->getRoleResources();
2405+
$currentProjectRoles = $this->getTopcoderProjectRoles($user, $resources, $roleResources);
2406+
if($currentProjectRoles) {
2407+
$currentProjectRoles = array_map('strtolower', $currentProjectRoles);
2408+
$isClientManager = count(array_intersect($currentProjectRoles, ["client manager"])) > 0;
2409+
if ($isClientManager) {
2410+
$recordID = $activity['RecordID'];
2411+
$category = CategoryModel::categories($challengeID);
2412+
$categoryName = val('Name', $category);
2413+
$userModel = new UserModel();
2414+
$discussionModel = new DiscussionModel();
2415+
if ($activityType == 'Discussion') {
2416+
$discussion = $discussionModel->getID($recordID);
2417+
$message = Gdn::formatService()->renderQuote(val('Body', $discussion), val('Format', $discussion));
2418+
$author = $userModel->getID(val('InsertUserID', $discussion));
2419+
$dateInserted = Gdn_Format::dateFull(val('DateInserted',$discussion));
2420+
// $categoryBreadcrumbs = array_column(array_values(CategoryModel::getAncestors(val('CategoryID',$discussion))), 'Name');
2421+
2422+
$activity['Story'] =
2423+
'<p>Hi there,</p>' .
2424+
'<p>A new message has been posted on the discussion tied to your Topcoder Work "' . $categoryName . '" ' .
2425+
'which was updated ' . $dateInserted . ' by ' . $author->Name . ':<p/>' .
2426+
'<hr/>' .
2427+
'<div style="padding: 0; margin: 0">' .
2428+
'<p><span>Discussion: ' . val('Name', $discussion) . '</p>' .
2429+
'<p><span>Author: ' . val('Name', $author) . '</p>' .
2430+
// '<p><span>Category: ' . implode('›', $categoryBreadcrumbs) . '</p>' .
2431+
'<p><span>Message:</span> ' . $message . '</p>' .
2432+
'<hr/>'.
2433+
'<p>To answer, click "Open Discussion" below to be taken to this discussion.<br/>
2434+
Please do not reply to this email.<br/>
2435+
Thank you!
2436+
The Topcoder Team</p>' .
2437+
'</div>' .
2438+
'<hr/>';
2439+
2440+
} else { // Comment
2441+
$commentModel = new CommentModel();
2442+
$comment = $commentModel->getID($recordID);
2443+
// $discussion = $discussionModel->getID(val('DiscussionID', $comment));
2444+
// $discussionName = val('Name',$discussion);
2445+
$commentDateInserted = Gdn_Format::dateFull(val('DateInserted',$comment));
2446+
$commentAuthor = $userModel->getID(val('InsertUserID',$comment));
2447+
$commentStory = Gdn::formatService()->renderQuote(val('Body',$comment), val('Format',$comment));
2448+
$activity['Story'] =
2449+
'<p>Hi there,</p>' .
2450+
'<p>A new message has been posted on the discussion tied to your Topcoder Work "' . $categoryName . '" ' .
2451+
'which was updated ' . $commentDateInserted . ' by ' . val('Name',$commentAuthor) . ':</p>' .
2452+
'<hr/>' .
2453+
'<p class="label"><span style="display: block">Message:</span>'.'</p>' .
2454+
$commentStory .
2455+
'<br/><hr/>';
2456+
2457+
$parentCommentID = (int)val('ParentCommentID',$comment);
2458+
if($parentCommentID > 0) {
2459+
$parentComment = $commentModel->getID($parentCommentID, DATASET_TYPE_ARRAY);
2460+
$parentCommentAuthor = $userModel->getID($parentComment['InsertUserID']);
2461+
$parentCommentStory = condense(Gdn_Format::to($parentComment['Body'], $parentComment['Format']));
2462+
$activity['Story'] .=
2463+
'<p class="label">Original Message (by '.$parentCommentAuthor->Name.' ):</p>'.
2464+
'<p>' .
2465+
$parentCommentStory.
2466+
'</p>' .
2467+
'<hr/>';
2468+
}
2469+
$activity['Story'] .= '<p>To answer, click "Open Discussion" below to be taken to this discussion.<br/>
2470+
Please do not reply to this email.<br/>
2471+
Thank you!
2472+
The Topcoder Team</p>';
2473+
}
2474+
2475+
$headline = 'Message From a Topcoder Member on Your Work - Please See';
2476+
$activity['HeadlineFormat'] = $headline;
2477+
$activity['Headline'] = $headline;
2478+
$activity['Data']['EmailUrl'] = val('EmbedUrl', $data);
2479+
$activity['Data']['EmailTemplate'] = 'email-selfservice';
2480+
return;
2481+
}
2482+
}
2483+
}
2484+
}
2485+
$activity['Data']['EmailUrl'] = externalUrl(val('Route', $activity) == '' ? '/' : val('Route', $activity));
2486+
$activity['Data']['EmailTemplate'] = 'email-basic';
2487+
}
22962488
}
22972489

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

24382630
$isTopcoderAdmin = val('IsAdmin', $topcoderProfile);
2631+
$isTopcoderClientManager = TopcoderPlugin::isTopcoderClientManager();
24392632
$photoUrl = isset($photoUrl) && !empty(trim($photoUrl)) ? $photoUrl: UserModel::getDefaultAvatarUrl();
24402633
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
2441-
$href = (val('NoLink', $options)) || $isUnlickableUser ? '' : ' href="'.url($userLink).'"';
2634+
$href = (val('NoLink', $options)) || $isUnlickableUser ||
2635+
($isTopcoderClientManager && getIncomingValue('embed_type') == 'mfe') ? '' : ' href="'.url($userLink).'"';
24422636

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

2724+
$topcoderProfile = TopcoderPlugin::getTopcoderUser($userID);
2725+
25302726
// Go to Topcoder user profile link instead of Vanilla profile link
2531-
$isUnlickableUser = TopcoderPlugin::isUnclickableUser($name);
2727+
$isTopcoderClientManager = TopcoderPlugin::isTopcoderClientManager();
2728+
$isUnlickableUser = ( $isTopcoderClientManager && getIncomingValue('embed_type') == 'mfe') || TopcoderPlugin::isUnclickableUser($name);
25322729
$userUrl = $isUnlickableUser? '#' : topcoderUserUrl($user, $px);
25332730

2534-
$topcoderProfile = TopcoderPlugin::getTopcoderUser($userID);
2731+
25352732
$topcoderRating = val('Rating',$topcoderProfile, false);
25362733
if($topcoderRating != false || $topcoderRating == null) {
25372734
$coderStyles = TopcoderPlugin::getRatingCssClass($topcoderRating);
@@ -2838,4 +3035,34 @@ function watchingSorts($extraClasses = '') {
28383035
'Sort'
28393036
);
28403037
}
3038+
}
3039+
3040+
if (!function_exists('isMFE')) {
3041+
function isMFE() {
3042+
return getIncomingValue('embed_type') == 'mfe';
3043+
}
3044+
}
3045+
3046+
if (!function_exists('hideInMFE')) {
3047+
function hideInMFE() {
3048+
if (!Gdn::session()->isValid()) {
3049+
return false;
3050+
}
3051+
//FIX Issues-652: Client Manager - no navigation when embedded
3052+
$isMFE = isMFE();
3053+
$isTopcoderClientManager = TopcoderPlugin::isTopcoderClientManager();
3054+
if ($isMFE && $isTopcoderClientManager) {
3055+
return true;
3056+
}
3057+
return false;
3058+
}
3059+
}
3060+
3061+
if (!function_exists('isSelfService')) {
3062+
function isSelfService() {
3063+
if (!Gdn::session()->isValid()) {
3064+
return false;
3065+
}
3066+
return TopcoderPlugin::isChallengeSelfService();
3067+
}
28413068
}

0 commit comments

Comments
 (0)