Skip to content

Commit 4e85d92

Browse files
authored
Merge pull request #17 from topcoder-platform/forums-issues-24_25
Forums issues 24 25
2 parents 2297129 + 5c91615 commit 4e85d92

File tree

2 files changed

+169
-13
lines changed

2 files changed

+169
-13
lines changed

Topcoder/class.topcoder.plugin.php

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ public function settingsController_topcoder_create($sender) {
3030
$cf->initialize([
3131
'Plugins.Topcoder.BaseApiURL' => ['Control' => 'TextBox', 'Default' => 'https://api.topcoder-dev.com', 'Description' => 'TopCoder Base API URL'],
3232
'Plugins.Topcoder.MemberApiURI' => ['Control' => 'TextBox', 'Default' => '/v3/members', 'Description' => 'Topcoder Member API URI'],
33+
'Plugins.Topcoder.RoleApiURI' => ['Control' => 'TextBox', 'Default' => '/v3/roles', 'Description' => 'Topcoder Role API URI'],
3334
'Plugins.Topcoder.MemberProfileURL' => ['Control' => 'TextBox', 'Default' => 'https://www.topcoder.com/members', 'Description' => 'Topcoder Member Profile URL'],
35+
3436
]);
3537

3638
$sender->setData('Title', sprintf(t('%s Settings'), 'Topcoder'));
@@ -274,6 +276,132 @@ public static function getTopcoderProfile($name) {
274276
return null;
275277
}
276278

279+
/**
280+
* Get a Topcoder Member Id by Topcoder handle
281+
* @param $name vanilla user name
282+
* @return null|int
283+
*/
284+
public static function getTopcoderId($name) {
285+
$topcoderMembersApiUrl = c('Plugins.Topcoder.BaseApiURL').c('Plugins.Topcoder.MemberApiURI');
286+
$memberData = @file_get_contents($topcoderMembersApiUrl.'/'.$name);
287+
if($memberData === false) {
288+
// Handle errors (e.g. 404 and others)
289+
return null;
290+
}
291+
$memberResponse = json_decode($memberData);
292+
//Use a photo of Topcoder member if the member with the given user name exists and photoUrl is not null
293+
if($memberResponse->result->status === 200 && $memberResponse->result->content !== null) {
294+
return $memberResponse->result->content->userId;
295+
}
296+
return null;
297+
}
298+
299+
/**
300+
* Generate machine to machine token from Auth0
301+
* @return null|String m2m token
302+
*/
303+
public static function getM2MToken()
304+
{
305+
$TOPCODER_AUTH0_CLIENT_ID = getenv('TOPCODER_AUTH0_CLIENT_ID');
306+
$TOPCODER_AUTH0_CLIENT_SECRET = getenv('TOPCODER_AUTH0_CLIENT_SECRET');
307+
$TOPCODER_AUTH0_AUDIENCE = getenv('TOPCODER_AUTH0_AUDIENCE');
308+
$TOPCODER_AUTH0_URL = getenv('TOPCODER_AUTH0_URL');
309+
$TOPCODER_AUTH0_PROXY_SERVER_URL = getenv('TOPCODER_AUTH0_PROXY_SERVER_URL');
310+
311+
$issetM2MParams = (isset($TOPCODER_AUTH0_CLIENT_ID) &&
312+
isset($TOPCODER_AUTH0_CLIENT_SECRET) &&
313+
isset($TOPCODER_AUTH0_AUDIENCE) &&
314+
isset($TOPCODER_AUTH0_URL) &&
315+
isset($TOPCODER_AUTH0_PROXY_SERVER_URL));
316+
if(!$issetM2MParams) {
317+
logMessage(__FILE__,__LINE__,'TopcoderPlugin','getM2MToken()',"M2M Token parameters weren't set");
318+
throw new InvalidArgumentException("M2M Token parameters weren't set");
319+
}
320+
321+
$data = array('grant_type' => 'client_credentials',
322+
'client_id' => $TOPCODER_AUTH0_CLIENT_ID,
323+
'client_secret' => $TOPCODER_AUTH0_CLIENT_SECRET,
324+
'audience' => $TOPCODER_AUTH0_AUDIENCE,
325+
'auth0_url' => $TOPCODER_AUTH0_URL);
326+
327+
$m2mOptions = array('http' => array(
328+
'method' => 'POST',
329+
'header' => 'Content-type: application/json',
330+
'content' => json_encode($data)
331+
));
332+
333+
$m2mContext = stream_context_create($m2mOptions);
334+
try {
335+
$m2mTokenData = file_get_contents($TOPCODER_AUTH0_PROXY_SERVER_URL, false, $m2mContext);
336+
$m2mTokenResponse = json_decode($m2mTokenData);
337+
return $m2mTokenResponse->access_token;
338+
} catch (Exception $e) {
339+
logMessage(__FILE__,__LINE__,'TopcoderPlugin','getM2MToken',"M2M token wasn't generated:" .$e.message);
340+
return null;
341+
}
342+
343+
}
344+
345+
/**
346+
* Get a Topcoder Roles
347+
*
348+
* @param $name Topcoder Handle
349+
* @return null|string array of role objects. Example of role object:
350+
* {
351+
* "id":"3",
352+
* "modifiedBy":null,
353+
* "modifiedAt":null,
354+
* "createdBy":null,
355+
* "createdAt":null,
356+
* "roleName":"Connect Support"
357+
* }
358+
*/
359+
public static function getTopcoderRoles($name) {
360+
$topcoderId = TopcoderPlugin::getTopcoderId($name);
361+
if ($topcoderId) {
362+
$token = TopcoderPlugin::getM2MToken();
363+
if ($token) {
364+
$topcoderRolesApiUrl = c('Plugins.Topcoder.BaseApiURL') . c('Plugins.Topcoder.RoleApiURI');
365+
$options = array('http' => array(
366+
'method' => 'GET',
367+
'header' => 'Authorization: Bearer ' .$token
368+
));
369+
$context = stream_context_create($options);
370+
$rolesData = file_get_contents($topcoderRolesApiUrl . '?filter=subjectID%3D' . $topcoderId, false, $context);
371+
if ($rolesData === false) {
372+
// Handle errors (e.g. 404 and others)
373+
logMessage(__FILE__, __LINE__, 'TopcoderPlugin', 'getTopcoderRoles', "Couldn't get Topcoder roles".json_encode($http_response_header));
374+
return null;
375+
}
376+
377+
$rolesResponse = json_decode($rolesData);
378+
if ($rolesResponse->result->status === 200 && $rolesResponse->result->content !== null) {
379+
return $rolesResponse->result->content;
380+
}
381+
}
382+
}
383+
return null;
384+
}
385+
386+
/**
387+
* Check if User has a Topcoder admin role
388+
*
389+
* @param $name username
390+
* @return boolean true if User has Topcoder admin role
391+
*/
392+
public static function hasTopcoderAdminRole($name) {
393+
$roles = TopcoderPlugin::getTopcoderRoles($name);
394+
if($roles) {
395+
$adminRoleNames = array("admin", "administrator");
396+
foreach ($roles as $role) {
397+
if (in_array(strtolower($role->roleName), $adminRoleNames)) {
398+
return true;
399+
}
400+
}
401+
}
402+
return false;
403+
}
404+
277405
/**
278406
* Get a photo url from Topcoder Member Profile
279407
* @param $name vanilla user name
@@ -509,6 +637,22 @@ function userPhotoUrl($user) {
509637
}
510638
}
511639

640+
if (!function_exists('topcoderUserUrl')) {
641+
/**
642+
* Return the URL for a topcoder user.
643+
*
644+
* @param array|object $user The user to get the url for.
645+
* @param string $px The prefix to apply before fieldnames.
646+
* @return string The url suitable to be passed into the url() function.
647+
* @since 2.1
648+
*/
649+
function topcoderUserUrl($user, $px = '') {
650+
$userName = val($px.'Name', $user);
651+
return TopcoderPlugin::getTopcoderProfileUrl(rawurlencode($userName));
652+
}
653+
}
654+
655+
512656
if (!function_exists('userAnchor')) {
513657
/**
514658
* Take a user object, and writes out an anchor of the user's name to the user's profile.
@@ -543,13 +687,19 @@ function userAnchor($user, $cssClass = null, $options = null) {
543687
$attributes['title'] = $options['title'];
544688
}
545689

546-
$userUrl = userUrl($user, $px);
690+
// Go to Topcoder user profile link instead of Vanilla profile link
691+
$userUrl = topcoderUserUrl($user, $px);
692+
547693
$topcoderRating = TopcoderPlugin::getTopcoderRating($name);
548694
if($topcoderRating != null) {
549695
$coderStyles = TopcoderPlugin::getRatingCssClass($topcoderRating);
550696
$attributes['class'] = $attributes['class'].' '.$coderStyles ;
551697
}
552698

699+
$isTopcoderAdmin = TopcoderPlugin::hasTopcoderAdminRole($name);
700+
if($isTopcoderAdmin) {
701+
$attributes['class'] = $attributes['class'].' '. 'topcoderAdmin' ;
702+
}
553703
return '<a href="'.htmlspecialchars(url($userUrl)).'"'.attribute($attributes).'>'.$text.'</a>';
554704
}
555705
}

Topcoder/design/topcoder.css

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
.coderTextRed, .coderTextYellow, .coderTextBlue, .coderTextGreen, .coderTextGray, .coderTextOrange {
1+
.coderTextRed, .coderTextYellow, .coderTextBlue, .coderTextGreen, .coderTextGray, .coderTextOrange, .topcoderAdmin {
22
font-weight: bold;
33
background-color: transparent;
44
}
5-
.coderTextRed:link, .coderTextYellow:link, .coderTextBlue:link, .coderTextGreen:link, .coderTextGray:link, .coderTextOrange:link, .coderTextWhite:link, .coderTextBlack:link {
5+
.coderTextRed:link, .coderTextYellow:link, .coderTextBlue:link, .coderTextGreen:link, .coderTextGray:link, .coderTextOrange:link, .coderTextWhite:link, .coderTextBlack:link , .topcoderAdmin:link {
66
text-decoration: none;
77
}
8-
.coderTextRed:visited, .coderTextYellow:visited, .coderTextBlue:visited, .coderTextGreen:visited, .coderTextGray:visited, .coderTextOrange:visited, .coderTextWhite:visited, .coderTextBlack:visited {
8+
.coderTextRed:visited, .coderTextYellow:visited, .coderTextBlue:visited, .coderTextGreen:visited, .coderTextGray:visited, .coderTextOrange:visited, .coderTextWhite:visited, .coderTextBlack:visited, .topcoderAdmin:visited {
99
text-decoration: none;
1010
}
11-
a.coderTextRed:hover, a.coderTextYellow:hover, a.coderTextBlue:hover, a.coderTextGreen:hover, a.coderTextGray:hover, a.coderTextOrange:hover, a.coderTextWhite:hover, a.coderTextBlack:hover {
11+
a.coderTextRed:hover, a.coderTextYellow:hover, a.coderTextBlue:hover, a.coderTextGreen:hover, a.coderTextGray:hover, a.coderTextOrange:hover, a.coderTextWhite:hover, a.coderTextBlack:hover, a.topcoderAdmin:hover {
1212
text-decoration: underline;
1313
}
14-
.coderTextRed:active, .coderTextYellow:active, .coderTextBlue:active, .coderTextGreen:active, .coderTextGray:active, .coderTextOrange:active, .coderTextWhite:active, .coderTextBlack:active {
14+
.coderTextRed:active, .coderTextYellow:active, .coderTextBlue:active, .coderTextGreen:active, .coderTextGray:active, .coderTextOrange:active, .coderTextWhite:active, .coderTextBlack:active, a.topcoderAdmin:active {
1515
text-decoration: underline;
1616
}
1717

1818
/* Orange */
19-
.coderTextOrange, .coderTextOrange:link, .coderTextOrange:visited, .coderTextOrange:hover, .coderTextOrange:active { color: #FF9900; }
19+
.coderTextOrange, .coderTextOrange:link, .coderTextOrange:visited, .coderTextOrange:hover, .coderTextOrange:active { color: #ff9900; }
2020
/* Red */
2121
.coderTextRed, .coderTextRed:link, .coderTextRed:visited, .coderTextRed:hover, .coderTextRed:active { color: #EE0000; }
2222
/* Yellow */
@@ -31,20 +31,23 @@ a.coderTextRed:hover, a.coderTextYellow:hover, a.coderTextBlue:hover, a.coderTex
3131
.coderTextWhite, .coderTextWhite:link, .coderTextWhite:visited, .coderTextWhite:hover, .coderTextWhite:active { color: #FFFFFF; }
3232
/* Black */
3333
.coderTextBlack, .coderTextBlack:link, .coderTextBlack:visited, .coderTextBlack:hover, .coderTextBlack:active { color: #000000; }
34-
.coderTextRed, .coderTextYellow, .coderTextBlue, .coderTextGreen, .coderTextGray, .coderTextOrange {
34+
/* Topcoder Admin */
35+
.topcoderAdmin, .topcoderAdmin:link, .topcoderAdmin:visited, .topcoderAdmin:hover, .topcoderAdmin:active { color: #ff5100; }
36+
37+
.coderTextRed, .coderTextYellow, .coderTextBlue, .coderTextGreen, .coderTextGray, .coderTextOrange, .topcoderAdmin {
3538
font-weight: bold !important;
3639
background-color: transparent !important;
3740
}
38-
.coderTextRed:link, .coderTextYellow:link, .coderTextBlue:link, .coderTextGreen:link, .coderTextGray:link, .coderTextOrange:link, .coderTextWhite:link, .coderTextBlack:link {
41+
.coderTextRed:link, .coderTextYellow:link, .coderTextBlue:link, .coderTextGreen:link, .coderTextGray:link, .coderTextOrange:link, .coderTextWhite:link, .coderTextBlack:link, .topcoderAdmin:link {
3942
text-decoration: none !important;
4043
}
41-
.coderTextRed:visited, .coderTextYellow:visited, .coderTextBlue:visited, .coderTextGreen:visited, .coderTextGray:visited, .coderTextOrange:visited, .coderTextWhite:visited, .coderTextBlack:visited {
44+
.coderTextRed:visited, .coderTextYellow:visited, .coderTextBlue:visited, .coderTextGreen:visited, .coderTextGray:visited, .coderTextOrange:visited, .coderTextWhite:visited, .coderTextBlack:visited, .topcoderAdmin:visited {
4245
text-decoration: none !important;
4346
}
44-
.coderTextRed:hover, .coderTextYellow:hover, .coderTextBlue:hover, .coderTextGreen:hover, .coderTextGray:hover, .coderTextOrange:hover, .coderTextWhite:hover, .coderTextBlack:hover {
47+
.coderTextRed:hover, .coderTextYellow:hover, .coderTextBlue:hover, .coderTextGreen:hover, .coderTextGray:hover, .coderTextOrange:hover, .coderTextWhite:hover, .coderTextBlack:hover, .topcoderAdmin:hover {
4548
text-decoration: underline !important;
4649
}
47-
.coderTextRed:active, .coderTextYellow:active, .coderTextBlue:active, .coderTextGreen:active, .coderTextGray:active, .coderTextOrange:active, .coderTextWhite:active, .coderTextBlack:active {
50+
.coderTextRed:active, .coderTextYellow:active, .coderTextBlue:active, .coderTextGreen:active, .coderTextGray:active, .coderTextOrange:active, .coderTextWhite:active, .coderTextBlack:active, .topcoderAdmin:active {
4851
text-decoration: underline !important;
4952
}
5053

@@ -63,4 +66,7 @@ a.coderTextRed:hover, a.coderTextYellow:hover, a.coderTextBlue:hover, a.coderTex
6366
/* White */
6467
.coderTextWhite, .coderTextWhite:link, .coderTextWhite:visited, .coderTextWhite:hover, .coderTextWhite:active { color: #FFFFFF !important; }
6568
/* Black */
66-
.coderTextBlack, .coderTextBlack:link, .coderTextBlack:visited, .coderTextBlack:hover, .coderTextBlack:active { color: #000000 !important; }
69+
.coderTextBlack, .coderTextBlack:link, .coderTextBlack:visited, .coderTextBlack:hover, .coderTextBlack:active { color: #000000 !important; }
70+
71+
/* Topcoder Admin */
72+
.topcoderAdmin, .topcoderAdmin:link, .topcoderAdmin:visited, .topcoderAdmin:hover, .topcoderAdmin:active { color: #ff5100 !important; }

0 commit comments

Comments
 (0)