Badges WIP: Rules autoloading work

This commit is contained in:
Zachary Doll 2013-11-04 17:32:04 -06:00
parent 692c530fb6
commit 0f3e73cbfa
11 changed files with 288 additions and 59 deletions

View File

@ -2,7 +2,7 @@
/* Copyright 2013 Zachary Doll */
/**
* All is the base class for controllers throughout the gamification applicati0n.
* Contains management code for creating badges.
*
* @since 1.0
* @package Yaga
@ -51,6 +51,26 @@ class BadgesController extends DashboardController {
$this->Render();
}
public function UpdateRuleMap() {
foreach(glob(PATH_APPLICATIONS . DS . 'yaga' . DS . 'rules' . DS . '*.php') as $filename) {
include_once $filename;
}
$Cache = array();
$Cache['Class'] = array();
$Cache['Name'] = array();
$Cache['Description'] = array();
foreach(get_declared_classes() as $className) {
if(in_array('YagaRule', class_implements($className))) {
$object = new $className();
$Cache['Name'][] = $object->FriendlyName();
$Cache['Description'][] = $object->Description();
$Cache['Class'][] = $className;
}
}
decho($Cache);
}
public function Edit($BadgeID = NULL) {
$this->Permission('Yaga.Badges.Manage');
@ -65,50 +85,32 @@ class BadgesController extends DashboardController {
}
if($this->Form->IsPostBack() == FALSE) {
$this->Form->SetData($this->Badge);
if(property_exists($this, 'Badge')) {
$this->Form->SetData($this->Badge);
}
}
else {
$Upload = new Gdn_Upload();
$TmpImage = $Upload->ValidateUpload('PhotoUpload', FALSE);
if($TmpImage) {
// Generate the target image name
$TargetImage = $Upload->GenerateTargetName(PATH_UPLOADS);
$ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME);
// Save the uploaded image
$Parts = $Upload->SaveAs($TmpImage, $ImageBaseName);
$this->Form->SetFormValue('Photo', $Parts['SaveName']);
}
if($this->Form->Save()) {
$Upload = new Gdn_Upload();
$TmpImage = $Upload->ValidateUpload('PhotoUpload_New', FALSE);
if($TmpImage) {
// Generate the target image name
$TargetImage = $Upload->GenerateTargetName(PATH_UPLOADS);
$ImageBaseName = pathinfo($TargetImage, PATHINFO_BASENAME);
// Save the uploaded image
$Parts = $Upload->SaveAs(
$TmpImage, $ImageBaseName
);
$this->Form->SetFormValue('Photo', $Parts['SaveName']);
}
if($Edit) {
$Badge = $this->BadgeModel->GetBadge($this->Form->GetFormValue('BadgeID'));
}
else {
$Badge = $this->BadgeModel->GetNewestBadge();
}
$NewBadgeRow = '<tr id="BadgeID_' . $Badge->BadgeID . '" data-badgeid="' . $Badge->BadgeID . '"' . ($Alt ? ' class="Alt"' : '') . '>';
$NewBadgeRow .= '<td>' . Img($Badge->Photo) . '</td>';
$NewBadgeRow .= "<td>$Badge->Name</td>";
$NewBadgeRow .= "<td>$Badge->Description</td>";
$NewBadgeRow .= "<td>$Badge->RuleClass</td>";
$NewBadgeRow .= "<td>$Badge->RuleCriteria</td>";
$NewBadgeRow .= "<td>$Badge->AwardValue</td>";
$ToggleText = ($Badge->Enabled) ? T('Yes') : T('No');
$NewBadgeRow .= '<td>' . Anchor($ToggleText, 'yaga/badges/toggle/' . $Badge->BadgeID, array('class' => 'Hijack')) . '</td>';
$NewBadgeRow .= '<td>' . Anchor(T('Edit'), 'yaga/badges/edit/' . $Badge->BadgeID, array('class' => 'SmallButton')) . Anchor(T('Delete'), 'yaga/badges/delete/' . $Badge->BadgeID, array('class' => 'Danger PopConfirm SmallButton')) . '</td>';
$NewBadgeRow .= '</tr>';
if($Edit) {
$this->JsonTarget('#BadgeID_' . $this->Badge->BadgeID, $NewBadgeRow, 'ReplaceWith');
$this->InformMessage('Badge updated successfully!');
}
else {
$this->JsonTarget('#Badges tbody', $NewBadgeRow, 'Append');
$this->InformMessage('Badge added successfully!');
}
Redirect('/yaga/badges/settings');
}
}
@ -130,16 +132,49 @@ class BadgesController extends DashboardController {
public function Toggle($BadgeID) {
if(!$this->Request->IsPostBack()) {
//throw PermissionException('Javascript');
throw PermissionException('Javascript');
}
$this->Permission('Yaga.Reactions.Manage');
$this->AddSideMenu('badges/settings');
$Badge = $this->BadgeModel->GetBadge($BadgeID);
$Enable = (!$Badge->Enabled) ? TRUE : FALSE;
$EnableText = ($Enable) ? 'Yes' : 'No';
if($Badge->Enabled) {
$Enable = FALSE;
$ToggleText = T('Disabled');
$ActiveClass = 'InActive';
}
else {
$Enable = TRUE;
$ToggleText = T('Enabled');
$ActiveClass = 'Active';
}
$Slider = Wrap(Wrap(Anchor($ToggleText, 'yaga/badges/toggle/' . $Badge->BadgeID, 'Hijack SmallButton'), 'span', array('class' => "ActivateSlider ActivateSlider-{$ActiveClass}")), 'td');
$this->BadgeModel->EnableBadge($BadgeID, $Enable);
$this->JsonTarget('#BadgeID_' . $BadgeID . ' td:nth-child(7)', Wrap(Anchor($EnableText, 'yaga/badges/toggle/' . $BadgeID, array('class' => 'Hijack')), 'td'), 'ReplaceWith');
$this->JsonTarget('#BadgeID_' . $BadgeID . ' td:nth-child(7)', $Slider, 'ReplaceWith');
$this->Render('Blank', 'Utility', 'Dashboard');
}
public function DeletePhoto($BadgeID = FALSE, $TransientKey = '') {
// Check permission
$this->Permission('Garden.Badges.Manage');
$RedirectUrl = 'yaga/badges/edit/'.$BadgeID;
if (Gdn::Session()->ValidateTransientKey($TransientKey)) {
// Do removal, set message, redirect
$BadgeModel = new BadgeModel();
$BadgeModel->SetField($BadgeID, 'Photo', NULL);
$this->InformMessage(T('Badge photo has been deleted.'));
}
if ($this->_DeliveryType == DELIVERY_TYPE_ALL) {
Redirect($RedirectUrl);
} else {
$this->ControllerName = 'Home';
$this->View = 'FileNotFound';
$this->RedirectUrl = Url($RedirectUrl);
$this->Render();
}
}
}

5
design/badges.css Normal file
View File

@ -0,0 +1,5 @@
/* Copyright 2013 Zachary Doll */
.BadgePhoto {
height: 25px;
}

