@@ -33,6 +33,7 @@ class TopcoderPlugin extends Gdn_Plugin {
33
33
const CACHE_KEY_TOPCODER_PROFILE = 'topcoder.{UserID} ' ;
34
34
const CACHE_TOPCODER_KEY_TOPCODER_PROFILE = 'topcoder.{Handle} ' ;
35
35
const CACHE_TOPCODER_KEY_TOPCODER_ROLE_RESOURCES = 'topcoder.roleresources ' ;
36
+ const CACHE_TOPCODER_KEY_TOPCODER_CHALLENGE = 'topcoder.challenge.{ChallengeID} ' ;
36
37
const CACHE_TOPCODER_KEY_TOPCODER_CHALLENGE_RESOURCES = 'topcoder.challenge.{ChallengeID}.resources ' ;
37
38
38
39
const CACHE_DEFAULT_EXPIRY_TIME = 60 *60 *3 ; //The default expiration time in Memcached is in seconds, 10800 = 3 hours
@@ -866,6 +867,7 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
866
867
]);
867
868
868
869
$ groupID = false ;
870
+ $ categoryModel = new CategoryModel ();
869
871
if ($ args ['Controller ' ] instanceof DiscussionController) {
870
872
if (array_key_exists ('discussionid ' , $ methodArgs )) {
871
873
$ discussionID = $ methodArgs ['discussionid ' ];
@@ -887,7 +889,6 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
887
889
$ discussionModel = new DiscussionModel ();
888
890
$ discussion = $ discussionModel ->getID ($ discussionID );
889
891
if ($ discussion ->CategoryID ){
890
- $ categoryModel = new CategoryModel ();
891
892
$ category = $ categoryModel ->getID ($ discussion ->CategoryID );
892
893
$ groupID = $ category ->GroupID ;
893
894
}
@@ -898,16 +899,28 @@ function gdn_dispatcher_beforeControllerMethod_handler($sender, $args){
898
899
$ discussionModel = new DiscussionModel ();
899
900
$ discussion = $ discussionModel ->getID ($ comment ->DiscussionID );
900
901
if ($ discussion ->CategoryID ){
901
- $ categoryModel = new CategoryModel ();
902
902
$ category = $ categoryModel ->getID ($ discussion ->CategoryID );
903
903
$ groupID = $ category ->GroupID ;
904
904
}
905
905
}
906
+ } else if ($ args ['Controller ' ] instanceof CategoriesController) {
907
+ if (array_key_exists ('categoryidentifier ' , $ methodArgs )) {
908
+ $ categoryUrlCode = $ methodArgs ['categoryidentifier ' ];
909
+ if ($ categoryUrlCode ) {
910
+ $ category = $ categoryModel ->getByCode ($ categoryUrlCode );
911
+ $ groupID = val ('GroupID ' , $ category );
912
+ }
913
+ }
906
914
}
907
915
908
916
if ($ groupID && $ groupID > 0 ) {
909
917
$ groupModel = new GroupModel ();
910
918
$ group = $ groupModel ->getByGroupID ($ groupID );
919
+ $ category = $ categoryModel ->getByCode ($ group ->ChallengeID );
920
+ $ categoryID = val ('CategoryID ' , $ category );
921
+ Gdn::controller ()->setData ('Breadcrumbs.Options.GroupCategoryID ' , $ categoryID );
922
+ Gdn::controller ()->setData ('Breadcrumbs.Options.GroupID ' , $ groupID );
923
+ Gdn::controller ()->setData ('Breadcrumbs.Options.ChallengeID ' , $ group ->ChallengeID );
911
924
if ($ group ->ChallengeID ) {
912
925
$ this ->setTopcoderProjectData ($ args ['Controller ' ], $ group ->ChallengeID );
913
926
}
@@ -1446,11 +1459,11 @@ public function getChallengeResources($challengeId) {
1446
1459
}
1447
1460
1448
1461
$ expirationTime = self ::CACHE_DEFAULT_EXPIRY_TIME ;
1449
- $ challenge = self ::loadChallenge ($ challengeId );
1450
- if ($ challenge && count ( $ challenge ) > 0 ) {
1462
+ $ challenge = self ::getChallenge ($ challengeId );
1463
+ if ($ challenge ) {
1451
1464
// Set expiration time for Challenge roles
1452
- $ endDate = strtotime ( $ challenge [0 ]-> endDate ) ;
1453
- $ startDate = strtotime ( $ challenge [0 ]-> startDate ) ;
1465
+ $ endDate = $ challenge [' EndDate ' ] ;
1466
+ $ startDate =$ challenge [' StartDate ' ] ;
1454
1467
// $duration = $endDate > -1 && $startDate > -1 ? $endDate - $startDate: 0;
1455
1468
// archived
1456
1469
$ isEnded = $ endDate > -1 && now () - $ endDate > 0 ;
@@ -1520,6 +1533,44 @@ private static function loadChallengeResources($challengeId) {
1520
1533
return null ;
1521
1534
}
1522
1535
1536
+ /**
1537
+ * Get Topcoder Challenge by ChallengeId
1538
+ * @param $challengeId
1539
+ * @return mixed|null
1540
+ */
1541
+ public function getChallenge ($ challengeId ) {
1542
+ $ challenge = self ::getChallengeFromCache ($ challengeId );
1543
+ if ($ challenge ) {
1544
+ return $ challenge ;
1545
+ }
1546
+
1547
+ $ cachedChallenge = ['ChallengeID ' => $ challengeId ];
1548
+ $ challenge = self ::loadChallenge ($ challengeId );
1549
+
1550
+ $ expirationTime = self ::CACHE_DEFAULT_EXPIRY_TIME ;
1551
+ if ($ challenge ) {
1552
+ // Set expiration time for Challenge roles
1553
+ $ startDate = strtotime ($ challenge ->startDate );
1554
+ $ endDate = strtotime ($ challenge ->endDate );
1555
+ // archived
1556
+ $ isEnded = $ endDate > -1 && now () - $ endDate > 0 ;
1557
+ if (!$ isEnded ) {
1558
+ $ expirationTime = self ::CACHE_ONE_DAY_EXPIRY_TIME ;
1559
+ }
1560
+ $ cachedChallenge ['StartDate ' ] = $ startDate ;
1561
+ $ cachedChallenge ['EndDate ' ] = $ endDate ;
1562
+ $ cachedChallenge ['Track ' ] = $ challenge ->track ;
1563
+ $ termIDs = array_column ($ challenge ->terms , 'id ' );
1564
+ $ NDA_UUID = c ('Plugins.Topcoder.NDA_UUID ' );
1565
+ $ cachedChallenge ['IsNDA ' ] = in_array ($ NDA_UUID , $ termIDs );
1566
+ }
1567
+ if (Gdn_Cache::activeEnabled ()) {
1568
+ self ::topcoderChallengeCache ($ challengeId , $ cachedChallenge , $ expirationTime );
1569
+ }
1570
+ return $ cachedChallenge ;
1571
+ }
1572
+
1573
+
1523
1574
/**
1524
1575
* Load Topcoder Challenge by Challenge ID
1525
1576
* @param $challengeId
@@ -1535,7 +1586,7 @@ private static function loadChallenge($challengeId) {
1535
1586
'header ' => 'Authorization: Bearer ' .$ token
1536
1587
));
1537
1588
$ context = stream_context_create ($ options );
1538
- $ data = file_get_contents ($ topcoderChallengeApiUrl . ' ?challengeId= ' . $ challengeId , false , $ context );
1589
+ $ data = file_get_contents ($ topcoderChallengeApiUrl . $ challengeId , false , $ context );
1539
1590
if ($ data === false ) {
1540
1591
// Handle errors (e.g. 404 and others)
1541
1592
self ::log ('Couldn \'t get challenge: no token ' , ['headers ' => json_encode ($ http_response_header )]);
@@ -1549,6 +1600,35 @@ private static function loadChallenge($challengeId) {
1549
1600
return null ;
1550
1601
}
1551
1602
1603
+ /**
1604
+ * Load challenge from cache
1605
+ * @param $challengeID
1606
+ * @return false|mixed
1607
+ */
1608
+ private static function getChallengeFromCache ($ challengeID ) {
1609
+ if (!Gdn_Cache::activeEnabled ()) {
1610
+ return false ;
1611
+ }
1612
+
1613
+ $ handleKey = formatString (self ::CACHE_TOPCODER_KEY_TOPCODER_CHALLENGE , ['ChallengeID ' => $ challengeID ]);
1614
+ if (!Gdn::cache ()->exists ($ handleKey )) {
1615
+ return false ;
1616
+ }
1617
+ $ challenge = Gdn::cache ()->get ($ handleKey );
1618
+ if ($ challenge === Gdn_Cache::CACHEOP_FAILURE ) {
1619
+ return false ;
1620
+ }
1621
+ return $ challenge ;
1622
+ }
1623
+
1624
+ private static function topcoderChallengeCache ($ challengeID , $ challenge , $ expirationTime = self ::CACHE_DEFAULT_EXPIRY_TIME ) {
1625
+ $ challengeKey = formatString (self ::CACHE_TOPCODER_KEY_TOPCODER_CHALLENGE , ['ChallengeID ' => $ challengeID ]);
1626
+ return Gdn::cache ()->store ($ challengeKey , $ challenge , [
1627
+ Gdn_Cache::FEATURE_EXPIRY => $ expirationTime
1628
+ ]);
1629
+ }
1630
+
1631
+
1552
1632
/**
1553
1633
* Get a Topcoder Roles
1554
1634
*
@@ -1761,13 +1841,15 @@ public static function getUserPhotoUrl($user) {
1761
1841
// Set Topcoder Project Roles Data for a challenge
1762
1842
private function setTopcoderProjectData ($ sender , $ challengeID ) {
1763
1843
if ($ challengeID ) {
1844
+ $ challenge = $ this ->getChallenge ($ challengeID );
1764
1845
$ resources = $ this ->getChallengeResources ($ challengeID );
1765
1846
$ roleResources = $ this ->getRoleResources ();
1766
1847
$ currentProjectRoles = $ this ->getTopcoderProjectRoles (Gdn::session ()->User , $ resources , $ roleResources );
1767
1848
if ($ currentProjectRoles ) {
1768
1849
$ currentProjectRoles = array_map ('strtolower ' ,$ currentProjectRoles );
1769
1850
}
1770
1851
1852
+ $ sender ->Data ['Challenge ' ] = $ challenge ;
1771
1853
$ sender ->Data ['ChallengeResources ' ] = $ resources ;
1772
1854
$ sender ->Data ['ChallengeRoleResources ' ] = $ roleResources ;
1773
1855
$ sender ->Data ['ChallengeCurrentUserProjectRoles ' ] = $ currentProjectRoles ;
@@ -1777,7 +1859,7 @@ private function setTopcoderProjectData($sender, $challengeID) {
1777
1859
// }
1778
1860
self ::log ('setTopcoderProjectData ' , ['ChallengeID ' => $ challengeID , 'currentUser ' => $ currentProjectRoles ,
1779
1861
'Topcoder Resources ' => $ resources , 'Topcoder RoleResources '
1780
- => $ roleResources ,]);
1862
+ => $ roleResources , ' challenge ' => $ challenge ]);
1781
1863
}
1782
1864
}
1783
1865
@@ -1984,6 +2066,62 @@ public static function log($message, $data = []) {
1984
2066
);
1985
2067
}
1986
2068
}
2069
+
2070
+ // MAGIC EVENTS TO OVERRIDE VANILLA CONTROLLER METHODS
2071
+
2072
+ /**
2073
+ * Allows user to announce or unannounce a discussion.
2074
+ * FIX: https://github.com/topcoder-platform/forums/issues/456
2075
+ * @param int $discussionID Unique discussion ID.
2076
+ * @param string $TransientKey Single-use hash to prove intent.
2077
+ */
2078
+ public function discussionController_announce_create ($ sender , $ discussionID = '' , $ announce =true ,$ target = '' ) {
2079
+ // Make sure we are posting back.
2080
+ if (!$ sender ->Request ->isAuthenticatedPostBack ()) {
2081
+ throw permissionException ('Javascript ' );
2082
+ }
2083
+
2084
+ $ discussion = $ sender ->DiscussionModel ->getID ($ discussionID );
2085
+ if (!$ discussion ) {
2086
+ throw notFoundException ('Discussion ' );
2087
+ }
2088
+
2089
+ //$sender->categoryPermission($discussion->CategoryID, 'Vanilla.Discussions.Announce');// protected
2090
+ if (!CategoryModel::checkPermission ($ discussion ->CategoryID , 'Vanilla.Discussions.Announce ' )) {
2091
+ $ sender ->permission ('Vanilla.Discussions.Announce ' , true , 'Category ' , $ discussion ->CategoryID );
2092
+ }
2093
+
2094
+ // Save the property.
2095
+ // 0 - Don't Announce Discussion
2096
+ // 2 - Announce Discussion in the current category
2097
+ $ newAnnounceValue = (bool )$ announce ? 2 : 0 ;
2098
+ $ sender ->DiscussionModel ->setField ($ discussionID , 'Announce ' , $ newAnnounceValue );
2099
+ $ discussion ->Announce = $ newAnnounceValue ;
2100
+
2101
+ // Redirect to the front page
2102
+ if ($ sender ->_DeliveryType === DELIVERY_TYPE_ALL ) {
2103
+ $ target = getIncomingValue ('Target ' , 'discussions ' );
2104
+ redirectTo ($ target );
2105
+ }
2106
+
2107
+ $ sender ->sendOptions ($ discussion );
2108
+ if ($ newAnnounceValue == 2 ) {
2109
+ require_once $ sender ->fetchViewLocation ('helper_functions ' , 'Discussions ' , 'vanilla ' );
2110
+ $ dataHtml = tag ($ discussion , 'Announce ' , 'Announcement ' );
2111
+ // Remove if exists
2112
+ $ sender ->jsonTarget (".Section-DiscussionList #Discussion_ $ discussionID .Meta-Discussion " , $ dataHtml , 'Prepend ' );
2113
+ $ sender ->jsonTarget (".Section-DiscussionList #Discussion_ $ discussionID " , 'Announcement ' , 'AddClass ' );
2114
+ } else {
2115
+ $ sender ->jsonTarget (".Section-DiscussionList #Discussion_ $ discussionID .Tag-Announcement " , null , 'Remove ' );
2116
+ $ sender ->jsonTarget (".Section-DiscussionList #Discussion_ $ discussionID " , 'Announcement ' , 'RemoveClass ' );
2117
+
2118
+ }
2119
+
2120
+ $ sender ->jsonTarget ("#Discussion_ $ discussionID " , null , 'Highlight ' );
2121
+ $ sender ->jsonTarget (".Discussion #Item_0 " , null , 'Highlight ' );
2122
+
2123
+ $ sender ->render ('Blank ' , 'Utility ' , 'Dashboard ' );
2124
+ }
1987
2125
}
1988
2126
1989
2127
if (!function_exists ('topcoderRatingCssClass ' )) {
@@ -2483,3 +2621,50 @@ function topcoderMentionAnchor($mention, $cssClass = null, $options = null) {
2483
2621
}
2484
2622
}
2485
2623
2624
+ if (!function_exists ('watchingSorts ' )) {
2625
+ /**
2626
+ * Returns watching sorting.
2627
+ *
2628
+ * @param string $extraClasses any extra classes you add to the drop down
2629
+ * @return string
2630
+ */
2631
+ function watchingSorts ($ extraClasses = '' ) {
2632
+ if (!Gdn::session ()->isValid ()) {
2633
+ return ;
2634
+ }
2635
+
2636
+ $ baseUrl = preg_replace ('/\?.*/ ' , '' , Gdn::request ()->getFullPath ());
2637
+ $ transientKey = Gdn::session ()->transientKey ();
2638
+ $ filters = [
2639
+ [
2640
+ 'name ' => t ('New ' ),
2641
+ 'param ' => 'sort ' ,
2642
+ 'value ' => 'new ' ,
2643
+ 'extra ' => ['TransientKey ' => $ transientKey , 'save ' => 1 ]
2644
+ ],
2645
+
2646
+ [
2647
+ 'name ' => t ('Old ' ),
2648
+ 'param ' => 'sort ' ,
2649
+ 'value ' => 'old ' ,
2650
+ 'extra ' => ['TransientKey ' => $ transientKey , 'save ' => 1 ]
2651
+ ]
2652
+ ];
2653
+
2654
+ $ defaultParams = [];
2655
+ if (!empty ($ defaultParams )) {
2656
+ $ defaultUrl = $ baseUrl .'? ' .http_build_query ($ defaultParams );
2657
+ } else {
2658
+ $ defaultUrl = $ baseUrl ;
2659
+ }
2660
+
2661
+ return sortsDropDown ('WatchingSort ' ,
2662
+ $ baseUrl ,
2663
+ $ filters ,
2664
+ $ extraClasses ,
2665
+ null ,
2666
+ $ defaultUrl ,
2667
+ 'Sort '
2668
+ );
2669
+ }
2670
+ }
0 commit comments