Added skeleton rank controller-model-views

This commit is contained in:
Zachary Doll 2013-11-19 16:15:29 -06:00
parent e6cc8af84e
commit 94f603847b
5 changed files with 677 additions and 0 deletions

View File

@ -0,0 +1,250 @@
<?php if(!defined('APPLICATION')) exit();
/* Copyright 2013 Zachary Doll */
/**
* Contains management code for designing ranks.
*
* @since 1.0
* @package Yaga
*/
class RankController extends DashboardController {
/**
* @var array These objects will be created on instantiation and available via
* $this->ObjectName
*/
public $Uses = array('Form', 'RankModel');
/**
* Make this look like a dashboard page and add the resources
*
* @since 1.0
* @access public
*/
public function Initialize() {
parent::Initialize();
Gdn_Theme::Section('Dashboard');
if($this->Menu) {
$this->Menu->HighlightRoute('/rank');
}
$this->AddJsFile('admin.ranks.js');
$this->AddCssFile('ranks.css');
}
/**
* Manage the current ranks and add new ones
*
* @param int $Page
*/
public function Settings($Page = '') {
$this->Permission('Yaga.Ranks.Manage');
$this->AddSideMenu('rank/settings');
$this->Title(T('Manage Ranks'));
// Get list of ranks from the model and pass to the view
$this->SetData('Ranks', $this->RankModel->GetRanks());
$this->Render();
}
/**
* Edit an existing rank or add a new one
*
* @param int $RankID
* @throws ForbiddenException if no proper rules are found
*/
public function Edit($RankID = NULL) {
$this->Permission('Yaga.Ranks.Manage');
$this->AddSideMenu('rank/settings');
$this->Form->SetModel($this->RankModel);
$Edit = FALSE;
if($RankID) {
$this->Rank = $this->RankModel->GetRank($RankID);
$this->Form->AddHidden('RankID', $RankID);
$Edit = TRUE;
}
if($this->Form->IsPostBack() == FALSE) {
if(property_exists($this, 'Rank')) {
$this->Form->SetData($this->Rank);
}
}
else {
// Handle the photo upload
$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, 'ranks/' . $ImageBaseName);
$this->Form->SetFormValue('Photo', $Parts['SaveName']);
}
if($this->Form->Save()) {
if($Edit) {
$this->InformMessage('Rank updated successfully!');
}
else {
$this->InformMessage('Rank added successfully!');
}
Redirect('/yaga/rank/settings');
}
}
$this->Render('add');
}
/**
* Convenience function for nice URLs
*/
public function Add() {
$this->Edit();
}
/**
* Remove the rank via model.
*
* @todo Consider adding a confirmation page when not using JS
* @param int $RankID
*/
public function Delete($RankID) {
$this->Permission('Yaga.Ranks.Manage');
$this->AddSideMenu('rank/settings');
$this->RankModel->DeleteRank($RankID);
redirect('rank/settings');
}
/**
* Toggle the enabled state of a rank. Must be done via JS.
*
* @param int $RankID
* @throws PermissionException
*/
public function Toggle($RankID) {
if(!$this->Request->IsPostBack()) {
throw PermissionException('Javascript');
}
$this->Permission('Yaga.Ranks.Manage');
$this->AddSideMenu('rank/settings');
$Rank = $this->RankModel->GetRank($RankID);
if($Rank->Enabled) {
$Enable = FALSE;
$ToggleText = T('Disabled');
$ActiveClass = 'InActive';
}
else {
$Enable = TRUE;
$ToggleText = T('Enabled');
$ActiveClass = 'Active';
}
$Slider = Wrap(Wrap(Anchor($ToggleText, 'yaga/rank/toggle/' . $Rank->RankID, 'Hijack SmallButton'), 'span', array('class' => "ActivateSlider ActivateSlider-{$ActiveClass}")), 'td');
$this->RankModel->EnableRank($RankID, $Enable);
$this->JsonTarget('#RankID_' . $RankID . ' td:nth-child(7)', $Slider, 'ReplaceWith');
$this->Render('Blank', 'Utility', 'Dashboard');
}
/**
* Remove the photo association of a rank. This does not remove the actual file
*
* @param int $RankID
* @param string $TransientKey
*/
public function DeletePhoto($RankID = FALSE, $TransientKey = '') {
// Check permission
$this->Permission('Garden.Ranks.Manage');
$RedirectUrl = 'yaga/rank/edit/'.$RankID;
if (Gdn::Session()->ValidateTransientKey($TransientKey)) {
$this->RankModel->SetField($RankID, 'Photo', NULL);
$this->InformMessage(T('Rank 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();
}
}
/**
* You can manually award ranks to users for special cases
*
* @param int $UserID
*/
public function Award($UserID) {
// Check permission
$this->Permission('Garden.Ranks.Add');
$this->AddSideMenu('rank/settings');
// Only allow awarding if some ranks exist
if(!$this->RankModel->GetRankCount()) {
throw ForbiddenException('award ranks without any ranks defined');
}
$UserModel = Gdn::UserModel();
$User = $UserModel->GetID($UserID);
$this->SetData('Username', $User->Name);
$Ranks = $this->RankModel->GetRanks();
$Ranklist = array();
foreach($Ranks as $Rank) {
$Ranklist[$Rank->RankID] = $Rank->Name;
}
$this->SetData('Ranks', $Ranklist);
if($this->Form->IsPostBack() == FALSE) {
// Add the user id field
$this->Form->AddHidden('UserID', $User->UserID);
}
else {
$Validation = new Gdn_Validation();
$Validation->ApplyRule('UserID', 'ValidateRequired');
$Validation->ApplyRule('RankID', 'ValidateRequired');
if($Validation->Validate($this->Request->Post())) {
$FormValues = $this->Form->FormValues();
if($this->RankModel->UserHasRank($FormValues['UserID'], $FormValues['RankID'])) {
$this->Form->AddError($User->Name . T(' already has this rank!'), 'RankID');
// Need to respecify the user id
$this->Form->AddHidden('UserID', $User->UserID);
}
if($this->Form->ErrorCount() == 0) {
$this->RankModel->AwardRank($FormValues['RankID'], $FormValues['UserID'], Gdn::Session()->UserID, $FormValues['Reason']);
if($this->Request->Get('Target')) {
$this->RedirectUrl = $this->Request->Get('Target');
}
elseif($this->DeliveryType() == DELIVERY_TYPE_ALL) {
$this->RedirectUrl = Url(UserUrl($User));
}
else {
$this->JsonTarget('', '', 'Refresh');
}
}
}
else {
$this->Form->SetValidationResults($Validation->Results());
}
}
$this->Render();
}
}

296
models/class.rankmodel.php Normal file
View File

@ -0,0 +1,296 @@
<?php if (!defined('APPLICATION')) exit();
/* Copyright 2013 Zachary Doll */
/**
* Describes ranks and the associated rule criteria
*
* @todo Consider splitting into two models
* Events:
*
* @package Yaga
* @since 1.0
*/
class RankModel extends Gdn_Model {
/**
* Used as a cache
* @var DataSet
*/
private static $_Ranks = NULL;
/**
* Defines the related database table name.
*/
public function __construct() {
parent::__construct('Rank');
}
/**
* Returns a list of all ranks
*
* @return DataSet
*/
public function GetRanks() {
if(empty(self::$_Ranks)) {
self::$_Ranks = $this->SQL
->Select()
->From('Rank')
->OrderBy('RankID')
->Get()
->Result();
}
return self::$_Ranks;
}
public function GetRankCount() {
return count($this->GetRanks());
}
/**
* Returns a list of currently enabled ranks
*
* @return DataSet
*/
public function GetEnabledRanks() {
return $this->SQL
->Select()
->From('Rank')
->Where('Enabled', TRUE)
->OrderBy('RankID')
->Get()
->Result();
}
/**
* Returns data for a specific rank
*
* @param int $RankID
* @return DataSet
*/
public function GetRank($RankID) {
$Rank = $this->SQL
->Select()
->From('Rank')
->Where('RankID', $RankID)
->Get()
->FirstRow();
return $Rank;
}
/**
* Returns the last inserted rank
*
* @return DataSet
*/
public function GetNewestRank() {
$Rank = $this->SQL
->Select()
->From('Rank')
->OrderBy('RankID', 'desc')
->Get()
->FirstRow();
return $Rank;
}
public function GetRankAwardCount($RankID) {
$Wheres = array('RankID' => $RankID);
return $this->SQL
->GetCount('RankAward', $Wheres);
}
public function GetRecentRankAwards($RankID, $Limit = 15) {
return $this->SQL
->Select('ba.UserID, ba.DateInserted, u.Name, u.Photo, u.Gender, u.Email')
->From('RankAward ba')
->Join('User u', 'ba.UserID = u.UserID')
->Where('RankID', $RankID)
->OrderBy('DateInserted', 'Desc')
->Limit($Limit)
->Get()
->Result();
}
/**
* Convenience function to determin if a rank id currently exists
*
* @param int $RankID
* @return bool
*/
public function RankExists($RankID) {
$temp = $this->GetRank($RankID);
return !empty($temp);
}
/**
* Enable or disable a rank
*
* @param int $RankID
* @param bool $Enable
*/
public function EnableRank($RankID, $Enable) {
$Enable = (!$Enable) ? FALSE : TRUE;
$this->SQL
->Update('Rank')
->Set('Enabled', $Enable)
->Where('RankID', $RankID)
->Put();
}
/**
* Remove a rank and associated awards
*
* @param int $RankID
*/
public function DeleteRank($RankID) {
if($this->RankExists($RankID)) {
$this->SQL->Delete('Rank', array('RankID' => $RankID));
$this->SQL->Delete('RankAward', array('RankID' => $RankID));
}
}
/**
* Award a rank to a user and record some activity
*
* @param int $RankID
* @param int $UserID This is the user that should get the award
* @param int $InsertUserID This is the user that gave the award
* @param string $Reason This is the reason the giver gave with the award
*/
public function AwardRank($RankID, $UserID, $InsertUserID = NULL, $Reason = '') {
$Rank = $this->GetRank($RankID);
if(!empty($Rank)) {
if(!$this->UserHasRank($UserID, $RankID)) {
$this->SQL->Insert('RankAward', array(
'RankID' => $RankID,
'UserID' => $UserID,
'InsertUserID' => $InsertUserID,
'Reason' => $Reason,
'DateInserted' => date(DATE_ISO8601)
));
// Record the points for this rank
UserModel::GivePoints($UserID, $Rank->AwardValue, 'Rank');
// Record some activity
$Rank = $this->GetRank($RankID);
$ActivityModel = new ActivityModel();
$Activity = array(
'ActivityType' => 'RankAward',
'ActivityUserID' => Gdn::Session()->UserID,
'RegardingUserID' => $UserID,
'Photo' => '/uploads/' . $Rank->Photo,
'RecordType' => 'Rank',
'RecordID' => $RankID,
'Route' => '/ranks/detail/' . $Rank->RankID . '/' . Gdn_Format::Url($Rank->Name),
'HeadlineFormat' => '{RegardingUserID,You} earned the <a href="{Url,html}">{Data.Name,text}</a> rank.',
'Data' => array(
'Name' => $Rank->Name
),
'Story' => $Rank->Description
);
$ActivityModel->Queue($Activity);
// Notify the user of the award
$Activity['NotifyUserID'] = $UserID;
$Activity['Emailed'] = ActivityModel::SENT_PENDING;
$ActivityModel->Queue($Activity, 'Ranks', array('Force' => TRUE));
$ActivityModel->SaveQueue();
$this->EventArguments['UserID'] = $UserID;
$this->FireEvent('AfterRankAward');
}
}
}
/**
* Returns how many ranks the user has of this particular id. It should only
* ever be 1 or zero.
*
* @param int $UserID
* @param int $RankID
* @return int
*/
public function UserHasRank($UserID, $RankID) {
return $this->SQL
->Select()
->From('RankAward')
->Where('RankID', $RankID)
->Where('UserID', $UserID)
->GetCount();
}
/**
* Returns the ranks a user already has
*
* @param int $UserID
* @return array
*/
public function GetUserRankAward($UserID, $RankID) {
return $this->SQL
->Select()
->From('Rank b')
->Join('RankAward ba', 'ba.RankID = b.RankID', 'left')
->Where('b.RankID', $RankID)
->Where('ba.UserID', $UserID)
->Get()
->FirstRow();
}
/**
* Returns the ranks a user already has
*
* @param int $UserID
* @return array
*/
public function GetUserRankAwards($UserID) {
return $this->SQL
->Select()
->From('Rank b')
->Join('RankAward ba', 'ba.RankID = b.RankID', 'left')
->Where('ba.UserID', $UserID)
->Get()
->Result(DATASET_TYPE_ARRAY);
}
/**
* Returns the full list of ranks and the associated user awards if applicable
*
* @param int $UserID
* @return DataSet
*/
public function GetAllRanksUserAwards($UserID) {
return $this->SQL
->Select('b.*, ba.UserID, ba.InsertUserID, ba.Reason, ba.DateInserted, ui.Name as InsertUserName')
->From('Rank b')
->Join('RankAward ba', 'ba.RankID = b.RankID', 'left')
->Join('User ui', 'ba.InsertUserID = ui.UserID', 'left')
->Where('ba.UserID', $UserID)
->OrWhere('b.RankID is not null') // needed to get the full set of ranks
->GroupBy('b.RankID')
->OrderBy('b.RankID', 'Desc')
->Get();
}
/**
* Returns the list of unobtained but enabled ranks for a specific user
*
* @param int $UserID
* @param bool $Enabled Description
* @return DataSet
*/
public function GetRanksToCheckForUser($UserID) {
return $this->SQL
->Select()
->From('Rank b')
->Join('RankAward ba', 'b.RankID = ba.RankID', 'left')
->Where('ba.UserID', $UserID)
->Where('b.Enabled', 1)
//->OrWhere('b.RankID is not null') // needed to get the full set of ranks
->Get()
->Result();
}
}

55
views/rank/add.php Normal file
View File

@ -0,0 +1,55 @@
<?php if(!defined('APPLICATION')) exit();
/* Copyright 2013 Zachary Doll */
if(property_exists($this, 'Rank')) {
echo Wrap(T('Edit Rank'), 'h1');
}
else {
echo Wrap(T('Add Rank'), 'h1');
}
echo $this->Form->Open(array('enctype' => 'multipart/form-data', 'class' => 'Rank'));
echo $this->Form->Errors();
?>
<ul>
<li>
<?php
echo $this->Form->Label('Photo', 'PhotoUpload');
$Photo = $this->Form->GetValue('Photo');
if($Photo) {
echo Img(Gdn_Upload::Url($Photo));
echo '<br />'.Anchor(T('Delete Photo'),
CombinePaths(array('rank/deletephoto', $this->Rank->RankID, Gdn::Session()->TransientKey())),
'SmallButton Danger PopConfirm');
}
echo $this->Form->Input('PhotoUpload', 'file');
?>
</li>
<li>
<?php
echo $this->Form->Label('Name', 'Name');
echo $this->Form->TextBox('Name');
?>
</li>
<li>
<?php
echo $this->Form->Label('Description', 'Description');
echo $this->Form->TextBox('Description');
?>
</li>
<li>
<?php
echo $this->Form->Label('Award Value', 'AwardValue');
echo $this->Form->TextBox('AwardValue');
?>
</li>
<li>
<?php
echo $this->Form->Label('Active', 'Enabled');
echo $this->Form->CheckBox('Enabled');
?>
</li>
</ul>
<?php
echo $this->Form->Close('Save');

30
views/rank/award.php Normal file
View File

@ -0,0 +1,30 @@
<?php if(!defined('APPLICATION')) exit();
/* Copyright 2013 Zachary Doll */
$Ranks = $this->Data('Ranks');
$Username = $this->Data('Username', 'Unknown');
echo '<div id="UserRankForm">';
echo Wrap(T('Give a Rank to ') . $Username, 'h1');
echo $this->Form->Open();
echo $this->Form->Errors();
echo Wrap(
Wrap(
$this->Form->Label('Rank', 'RankID') .
$this->Form->Dropdown('RankID', $Ranks),
'li') .
Wrap(
$this->Form->Label('Reason (optional)', 'Reason') .
$this->Form->TextBox('Reason', array('Multiline' => TRUE)),
'li') .
Wrap(
Anchor(T('Cancel'), 'rank/settings'),
'li'),
'ul'
);
echo $this->Form->Close('Give Rank');
echo '</div>';

46
views/rank/settings.php Normal file
View File

@ -0,0 +1,46 @@
<?php if (!defined('APPLICATION')) exit();
/* Copyright 2013 Zachary Doll */
echo Wrap($this->Title(), 'h1');
echo Wrap(Wrap('Add or edit the available ranks that can be earned.', 'div'), 'div', array('class' => 'Wrap'));
echo Wrap(Anchor('Add Rank', 'yaga/rank/add', array('class' => 'SmallButton')), 'div', array('class' => 'Wrap'));
?>
<table id="Actions" class="AltRows">
<thead>
<tr>
<th>Image</th>
<th>Name</th>
<th>Description</th>
<th>Rule</th>
<th>Award Value</th>
<th>Active</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<?php
$Alt = 'Alt';
foreach($this->Data('Ranks') as $Rank) {
$Alt = $Alt ? '' : 'Alt';
$Row = '';
// TODO: Show image in pop up rather than linking to it
if($Rank->Photo) {
$Row .= Wrap(Anchor(Img(Gdn_Upload::Url($Rank->Photo), array('class' => 'RankPhoto')), Gdn_Upload::Url($Rank->Photo)), 'td');
}
else {
$Row .= Wrap(T('None'), 'td');
}
$Row .= Wrap($Rank->Name, 'td');
$Row .= Wrap($Rank->Description, 'td');
$Row .= Wrap($Rules[$Rank->RuleClass], 'td');
$Row .= Wrap($Rank->AwardValue, 'td');
$ToggleText = ($Rank->Enabled) ? T('Enabled') : T('Disabled');
$ActiveClass = ($Rank->Enabled) ? 'Active' : 'InActive';
$Row .= Wrap(Wrap(Anchor($ToggleText, 'yaga/rank/toggle/' . $Rank->RankID, 'Hijack SmallButton'), 'span', array('class' => "ActivateSlider ActivateSlider-{$ActiveClass}")), 'td');
$Row .= Wrap(Anchor(T('Edit'), 'yaga/rank/edit/' . $Rank->RankID, array('class' => 'SmallButton')) . Anchor(T('Delete'), 'yaga/rank/delete/' . $Rank->RankID, array('class' => 'Danger PopConfirm SmallButton')), 'td');
echo Wrap($Row, 'tr', array('id' => 'RankID_' . $Rank->RankID, 'data-rankid' => $Rank->RankID, 'class' => $Alt));
}
?>
</tbody>
</table>