View File

@ -88,5 +88,26 @@ class BadgeModel extends Gdn_Model {
// }
}
}
public function AwardBadge($BadgeID, $UserID) {
if($this->BadgeExists($BadgeID)) {
if(!$this->UserHasBadge($UserID, $BadgeID)) {
$this->SQL->Insert('BadgeAward', array(
'BadgeID' => $BadgeID,
'UserID' => $UserID,
'DateInserted' => date(DATE_ISO8601)
));
}
}
}
public function UserHasBadge($UserID, $BadgeID) {
return $this->SQL
->Select()
->From('BadgeAward')
->Where('BadgeID', $ActionID)
->Where('UserID', $UserID)
->GetCount();
}
}

View File

@ -0,0 +1,43 @@
<?php if(!defined('APPLICATION')) exit();
include_once 'interface.yagarule.php';
/**
* This rule awards badges based on a user's join date
*
* @author Zachary Doll
* @since 1.0
* @package Yaga
*/
class CommentCount implements YagaRule{
public function AwardCheck($Criteria, $UserID) {
$UserModel = new UserModel();
$User = $UserModel->GetID($UserID);
$InsertDate = strtotime($User->DateInserted);
$Days = $Criteria * 24 * 60 * 60;
if($InsertDate < time() - $Days) {
return TRUE;
}
else {
return FALSE;
}
}
public function CalculationHook() {
return 'EntryController_Signin_Handler';
}
public function Description() {
$Description = 'This rule checks a users total comment count against the criteria. If the user has more comments than the criteria, this will return true.';
return $Description;
}
public function AggregationFunction($UserID) {
return TRUE;
}
public function FriendlyName() {
return 'Comment Count Total';
}
}
?>

