Overview

Packages

  • None
  • Yaga

Classes

  • ActedModel
  • ActionController
  • ActionModel
  • AwardCombo
  • BadgeAwardModel
  • BadgeController
  • BadgeModel
  • BadgesController
  • BadgesModule
  • BestController
  • BestFilterModule
  • CakeDayPost
  • CommentCount
  • CommentMarathon
  • DiscussionBodyLength
  • DiscussionCategory
  • DiscussionCount
  • DiscussionPageCount
  • HasMentioned
  • HolidayVisit
  • LeaderBoardModule
  • LengthOfService
  • ManualAward
  • NecroPost
  • NewbieComment
  • PhotoExists
  • PostCount
  • PostReactions
  • QnAAnserCount
  • RankController
  • RankModel
  • ReactController
  • ReactionCount
  • ReactionModel
  • ReflexComment
  • RulesController
  • SocialConnection
  • Yaga
  • YagaController
  • YagaHooks

Interfaces

  • YagaRule
  • Overview
  • Package
  • Class
  • Tree
  • Todo
  • Download
  1: <?php if(!defined('APPLICATION')) exit();
  2: /* Copyright 2013-2014 Zachary Doll */
  3: 
  4: /**
  5:  * A collection of hooks that are enabled when Yaga is.
  6:  * 
  7:  * @package Yaga
  8:  * @since 1.0
  9:  */
 10: class YagaHooks implements Gdn_IPlugin {
 11: 
 12:   /**
 13:    * Redirect any old links to proper settings page permanently
 14:    * @param SettingsController $Sender
 15:    */
 16:   public function SettingsController_Yaga_Create($Sender) {
 17:     Redirect('yaga/settings', 301);
 18:   }
 19: 
 20:   /**
 21:    * Add Simple stats page to dashboard index
 22:    * @param SettingsController $Sender
 23:    */
 24:   public function SettingsController_AfterRenderAsset_Handler($Sender) {
 25:     $EventArguments = $Sender->EventArguments;
 26:     if($EventArguments['AssetName'] == 'Content' && $Sender->OriginalRequestMethod == 'index') {
 27:       //echo 'Sweet sweet stats!';
 28:       $BadgeAwardModel = Yaga::BadgeAwardModel();
 29:       $ReactionModel = Yaga::ReactionModel();
 30: 
 31:       $BadgeCount = $BadgeAwardModel->GetCount();
 32:       $ReactionCount = $ReactionModel->GetCount();
 33:       echo Wrap('Yaga Statistics', 'h1');
 34:       echo Wrap(
 35:               Wrap(
 36:                       Wrap(
 37:                               'Badges' . Wrap($BadgeCount, 'strong'),
 38:                               'div'), 'li', array('class' => 'BadgeCount')) .
 39:               Wrap(
 40:                       Wrap(
 41:                               'Reactions' . Wrap($ReactionCount, 'strong'),
 42:                               'div'), 'li', array('class' => 'ReactionCount')),
 43:             'ul',
 44:             array('class' => 'StatsOverview'));
 45:     }
 46:   }
 47: 
 48:   /**
 49:    * Add the settings page links
 50:    *
 51:    * @param Object $Sender
 52:    */
 53:   public function Base_GetAppSettingsMenuItems_Handler($Sender) {
 54:     $Menu = $Sender->EventArguments['SideMenu'];
 55:     $Section = 'Gamification';
 56:     $Attrs = array('class' => $Section);
 57:     $Menu->AddItem($Section, $Section, FALSE, $Attrs);
 58:     $Menu->AddLink($Section, T('Settings'), 'yaga/settings', 'Garden.Settings.Manage');
 59:     if(C('Yaga.Reactions.Enabled')) {
 60:       $Menu->AddLink($Section, T('Yaga.Reactions'), 'action/settings', 'Yaga.Reactions.Manage');
 61:     }
 62:     if(C('Yaga.Badges.Enabled')) {
 63:       $Menu->AddLink($Section, T('Yaga.Badges'), 'badge/settings', 'Yaga.Badges.Manage');
 64:     }
 65:     if(C('Yaga.Ranks.Enabled')) {
 66:       $Menu->AddLink($Section, T('Yaga.Ranks'), 'rank/settings', 'Yaga.Ranks.Manage');
 67:     }
 68:   }
 69: 
 70:   /**
 71:    * Add a Best Content item to the discussion filters module
 72:    * 
 73:    * @param mixed $Sender
 74:    * @return boolean
 75:    */
 76:   public function Base_AfterDiscussionFilters_Handler($Sender) {
 77:     if(!C('Yaga.Reactions.Enabled')) {
 78:       return FALSE;
 79:     }
 80: 
 81:     echo Wrap(Anchor(Sprite('SpBestOf') . ' ' . T('Yaga.BestContent'), '/best'), 'li', array('class' => $Sender->ControllerName == 'bestcontroller' ? 'Best Active' : 'Best'));
 82:   }
 83: 
 84:   /**
 85:    * Display the reaction counts on the profile page
 86:    * @param ProfileController $Sender
 87:    */
 88:   public function ProfileController_AfterUserInfo_Handler($Sender) {
 89:     if(!C('Yaga.Reactions.Enabled')) {
 90:       return;
 91:     }
 92:     $User = $Sender->User;
 93:     $Method = $Sender->RequestMethod;
 94:     if($Method == 'reactions') {
 95:       $ActionID = $Sender->RequestArgs[2];
 96:     }
 97:     else {
 98:       $ActionID = -1;
 99:     }
100:     echo '<div class="Yaga ReactionsWrap">';
101:     echo Wrap(T('Yaga.Reactions', 'Reactions'), 'h2', array('class' => 'H'));
102: 
103:     // insert the reaction totals in the profile
104:     $ReactionModel = Yaga::ReactionModel();
105:     $Actions = Yaga::ActionModel()->Get();
106:     $String = '';
107:     foreach($Actions as $Action) {
108:       $Selected = ($ActionID == $Action->ActionID) ? ' Selected' : '';
109:       $Count = $ReactionModel->GetUserCount($User->UserID, $Action->ActionID);
110:       $TempString = Wrap(Wrap(Gdn_Format::BigNumber($Count), 'span', array('title' => $Count)), 'span', array('class' => 'Yaga_ReactionCount CountTotal'));
111:       $TempString .= Wrap($Action->Name, 'span', array('class' => 'Yaga_ReactionName CountLabel'));
112: 
113:       $String .= Wrap(Wrap(Anchor($TempString, '/profile/reactions/' . $User->UserID . '/' . Gdn_Format::Url($User->Name) . '/' . $Action->ActionID, array('class' => 'Yaga_Reaction TextColor', 'title' => $Action->Description)), 'span', array('class' => 'CountItem' . $Selected)), 'span', array('class' => 'CountItemWrap'));
114:     }
115: 
116:     echo Wrap($String, 'div', array('class' => 'DataCounts'));
117:     echo '</div>';
118:   }
119: 
120:   /**
121:    * Add the badge count into the user info module
122:    *
123:    * @param UserInfoModule $Sender
124:    */
125:   public function UserInfoModule_OnBasicInfo_Handler($Sender) {
126:     if(!C('Yaga.Badges.Enabled')) {
127:       return;
128:     }
129:     echo '<dt class="Badges">' . T('Yaga.Badges', 'Badges') . '</dt> ';
130:     echo '<dd class="Badges">' . $Sender->User->CountBadges . '</dd>';
131:   }
132: 
133:   /**
134:    * This method shows the latest discussions/comments a user has posted that
135:    * received the specified action
136:    *
137:    * @param ProfileController $Sender
138:    * @param int $UserReference
139:    * @param string $Username
140:    * @param int $ActionID
141:    * @param int $Page
142:    */
143:   public function ProfileController_Reactions_Create($Sender, $UserReference = '', $Username = '', $ActionID = '', $Page = 0) {
144:     if(!C('Yaga.Reactions.Enabled')) {
145:       return;
146:     }
147: 
148:     list($Offset, $Limit) = OffsetLimit($Page, C('Yaga.ReactedContent.PerPage', 5));
149:     if(!is_numeric($Offset) || $Offset < 0) {
150:       $Offset = 0;
151:     }
152: 
153:     $Sender->EditMode(FALSE);
154: 
155:     // Tell the ProfileController what tab to load
156:     $Sender->GetUserInfo($UserReference, $Username);
157:     $Sender->_SetBreadcrumbs(T('Yaga.Reactions'), UserUrl($Sender->User, '', 'reactions'));
158:     $Sender->SetTabView(T('Yaga.Reactions'), 'reactions', 'profile', 'Yaga');
159: 
160:     $Sender->AddJsFile('jquery.expander.js');
161:     $Sender->AddJsFile('reactions.js', 'yaga');
162:     $Sender->AddDefinition('ExpandText', T('(more)'));
163:     $Sender->AddDefinition('CollapseText', T('(less)'));
164: 
165:     $Model = new ActedModel();
166:     $Data = $Model->Get($Sender->User->UserID, $ActionID, $Limit, $Offset);
167: 
168:     $Sender->SetData('Content', $Data);
169: 
170:     // Set the HandlerType back to normal on the profilecontroller so that it fetches it's own views
171:     $Sender->HandlerType = HANDLER_TYPE_NORMAL;
172: 
173:     // Do not show discussion options
174:     $Sender->ShowOptions = FALSE;
175: 
176:     if($Sender->Head) {
177:       $Sender->Head->AddTag('meta', array('name' => 'robots', 'content' => 'noindex,noarchive'));
178:     }
179: 
180:     $ReactionModel = Yaga::ReactionModel();
181: 
182:     // Build a pager
183:     $PagerFactory = new Gdn_PagerFactory();
184:     $Sender->Pager = $PagerFactory->GetPager('Pager', $Sender);
185:     $Sender->Pager->ClientID = 'Pager';
186:     $Sender->Pager->Configure(
187:             $Offset, $Limit, $ReactionModel->GetUserCount($Sender->User->UserID, $ActionID), 'profile/reactions/' . $Sender->User->UserID . '/' . Gdn_Format::Url($Sender->User->Name) . '/' . $ActionID . '/%1$s/'
188:     );
189: 
190:     // Render the ProfileController
191:     $Sender->Render();
192:   }
193: 
194:   /**
195:    * This method shows the highest scoring discussions/comments a user has ever posted
196:    *
197:    * @param ProfileController $Sender
198:    * @param int $UserReference
199:    * @param string $Username
200:    * @param int $Page
201:    */
202:   public function ProfileController_Best_Create($Sender, $UserReference = '', $Username = '', $Page = 0) {
203:     if(!C('Yaga.Reactions.Enabled')) {
204:       return;
205:     }
206: 
207:     list($Offset, $Limit) = OffsetLimit($Page, C('Yaga.BestContent.PerPage', 10));
208:     if(!is_numeric($Offset) || $Offset < 0) {
209:       $Offset = 0;
210:     }
211: 
212:     $Sender->EditMode(FALSE);
213: 
214:     // Tell the ProfileController what tab to load
215:     $Sender->GetUserInfo($UserReference, $Username);
216:     $Sender->_SetBreadcrumbs(T('Yaga.BestContent'), UserUrl($Sender->User, '', 'best'));
217:     $Sender->SetTabView(T('Yaga.BestContent'), 'best', 'profile', 'Yaga');
218: 
219:     $Sender->AddJsFile('jquery.expander.js');
220:     $Sender->AddJsFile('reactions.js', 'yaga');
221:     $Sender->AddDefinition('ExpandText', T('(more)'));
222:     $Sender->AddDefinition('CollapseText', T('(less)'));
223: 
224:     $Model = new ActedModel();
225:     $Data = $Model->GetBest($Sender->User->UserID, $Limit, $Offset);
226: 
227:     $Sender->SetData('Content', $Data);
228: 
229:     // Set the HandlerType back to normal on the profilecontroller so that it fetches it's own views
230:     $Sender->HandlerType = HANDLER_TYPE_NORMAL;
231: 
232:     // Do not show discussion options
233:     $Sender->ShowOptions = FALSE;
234: 
235:     if($Sender->Head) {
236:       $Sender->Head->AddTag('meta', array('name' => 'robots', 'content' => 'noindex,noarchive'));
237:     }
238: 
239:     // Build a pager
240:     $PagerFactory = new Gdn_PagerFactory();
241:     $Sender->Pager = $PagerFactory->GetPager('Pager', $Sender);
242:     $Sender->Pager->ClientID = 'Pager';
243:     $Sender->Pager->Configure(
244:             $Offset, $Limit, FALSE, 'profile/best/' . $Sender->User->UserID . '/' . Gdn_Format::Url($Sender->User->Name) . '/%1$s/'
245:     );
246: 
247:     // Render the ProfileController
248:     $Sender->Render();
249:   }
250: 
251:   /**
252:    * Add a best content tab on a user's profile
253:    * @param ProfileController $Sender
254:    */
255:   public function ProfileController_AddProfileTabs_Handler($Sender) {
256:     if(is_object($Sender->User) && $Sender->User->UserID > 0) {
257:       $Sender->AddProfileTab(Sprite('SpBestOf') . ' ' . T('Yaga.BestContent'), 'profile/best/' . $Sender->User->UserID . '/' . urlencode($Sender->User->Name));
258:     }
259:   }
260: 
261:   /**
262:    * Check for rank progress when the user model gets updated
263:    *
264:    * @param UserModel $Sender
265:    */
266:   public function UserModel_AfterSetField_Handler($Sender) {
267:     // Don't check for promotions if we aren't using ranks
268:     if(!C('Yaga.Ranks.Enabled')) {
269:       return;
270:     }
271:     
272:     $Fields = $Sender->EventArguments['Fields'];
273:     $FieldHooks = array('Points', 'CountDiscussions', 'CountComments');
274:     
275:     foreach($FieldHooks as $FieldHook) {
276:       if(array_key_exists($FieldHook, $Fields)) {
277:         $UserID = $Sender->EventArguments['UserID'];
278:         $this->_RankProgression($UserID);
279:         break; // Only need to fire once per event
280:       }
281:     }
282:   }
283:   
284:   /**
285:    * Update a user's rank id if they qualify
286:    * 
287:    * @param int $UserID
288:    */
289:   protected function _RankProgression($UserID) {
290:     $UserModel = Gdn::UserModel();
291:     $User = $UserModel->GetID($UserID);
292: 
293:     // Don't try to promote if they are frozen
294:     if(!$User->RankProgression) {
295:       return;
296:     }
297: 
298:     $RankModel = Yaga::RankModel();
299:     $Rank = $RankModel->GetHighestQualifyingRank($User);
300: 
301:     if($Rank && $Rank->RankID != $User->RankID) {
302:       // Only promote automatically
303:       $OldRank = $RankModel->GetByID($User->RankID);
304:       if($OldRank->Sort <= $Rank->Sort) {
305:         $RankModel->Set($Rank->RankID, $UserID, TRUE);
306:       }
307:     }
308:   }
309: 
310:   /**
311:    * Add the badge and rank notification options
312:    *
313:    * @param ProfileController $Sender
314:    */
315:   public function ProfileController_AfterPreferencesDefined_Handler($Sender) {
316:     if(C('Yaga.Badges.Enabled')) {
317:       $Sender->Preferences['Notifications']['Email.BadgeAward'] = T('Yaga.Notifications.Badges');
318:       $Sender->Preferences['Notifications']['Popup.BadgeAward'] = T('Yaga.Notifications.Badges');
319:     }
320: 
321:     if(C('Yaga.Ranks.Enabled')) {
322:       $Sender->Preferences['Notifications']['Email.RankPromotion'] = T('Yaga.Notifications.Ranks');
323:       $Sender->Preferences['Notifications']['Popup.RankPromotion'] = T('Yaga.Notifications.Ranks');
324:     }
325:   }
326: 
327:   /**
328:    * Add the Award Badge and Promote options to the profile controller
329:    *
330:    * @param ProfileController $Sender
331:    */
332:   public function ProfileController_BeforeProfileOptions_Handler($Sender) {
333:     if(Gdn::Session()->IsValid()) {
334:       if(C('Yaga.Badges.Enabled') && CheckPermission('Yaga.Badges.Add')) {
335:         $Sender->EventArguments['ProfileOptions'][] = array(
336:             'Text' => Sprite('SpRibbon') . ' ' . T('Yaga.Badge.Award'),
337:             'Url' => '/badge/award/' . $Sender->User->UserID,
338:             'CssClass' => 'Popup'
339:         );
340:       }
341: 
342:       if(C('Yaga.Ranks.Enabled') && CheckPermission('Yaga.Ranks.Add')) {
343:         $Sender->EventArguments['ProfileOptions'][] = array(
344:             'Text' => Sprite('SpModeratorActivities') . ' ' . T('Yaga.Rank.Promote'),
345:             'Url' => '/rank/promote/' . $Sender->User->UserID,
346:             'CssClass' => 'Popup'
347:         );
348:       }
349:     }
350:   }
351: 
352:   /**
353:    * Display a record of reactions after the first post
354:    *
355:    * @param DiscussionController $Sender
356:    */
357:   public function DiscussionController_AfterDiscussionBody_Handler($Sender) {
358:     if(!Gdn::Session()->CheckPermission('Yaga.Reactions.View') || !C('Yaga.Reactions.Enabled')) {
359:       return;
360:     }
361:     $Type = 'discussion';
362:     $ID = $Sender->DiscussionID;
363:     RenderReactionRecord($ID, $Type);
364:   }
365: 
366:   /**
367:    * Display a record of reactions after comments
368:    * @param DiscussionController $Sender
369:    */
370:   public function DiscussionController_AfterCommentBody_Handler($Sender) {
371:     if(!Gdn::Session()->CheckPermission('Yaga.Reactions.View') || !C('Yaga.Reactions.Enabled')) {
372:       return;
373:     }
374:     $Type = 'comment';
375:     $ID = $Sender->EventArguments['Comment']->CommentID;
376:     RenderReactionRecord($ID, $Type);
377:   }
378: 
379:   /**
380:    * Add action list to discussion items
381:    * @param DiscussionController $Sender
382:    */
383:   public function DiscussionController_AfterReactions_Handler($Sender) {
384:     if(C('Yaga.Reactions.Enabled') == FALSE) {
385:       return;
386:     }
387: 
388:     // check to see if allowed to add reactions
389:     if(!Gdn::Session()->CheckPermission('Yaga.Reactions.Add')) {
390:       return;
391:     }
392: 
393:     // Users shouldn't be able to react to their own content
394:     $Type = $Sender->EventArguments['RecordType'];
395:     $ID = $Sender->EventArguments['RecordID'];
396: 
397:     if(array_key_exists('Author', $Sender->EventArguments)) {
398:       $Author = $Sender->EventArguments['Author'];
399:       $AuthorID = $Author->UserID;
400:     }
401:     else {
402:       $Discussion = $Sender->EventArguments['Discussion'];
403:       $AuthorID = $Discussion->InsertUserID;
404:     }
405: 
406:     // Users shouldn't be able to react to their own content
407:     if(Gdn::Session()->UserID != $AuthorID) {
408:       RenderReactionList($ID, $Type);
409:     }
410:   }
411: 
412:   /**
413:    * Add the action list to any activity items that can be commented on
414:    *
415:    * @param ActivityController $Sender
416:    */
417:   public function ActivityController_AfterActivityBody_Handler($Sender) {
418:     if(!C('Yaga.Reactions.Enabled')) {
419:       return;
420:     }
421:     $Activity = $Sender->EventArguments['Activity'];
422:     $CurrentUserID = Gdn::Session()->UserID;
423:     $Type = 'activity';
424:     $ID = $Activity->ActivityID;
425: 
426:     // Only allow reactions on activities that allow comments
427:     if($Activity->AllowComments == 0) {
428:       return;
429:     }
430: 
431:     // check to see if allowed to add reactions
432:     if(!Gdn::Session()->CheckPermission('Yaga.Reactions.Add')) {
433:       return;
434:     }
435: 
436:     // Activities can be by multiple users
437:     if(is_array($Activity->ActivityUserID) && in_array($CurrentUserID, $Activity->ActivityUserID)) {
438:       // User is part of a multiple user activity
439:     }
440:     else if($CurrentUserID == $Activity->ActivityUserID) {
441:       // User is the author of this activity
442:     }
443:     else {
444:       echo Wrap(RenderReactionList($ID, $Type, FALSE), 'div', array('class' => 'Reactions'));
445:     }
446:   }
447: 
448:   /**
449:    * Apply any applicable rank perks when the session first starts.
450:    * @param UserModel $Sender
451:    */
452:   public function UserModel_AfterGetSession_Handler($Sender) {
453:     if(!C('Yaga.Ranks.Enabled')) {
454:       return;
455:     }
456: 
457:     $User = &$Sender->EventArguments['User'];
458:     $RankID = $User->RankID;
459:     if(is_null($RankID)) {
460:       return;
461:     }
462: 
463:     $RankModel = Yaga::RankModel();
464:     $Perks = $RankModel->GetPerks($RankID);
465:     
466:     // Apply all the perks
467:     foreach($Perks as $Perk => $PerkValue) {
468:       $PerkType = substr($Perk, 0, 4);
469:       $PerkKey = substr($Perk, 4);
470:       
471:       if($PerkType === 'Conf') {
472:         $this->_ApplyCustomConfigs($PerkKey, $PerkValue);
473:       }
474:       else if($PerkType === 'Perm' && $PerkValue === 'grant') {
475:         $this->_GrantPermission($User, $PerkKey);
476:       }
477:       else if($PerkType === 'Perm' && $PerkValue === 'revoke') {
478:         $this->_RevokePermission($User, $PerkKey);
479:       }
480:       else {
481:         // Do nothing
482:         // TODO: look into firing a custom event
483:       }
484:     }
485:   }
486: 
487:   /**
488:    * Gives the specified permission to a user, regardless of current role.
489:    * @param type $User
490:    * @param string $Permission
491:    */
492:   private function _GrantPermission($User, $Permission = '') {
493:     if($Permission === '') {
494:       return;
495:     }
496: 
497:     $TempPerms = unserialize($User->Permissions);
498:     if(!in_array($Permission, $TempPerms)) {
499:       $TempPerms[] = $Permission;
500:       $User->Permissions = serialize($TempPerms);
501:     }
502:   }
503: 
504:   /**
505:    * Removes the specified permission from a user, regardless of current role.
506:    *
507:    * Cannot be used to override $User->Admin = 1 permissions
508:    *
509:    * @param type $User
510:    * @param string $Permission
511:    */
512:   private function _RevokePermission($User, $Permission = '') {
513:     if($Permission === '') {
514:       return;
515:     }
516: 
517:     $TempPerms = unserialize($User->Permissions);
518:     $Key = array_search($Permission, $TempPerms);
519:     if($Key) {
520:       unset($TempPerms[$Key]);
521:       $User->Permissions = serialize($TempPerms);
522:     }
523:   }
524: 
525:   /**
526:    * Apply custom configuration from rank perks in memory only.
527:    * @param string $Name
528:    * @param mixed $Value
529:    */
530:   private function _ApplyCustomConfigs($Name = NULL, $Value = NULL) {
531:     SaveToConfig($Name, $Value, array('Save' => FALSE));
532:   }
533: 
534:   /**
535:    * Insert JS and CSS files into the appropiate controllers
536:    * 
537:    * @param ProfileController $Sender
538:    */
539:   public function ProfileController_Render_Before($Sender) {
540:     $this->_AddResources($Sender);
541: 
542:     if(C('Yaga.Badges.Enabled')) {
543:       $Sender->AddModule('BadgesModule');
544:     }
545:   }
546: 
547:   /**
548:    * Insert JS and CSS files into the appropiate controllers
549:    * 
550:    * @param DiscussionController $Sender
551:    */
552:   public function DiscussionController_Render_Before($Sender) {
553:     $this->_AddResources($Sender);
554:   }
555: 
556:   /**
557:    * Insert JS and CSS files into the appropiate controllers
558:    * 
559:    * @param CommentController $Sender
560:    */
561:   public function CommentController_Render_Before($Sender) {
562:     $this->_AddResources($Sender);
563:   }
564: 
565:   /**
566:    * Insert JS and CSS files into the appropiate controllers
567:    * 
568:    * @param ActivityController $Sender
569:    */
570:   public function ActivityController_Render_Before($Sender) {
571:     $this->_AddResources($Sender);
572: 
573:     if(C('Yaga.LeaderBoard.Enabled', FALSE)) {
574:       // add leaderboard modules to the activity page
575:       $Module = new LeaderBoardModule();
576:       $Module->GetData('w');
577:       $Sender->AddModule($Module);
578:       $Module = new LeaderBoardModule();
579:       $Sender->AddModule($Module);
580:     }
581:   }
582: 
583:   /**
584:    * Check for Badge Awards
585:    * 
586:    * @param Gdn_Dispatcher $Sender
587:    */
588:   public function Gdn_Dispatcher_AppStartup_Handler($Sender) {
589:     $this->_AwardBadges($Sender, __FUNCTION__);
590:   }
591: 
592:   /**
593:    * Check for Badge Awards
594:    * 
595:    * @param mixed $Sender
596:    */
597:   public function Base_AfterGetSession_Handler($Sender) {
598:     $this->_AwardBadges($Sender, __FUNCTION__);
599:   }
600: 
601:   /**
602:    * Check for Badge Awards
603:    * 
604:    * @param CommentModel $Sender
605:    */
606:   public function CommentModel_AfterSaveComment_Handler($Sender) {
607:     $this->_AwardBadges($Sender, __FUNCTION__);
608:   }
609: 
610:   /**
611:    * Check for Badge Awards
612:    * 
613:    * @param DiscussionModel $Sender
614:    */
615:   public function DiscussionModel_AfterSaveDiscussion_Handler($Sender) {
616:     $this->_AwardBadges($Sender, __FUNCTION__);
617:   }
618: 
619:   /**
620:    * Check for Badge Awards
621:    * 
622:    * @param ActivityModel $Sender
623:    */
624:   public function ActivityModel_BeforeSaveComment_Handler($Sender) {
625:     $this->_AwardBadges($Sender, __FUNCTION__);
626:   }
627: 
628:   /**
629:    * Check for Badge Awards
630:    * 
631:    * @param CommentModel $Sender
632:    */
633:   public function CommentModel_BeforeNotification_Handler($Sender) {
634:     $this->_AwardBadges($Sender, __FUNCTION__);
635:   }
636: 
637:   /**
638:    * Check for Badge Awards
639:    * 
640:    * @param DiscussionModel $Sender
641:    */
642:   public function DiscussionModel_BeforeNotification_Handler($Sender) {
643:     $this->_AwardBadges($Sender, __FUNCTION__);
644:   }
645: 
646:   /**
647:    * Check for Badge Awards
648:    * 
649:    * @param mixed $Sender
650:    */
651:   public function Base_AfterSignIn_Handler($Sender) {
652:     $this->_AwardBadges($Sender, __FUNCTION__);
653:   }
654: 
655:   /**
656:    * Check for Badge Awards
657:    * 
658:    * @param UserModel $Sender
659:    */
660:   public function UserModel_AfterSave_Handler($Sender) {
661:     $this->_AwardBadges($Sender, __FUNCTION__);
662:   }
663: 
664:   /**
665:    * Check for Badge Awards
666:    * 
667:    * @param ReactionModel $Sender
668:    */
669:   public function ReactionModel_AfterReactionSave_Handler($Sender) {
670:     $this->_AwardBadges($Sender, __FUNCTION__);
671:   }
672: 
673:   /**
674:    * Check for Badge Awards
675:    * 
676:    * @param BadgeAwardModel $Sender
677:    */
678:   public function BadgeAwardModel_AfterBadgeAward_Handler($Sender) {
679:     $this->_AwardBadges($Sender, __FUNCTION__);
680:   }
681: 
682:   /**
683:    * Check for Badge Awards
684:    * 
685:    * @param mixed $Sender
686:    */
687:   public function Base_AfterConnection_Handler($Sender) {
688:     $this->_AwardBadges($Sender, __FUNCTION__);
689:   }
690: 
691:   /**
692:    * This is the dispatcher to check badge awards
693:    *
694:    * @param mixed $Sender The sending object
695:    * @param string $Handler The event handler to check associated rules for awards
696:    * (e.g. BadgeAwardModel_AfterBadgeAward_Handler or Base_AfterConnection)
697:    */
698:   private function _AwardBadges($Sender, $Handler) {
699:     $Session = Gdn::Session();
700:     if(!C('Yaga.Badges.Enabled') || !$Session->IsValid()) {
701:       return;
702:     }
703: 
704:     // Let's us use __FUNCTION__ in the original hook
705:     $Hook = str_ireplace('_Handler', '', $Handler);
706: 
707:     $UserID = $Session->UserID;
708:     $User = $Session->User;
709: 
710:     $BadgeAwardModel = Yaga::BadgeAwardModel();
711:     $Badges = $BadgeAwardModel->GetUnobtained($UserID);
712: 
713:     $InteractionRules = RulesController::GetInteractionRules();
714: 
715:     $Rules = array();
716:     foreach($Badges as $Badge) {
717:       // The badge award needs to be processed
718:       if(($Badge->Enabled && $Badge->UserID != $UserID)
719:               || array_key_exists($Badge->RuleClass, $InteractionRules)) {
720:         // Create a rule object if needed
721:         $Class = $Badge->RuleClass;
722:         if(!in_array($Class, $Rules)) {
723:           $Rule = new $Class();
724:           $Rules[$Class] = $Rule;
725:         }
726: 
727:         $Rule = $Rules[$Class];
728:         // Only check awards for rules that use this hook
729:         if(in_array($Hook, $Rule->Hooks())) {
730:           $Criteria = (object) unserialize($Badge->RuleCriteria);
731:           $Result = $Rule->Award($Sender, $User, $Criteria);
732:           if($Result) {
733:             if(is_numeric($Result)) {
734:               $AwardedUserID = $Result;
735:             }
736:             else {
737:               $AwardedUserID = $UserID;
738:             }
739:             $BadgeAwardModel->Award($Badge->BadgeID, $AwardedUserID, $UserID);
740:           }
741:         }
742:       }
743:     }
744:   }
745: 
746:   /**
747:    * Add the appropriate resources for each controller
748:    *
749:    * @param Gdn_Controller $Sender
750:    */
751:   private function _AddResources($Sender) {
752:     $Sender->AddCssFile('reactions.css', 'yaga');
753:   }
754: 
755:   /**
756:    * Add global Yaga resources to all dashboard pages
757:    *
758:    * @param Gdn_Controller $Sender
759:    */
760:   public function Base_Render_Before($Sender) {
761:     if($Sender->MasterView == 'admin') {
762:       $Sender->AddCssFile('yaga.css', 'yaga');
763:     }
764:   }
765: 
766:   /**
767:    * Delete all of the Yaga related information for a specific user.
768:    * 
769:    * @param int $UserID The ID of the user to delete.
770:    * @param array $Options An array of options:
771:    *  - DeleteMethod: One of delete, wipe, or NULL
772:    * @param array $Data
773:    * 
774:    * @since 1.0
775:    */
776:    protected function DeleteUserData($UserID, $Options = array(), &$Data = NULL) {
777:     $SQL = Gdn::SQL();
778: 
779:     $DeleteMethod = GetValue('DeleteMethod', $Options, 'delete');
780:     if($DeleteMethod == 'delete') {
781:       // Remove neutral/negative reactions
782:       $Actions = Yaga::ActionModel()->GetWhere(array('AwardValue <' => 1))->Result();
783:       foreach($Actions as $Negative) {
784:         Gdn::UserModel()->GetDelete('Reaction', array('InsertUserID' => $UserID, 'ActionID' => $Negative->ActionID), $Data);
785:       }
786:     }
787:     else if($DeleteMethod == 'wipe') {
788:       // Completely remove reactions
789:       Gdn::UserModel()->GetDelete('Reaction', array('InsertUserID' => $UserID), $Data);
790:     }
791:     else {
792:       // Leave reactions
793:     }
794: 
795:     // Remove the reactions they have received
796:     Gdn::UserModel()->GetDelete('Reaction', array('ParentAuthorID' => $UserID), $Data);
797: 
798:     // Remove their badges
799:     Gdn::UserModel()->GetDelete('BadgeAward', array('UserID' => $UserID), $Data);
800: 
801:     // Blank the user's yaga information
802:     $SQL->Update('User')
803:             ->Set(array(
804:                 'CountBadges' => 0,
805:                 'RankID' => NULL,
806:                 'RankProgression' => 0
807:             ))
808:             ->Where('UserID', $UserID)
809:             ->Put();
810: 
811:     // Trigger a system wide point recount
812:     // TODO: Look into point re-calculation
813:   }
814: 
815:   /**
816:      * Remove Yaga data when deleting a user.
817:     *
818:     * @since 1.0
819:     * @package Yaga
820:     *
821:     * @param UserModel $Sender UserModel.
822:     */
823:    public function UserModel_BeforeDeleteUser_Handler($Sender) {
824:       $UserID = GetValue('UserID', $Sender->EventArguments);
825:       $Options = GetValue('Options', $Sender->EventArguments, array());
826:       $Options = is_array($Options) ? $Options : array();
827:       $Content =& $Sender->EventArguments['Content'];
828: 
829:       $this->DeleteUserData($UserID, $Options, $Content);
830:    }
831: 
832:   /**
833:    * Add update routines to the DBA controller
834:    *
835:    * @param DbaController $Sender
836:    */
837:   public function DbaController_CountJobs_Handler($Sender) {
838:     $Counts = array(
839:         'BadgeAward' => array('CountBadges')
840:     );
841: 
842:     foreach($Counts as $Table => $Columns) {
843:       foreach($Columns as $Column) {
844:         $Name = "Recalculate $Table.$Column";
845:         $Url = "/dba/counts.json?" . http_build_query(array('table' => $Table, 'column' => $Column));
846: 
847:         $Sender->Data['Jobs'][$Name] = $Url;
848:       }
849:     }
850:   }
851: 
852:   /**
853:    * Run the structure and stub scripts if necessary when the application is
854:    * enabled.
855:    */
856:   public function Setup() {
857:     $Config = Gdn::Factory(Gdn::AliasConfig);
858:     $Drop = C('Yaga.Version') === FALSE ? TRUE : FALSE;
859:     $Explicit = TRUE;
860:     include(PATH_APPLICATIONS . DS . 'yaga' . DS . 'settings' . DS . 'structure.php');
861:     include(PATH_APPLICATIONS . DS . 'yaga' . DS . 'settings' . DS . 'stub.php');
862: 
863:     $ApplicationInfo = array();
864:     include(CombinePaths(array(PATH_APPLICATIONS . DS . 'yaga' . DS . 'settings' . DS . 'about.php')));
865:     $Version = ArrayValue('Version', ArrayValue('Yaga', $ApplicationInfo, array()), 'Undefined');
866:     SaveToConfig('Yaga.Version', $Version);
867:   }
868: }
869: 
Yaga API documentation generated by ApiGen 2.8.0