View File

@ -0,0 +1,43 @@
<?php if(!defined('APPLICATION')) exit();
include_once 'interface.yagarule.php';
/**
* This rule awards badges based on a user's join date
*
* @author Zachary Doll
* @since 1.0
* @package Yaga
*/
class DiscussionCount implements YagaRule{
public function AwardCheck($Criteria, $UserID) {
$UserModel = new UserModel();
$User = $UserModel->GetID($UserID);
$InsertDate = strtotime($User->DateInserted);
$Days = $Criteria * 24 * 60 * 60;
if($InsertDate < time() - $Days) {
return TRUE;
}
else {
return FALSE;
}
}
public function CalculationHook() {
return 'EntryController_Signin_Handler';
}
public function Description() {
$Description = 'This rule checks a users discussion count against the criteria. It will return true once the user has as many or more than the given amount.';
return $Description;
}
public function AggregationFunction($UserID) {
return TRUE;
}
public function FriendlyName() {
return 'Discussion Count Total';
}
}
?>

43
rules/class.joindate.php Normal file
View File

@ -0,0 +1,43 @@
<?php if(!defined('APPLICATION')) exit();
include_once 'interface.yagarule.php';
/**
* This rule awards badges based on a user's join date
*
* @author Zachary Doll
* @since 1.0
* @package Yaga
*/
class JoinDate implements YagaRule{
public function AwardCheck($Criteria, $UserID) {
$UserModel = new UserModel();
$User = $UserModel->GetID($UserID);
$InsertDate = strtotime($User->DateInserted);
$Days = $Criteria * 24 * 60 * 60;
if($InsertDate < time() - $Days) {
return TRUE;
}
else {
return FALSE;
}
}
public function CalculationHook() {
return 'EntryController_Signin_Handler';
}
public function Description() {
$Description = 'This rule checks a users join date against the current date. The criteria is the age of the account in days. It will return true if the account is older than this number of days.';
return $Description;
}
public function AggregationFunction($UserID) {
return TRUE;
}
public function FriendlyName() {
return 'Join Date';
}
}
?>

View File

@ -0,0 +1,15 @@
<?php if(!defined('APPLICATION')) exit();
/**
*
* @author Zachary Doll
* @since 1.0
* @package Yaga
*/
interface YagaRule {
public function AwardCheck($Criteria, $UserID);
public function FriendlyName();
public function CalculationHook();
public function Description();
public function AggregationFunction($UserID);
}
?>

View File

@ -1,2 +1,11 @@
<?php if (!defined('APPLICATION')) exit();
// Application's bootstrap stuff can go here. Define global functions, mess with the Factory, Config modifications.
// Load up the rules
$Map = Gdn_Autoloader::MAP_LIBRARY;
$Context = Gdn_Autoloader::CONTEXT_APPLICATION;
$Path = PATH_APPLICATIONS . DS . 'yaga' . DS . 'rules';
$Options = array();
// Set the map options
$Options['Extension'] = 'yaga';
Gdn_Autoloader::RegisterMap($Map, $Context, $Path, $Options);

View File

@ -43,3 +43,10 @@ $Construct->Table('Badge')
->Column('AwardValue', 'int', 0)
->Column('Enabled', 'tinyint(1)', '1')
->Set($Explicit, $Drop);
$Construct->Table('BadgeAward')
->PrimaryKey('BadgeAwardID')
->Column('BadgeID', 'int')
->Column('UserID', 'int')
->Column('DateInserted', 'datetime')
->Set($Explicit, $Drop);

View File

@ -1,6 +1,6 @@
<?php if(!defined('APPLICATION')) exit();
/* Copyright 2013 Zachary Doll */
if(is_object($this->Badge)) {
if(property_exists($this, 'Badge')) {
echo Wrap(T('Edit Badge'), 'h1');
}
else {
@ -17,9 +17,9 @@ echo $this->Form->Errors();
$Photo = $this->Form->GetValue('Photo');
if($Photo) {
echo Img(Gdn_Upload::Url($Photo));
//echo '<br />'.Anchor(T('Delete Photo'),
// CombinePaths(array('vanilla/settings/deletecategoryphoto', $this->Category->CategoryID, Gdn::Session()->TransientKey())),
//'SmallButton Danger PopConfirm');
echo '<br />'.Anchor(T('Delete Photo'),
CombinePaths(array('badges/deletephoto', $this->Badge->BadgeID, Gdn::Session()->TransientKey())),
'SmallButton Danger PopConfirm');
}
echo $this->Form->Input('PhotoUpload', 'file');
?>

View File

@ -3,7 +3,7 @@
echo Wrap($this->Title(), 'h1');
echo Wrap(Wrap('Add or edit the available badges that can be earned.', 'div'), 'div', array('class' => 'Wrap'));
echo Wrap(Anchor('Add Action', 'yaga/badges/add', array('class' => 'Popup SmallButton')), 'div', array('class' => 'Wrap'));
echo Wrap(Anchor('Add Action', 'yaga/badges/add', array('class' => 'SmallButton')), 'div', array('class' => 'Wrap'));
?>
<table id="Actions" class="AltRows">
@ -21,19 +21,27 @@ echo Wrap(Anchor('Add Action', 'yaga/badges/add', array('class' => 'Popup SmallB
</thead>
<tbody>
<?php
$Alt = '';
$Alt = 'Alt';
foreach($this->Data('Badges') as $Badge) {
echo '<tr id="BadgeID_' . $Badge->BadgeID . '" data-badgeid="'. $Badge->BadgeID . '"' . ($Alt ? ' class="Alt"' : '') . '>';
echo '<td>' . Img($Badge->Photo) . '</td>';
echo "<td>$Badge->Name</td>";
echo "<td>$Badge->Description</td>";
echo "<td>$Badge->RuleClass</td>";
echo "<td>$Badge->RuleCriteria</td>";
echo "<td>$Badge->AwardValue</td>";
$ToggleText = ($Badge->Enabled) ? T('Yes') : T('No');
echo '<td>' . Anchor($ToggleText, 'yaga/badges/toggle/' . $Badge->BadgeID, array('class' => 'Hijack')) . '</td>';
echo '<td>' . Anchor(T('Edit'), 'yaga/badges/edit/' . $Badge->BadgeID, array('class' => 'Popup SmallButton')) . Anchor(T('Delete'), 'yaga/badges/delete/' . $Badge->BadgeID, array('class' => 'Danger PopConfirm SmallButton')) . '</td>';
echo '</tr>';
$Alt = $Alt ? '' : 'Alt';
$Row = '';
// TODO: Show image in pop up rather than linking to it
if($Badge->Photo) {
$Row .= Wrap(Anchor(Img(Gdn_Upload::Url($Badge->Photo), array('class' => 'BadgePhoto')), Gdn_Upload::Url($Badge->Photo)), 'td');
}
else {
$Row .= Wrap(T('None'), 'td');
}
$Row .= Wrap($Badge->Name, 'td');
$Row .= Wrap($Badge->Description, 'td');
$Row .= Wrap($Badge->RuleClass, 'td');
$Row .= Wrap($Badge->RuleCriteria, 'td');
$Row .= Wrap($Badge->AwardValue, 'td');
$ToggleText = ($Badge->Enabled) ? T('Enabled') : T('Disabled');
$ActiveClass = ($Badge->Enabled) ? 'Active' : 'InActive';
$Row .= Wrap(Wrap(Anchor($ToggleText, 'yaga/badges/toggle/' . $Badge->BadgeID, 'Hijack SmallButton'), 'span', array('class' => "ActivateSlider ActivateSlider-{$ActiveClass}")), 'td');
$Row .= Wrap(Anchor(T('Edit'), 'yaga/badges/edit/' . $Badge->BadgeID, array('class' => 'SmallButton')) . Anchor(T('Delete'), 'yaga/badges/delete/' . $Badge->BadgeID, array('class' => 'Danger PopConfirm SmallButton')), 'td');
echo Wrap($Row, 'tr', array('id' => 'BadgeID_' . $Badge->BadgeID, 'data-badgeid' => $Badge->BadgeID, 'class' => $Alt));
}
?>
</tbody>