2014-02-10 15:18:28 -06:00
< ? php if ( ! defined ( 'APPLICATION' )) exit ();
2014-02-06 14:44:21 -06:00
/* Copyright 2013 Zachary Doll */
/**
* Manage the yaga application including configuration and import / export
*
* @ since 1.0
* @ package Yaga
*/
class YagaController extends DashboardController {
/**
* @ var array These objects will be created on instantiation and available via
* $this -> ObjectName
*/
public $Uses = array ( 'Form' );
/**
* Make this look like a dashboard page and add the resources
*
* @ since 1.0
* @ access public
*/
public function Initialize () {
parent :: Initialize ();
$this -> Application = 'Yaga' ;
Gdn_Theme :: Section ( 'Dashboard' );
if ( $this -> Menu ) {
$this -> Menu -> HighlightRoute ( '/yaga' );
}
2014-02-06 15:08:29 -06:00
$this -> AddSideMenu ( 'yaga/settings' );
2014-02-07 14:05:13 -06:00
2014-02-06 14:44:21 -06:00
$this -> AddCssFile ( 'yaga.css' );
}
2014-02-07 14:05:13 -06:00
2014-02-06 14:44:21 -06:00
/**
* Redirect to settings by default
*/
public function Index () {
$this -> Settings ();
}
/**
* This handles all the core settings for the gamification application .
*/
public function Settings () {
$this -> Permission ( 'Garden.Settings.Manage' );
$this -> Title ( T ( 'Yaga.Settings' ));
// Get list of actions from the model and pass to the view
$ConfigModule = new ConfigurationModule ( $this );
$ConfigModule -> Initialize ( array (
2014-02-07 14:05:13 -06:00
'Yaga.Reactions.Enabled' => array (
'LabelCode' => 'Use Reactions' ,
'Control' => 'Checkbox'
),
'Yaga.Badges.Enabled' => array (
'LabelCode' => 'Use Badges' ,
'Control' => 'Checkbox'
),
'Yaga.Ranks.Enabled' => array (
'LabelCode' => 'Use Ranks' ,
'Control' => 'Checkbox'
),
'Yaga.LeaderBoard.Enabled' => array (
'LabelCode' => 'Show leaderboard on activity page' ,
'Control' => 'Checkbox'
),
'Yaga.LeaderBoard.Limit' => array (
'LabelCode' => 'Maximum number of leaders to show' ,
'Control' => 'Textbox' ,
'Options' => array (
'Size' => 45 ,
'class' => 'SmallInput'
)
2014-02-06 14:44:21 -06:00
)
));
$this -> ConfigurationModule = $ConfigModule ;
2014-02-10 15:18:28 -06:00
$this -> Render ();
2014-02-06 14:44:21 -06:00
}
2014-02-10 15:18:28 -06:00
/**
* Import a Yaga transport file
*/
2014-02-06 14:44:21 -06:00
public function Import () {
2014-02-06 15:08:29 -06:00
$this -> Title ( T ( 'Yaga.Import' ));
2014-02-08 16:12:59 -06:00
$this -> SetData ( 'TransportType' , 'Import' );
2014-02-10 16:28:50 -06:00
if ( ! class_exists ( 'ZipArchive' )) {
$this -> Form -> AddError ( 'You do not seem to have the minimum requirements to import a Yaga configuration automatically. Please reference manual_transport.md for more information.' );
}
2014-02-10 15:18:28 -06:00
if ( $this -> Form -> IsPostBack () == TRUE ) {
2014-02-10 14:55:18 -06:00
// Handle the file upload
$Upload = new Gdn_Upload ();
$TmpZip = $Upload -> ValidateUpload ( 'FileUpload' , FALSE );
$ZipFile = FALSE ;
if ( $TmpZip ) {
// Generate the target name
$TargetFile = $Upload -> GenerateTargetName ( PATH_UPLOADS , 'zip' );
$BaseName = pathinfo ( $TargetFile , PATHINFO_BASENAME );
// Save the uploaded zip
$Parts = $Upload -> SaveAs ( $TmpZip , $BaseName );
$ZipFile = PATH_UPLOADS . DS . $Parts [ 'SaveName' ];
2014-02-10 16:28:50 -06:00
$this -> SetData ( 'TransportPath' , $ZipFile );
2014-02-10 14:55:18 -06:00
}
2014-02-10 16:28:50 -06:00
$Include = $this -> _FindIncludes ();
2014-02-10 14:55:18 -06:00
if ( count ( $Include )) {
2014-02-10 16:28:50 -06:00
$Info = $this -> _ExtractZip ( $ZipFile );
$this -> _ImportData ( $Info , $Include );
Gdn_FileSystem :: RemoveFolder ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' );
2014-02-10 14:55:18 -06:00
}
else {
$this -> Form -> AddError ( 'You must select at least one item to import.' );
}
}
2014-02-10 16:28:50 -06:00
if ( $this -> Form -> ErrorCount () == 0 && $this -> Form -> IsPostBack ()) {
$this -> Render ( 'transport-success' );
}
else {
$this -> Render ();
}
2014-02-06 14:44:21 -06:00
}
2014-02-07 14:05:13 -06:00
2014-02-10 15:18:28 -06:00
/**
* Create a Yaga transport file
*/
2014-02-06 14:44:21 -06:00
public function Export () {
2014-02-06 15:08:29 -06:00
$this -> Title ( T ( 'Yaga.Export' ));
2014-02-08 16:12:59 -06:00
$this -> SetData ( 'TransportType' , 'Export' );
2014-02-07 14:05:13 -06:00
2014-02-10 16:28:50 -06:00
if ( ! class_exists ( 'ZipArchive' )) {
$this -> Form -> AddError ( 'You do not seem to have the minimum requirements to export your Yaga configuration automatically. Please reference manual_transport.md for more information.' );
}
2014-02-10 14:55:18 -06:00
2014-02-10 16:28:50 -06:00
if ( $this -> Form -> IsPostBack ()) {
$Include = $this -> _FindIncludes ();
2014-02-08 16:12:59 -06:00
if ( count ( $Include )) {
2014-02-10 16:28:50 -06:00
$Filename = $this -> _ExportData ( $Include );
$this -> SetData ( 'TransportPath' , $Filename );
2014-02-08 16:12:59 -06:00
}
else {
$this -> Form -> AddError ( 'You must select at least one item to export.' );
}
2014-02-10 16:28:50 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-10 16:28:50 -06:00
if ( $this -> Form -> ErrorCount () == 0 && $this -> Form -> IsPostBack ()) {
$this -> Render ( 'transport-success' );
}
else {
$this -> Render ();
2014-02-08 16:12:59 -06:00
}
2014-02-07 16:03:50 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-10 16:28:50 -06:00
protected function _FindIncludes () {
$FormValues = $this -> Form -> FormValues ();
$Sections = $FormValues [ 'Checkboxes' ];
// Figure out which boxes were checked
$Include = array ();
foreach ( $Sections as $Section ) {
$Include [ $Section ] = $FormValues [ $Section ];
}
return $Include ;
}
2014-02-10 15:18:28 -06:00
/**
* Creates a transport file for easily transferring Yaga configurations across
* installs
2014-02-10 16:28:50 -06:00
*
2014-02-10 15:18:28 -06:00
* @ param array An array containing the config areas to transfer
* @ param string Where to save the transport file
* @ return mixed False on failure , the path to the transport file on success
*/
2014-02-10 16:28:50 -06:00
protected function _ExportData ( $Include = array (), $Path = NULL ) {
2014-02-07 16:03:50 -06:00
$StartTime = microtime ( TRUE );
2014-02-07 16:35:31 -06:00
$Info = new stdClass ();
$Info -> Version = C ( 'Yaga.Version' , '?.?' );
$Info -> StartDate = date ( 'Y-m-d H:i:s' );
2014-02-10 14:55:18 -06:00
2014-02-07 16:03:50 -06:00
if ( is_null ( $Path )) {
2014-02-10 15:18:28 -06:00
$Path = PATH_UPLOADS . DS . 'export' . date ( 'Y-m-d-His' ) . '.yaga.zip' ;
2014-02-07 16:03:50 -06:00
}
$FH = new ZipArchive ();
2014-02-07 16:35:31 -06:00
$Images = array ();
$Hashes = array ();
2014-02-10 14:55:18 -06:00
if ( $FH -> open ( $Path , ZipArchive :: CREATE ) !== TRUE ) {
2014-02-07 16:35:31 -06:00
$this -> Form -> AddError ( 'Unable to create archive: ' . $FH -> getStatusString ());
2014-02-07 16:03:50 -06:00
return FALSE ;
}
2014-02-10 14:55:18 -06:00
2014-02-07 16:35:31 -06:00
// Add actions
2014-02-10 16:28:50 -06:00
if ( $Include [ 'Action' ]) {
2014-02-10 15:18:28 -06:00
$Info -> Action = 'actions.yaga' ;
2014-02-07 16:35:31 -06:00
$Actions = Yaga :: ActionModel () -> Get ( 'Sort' , 'asc' );
2014-02-10 16:28:50 -06:00
$this -> SetData ( 'ActionCount' , count ( $Actions ));
2014-02-07 16:35:31 -06:00
$ActionData = serialize ( $Actions );
$FH -> addFromString ( 'actions.yaga' , $ActionData );
2014-02-10 14:55:18 -06:00
$Hashes [] = md5 ( $ActionData );
2014-02-07 16:35:31 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-07 16:35:31 -06:00
// Add ranks and associated image
2014-02-10 16:28:50 -06:00
if ( $Include [ 'Rank' ]) {
2014-02-10 15:18:28 -06:00
$Info -> Rank = 'ranks.yaga' ;
2014-02-07 16:35:31 -06:00
$Ranks = Yaga :: RankModel () -> Get ( 'Level' , 'asc' );
2014-02-10 16:28:50 -06:00
$this -> SetData ( 'RankCount' , count ( $Ranks ));
2014-02-07 16:35:31 -06:00
$RankData = serialize ( $Ranks );
$FH -> addFromString ( 'ranks.yaga' , $RankData );
array_push ( $Images , C ( 'Yaga.Ranks.Photo' ), NULL );
2014-02-10 14:55:18 -06:00
$Hashes [] = md5 ( $RankData );
2014-02-07 16:35:31 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-07 16:35:31 -06:00
// Add badges and associated images
2014-02-10 16:28:50 -06:00
if ( $Include [ 'Badge' ]) {
2014-02-10 15:18:28 -06:00
$Info -> Badge = 'badges.yaga' ;
2014-02-07 16:35:31 -06:00
$Badges = Yaga :: BadgeModel () -> Get ();
2014-02-10 16:28:50 -06:00
$this -> SetData ( 'BadgeCount' , count ( $Badges ));
2014-02-07 16:35:31 -06:00
$BadgeData = serialize ( $Badges );
$FH -> addFromString ( 'badges.yaga' , $BadgeData );
2014-02-10 14:55:18 -06:00
$Hashes [] = md5 ( $BadgeData );
2014-02-07 16:35:31 -06:00
foreach ( $Badges as $Badge ) {
array_push ( $Images , $Badge -> Photo );
}
2014-02-07 16:03:50 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-07 16:35:31 -06:00
// Add in any images
2014-02-08 16:12:59 -06:00
$FilteredImages = array_filter ( $Images );
2014-02-10 16:28:50 -06:00
$ImageCount = count ( $FilteredImages );
$this -> SetData ( 'ImageCount' , $ImageCount );
if ( $ImageCount > 0 ) {
2014-02-08 16:12:59 -06:00
$FH -> addEmptyDir ( 'images' );
}
2014-02-10 14:55:18 -06:00
2014-02-08 16:12:59 -06:00
foreach ( $FilteredImages as $Image ) {
2014-02-10 14:55:18 -06:00
if ( $FH -> addFile ( PATH_UPLOADS . DS . $Image , 'images' . DS . $Image ) !== TRUE ) {
2014-02-08 16:12:59 -06:00
$this -> Form -> AddError ( 'Unable to add file: ' . $FH -> getStatusString ());
return FALSE ;
2014-02-07 16:03:50 -06:00
}
2014-02-10 14:55:18 -06:00
$Hashes [] = md5_file ( PATH_UPLOADS . DS . $Image );
2014-02-07 16:03:50 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-07 16:35:31 -06:00
// Save all the hashes
sort ( $Hashes );
$Info -> MD5 = md5 ( implode ( ',' , $Hashes ));
$Info -> EndDate = date ( 'Y-m-d H:i:s' );
2014-02-10 14:55:18 -06:00
2014-02-07 14:05:13 -06:00
$EndTime = microtime ( TRUE );
$TotalTime = $EndTime - $StartTime ;
$m = floor ( $TotalTime / 60 );
$s = $TotalTime - ( $m * 60 );
2014-02-07 16:35:31 -06:00
$Info -> ElapsedTime = sprintf ( '%02d:%02.2f' , $m , $s );
2014-02-10 14:55:18 -06:00
2014-02-07 16:35:31 -06:00
$FH -> setArchiveComment ( serialize ( $Info ));
2014-02-07 16:03:50 -06:00
if ( $FH -> close ()) {
2014-02-08 16:12:59 -06:00
return $Path ;
2014-02-07 14:05:13 -06:00
}
else {
2014-02-07 16:03:50 -06:00
$this -> Form -> AddError ( 'Unable to save archive: ' . $FH -> getStatusString ());
return FALSE ;
2014-02-07 14:05:13 -06:00
}
2014-02-06 14:44:21 -06:00
}
2014-02-10 14:55:18 -06:00
2014-02-10 15:18:28 -06:00
/**
* Extract the transport file and validate
2014-02-10 16:28:50 -06:00
*
2014-02-10 15:18:28 -06:00
* @ param string The transport file path
* @ return boolean Whether or not the transport file was extracted successfully
*/
2014-02-10 14:55:18 -06:00
protected function _ExtractZip ( $Filename ) {
if ( ! file_exists ( $Filename )) {
return FALSE ;
// File does not exist
}
$ZipFile = new ZipArchive ();
$Result = $ZipFile -> open ( $Filename );
if ( $Result !== TRUE ) {
return FALSE ;
// Unable to open file
}
// Get the metadata from the comment
$Comment = $ZipFile -> comment ;
$MetaData = unserialize ( $Comment );
2014-02-10 16:28:50 -06:00
2014-02-10 14:55:18 -06:00
$Result = $ZipFile -> extractTo ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' );
if ( $Result !== TRUE ) {
return FALSE ;
// Unable to extract file
}
$ZipFile -> close ();
// Validate checksum
if ( $this -> _ValidateChecksum ( $MetaData ) === TRUE ) {
return $MetaData ;
}
else {
return FALSE ;
// Invalid checksum
}
}
2014-02-10 16:28:50 -06:00
/**
* Dumps the db tables , inserts data , and copies files on over
* @ param stdClass The info object read in from the archive
* @ param array Which tables should be overwritten
*/
protected function _ImportData ( $Info , $Include ) {
foreach ( $Include as $Key => $Value ) {
if ( $Value ) {
$Data = unserialize ( file_get_contents ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $Info -> $Key ));
Gdn :: SQL () -> EmptyTable ( $Key );
$ModelName = $Key . 'Model' ;
$Model = Yaga :: $ModelName ();
foreach ( $Data as $Datum ) {
$Model -> Insert (( array ) $Datum );
}
$this -> SetData ( $Key . 'Count' , $Model -> GetCount ());
}
}
if ( Gdn_FileSystem :: Copy ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . 'images' . DS , PATH_UPLOADS . DS ) === FALSE ) {
$this -> Form -> AddError ( 'Unable to copy image files.' );
}
}
2014-02-10 15:18:28 -06:00
/**
* Inspects the Yaga transport files and calculates a checksum
2014-02-10 16:28:50 -06:00
*
2014-02-10 15:18:28 -06:00
* @ param stdClass The metadata object read in from the transport file
* @ return boolean Whether or not the checksum is valid
*/
2014-02-10 14:55:18 -06:00
protected function _ValidateChecksum ( $MetaData ) {
$Hashes = array ();
// Hash the data files
if ( property_exists ( $MetaData , 'Actions' )) {
$Hashes [] = md5_file ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData -> Actions );
}
2014-02-10 16:28:50 -06:00
2014-02-10 14:55:18 -06:00
if ( property_exists ( $MetaData , 'Badges' )) {
$Hashes [] = md5_file ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData -> Badges );
}
2014-02-10 16:28:50 -06:00
2014-02-10 14:55:18 -06:00
if ( property_exists ( $MetaData , 'Ranks' )) {
$Hashes [] = md5_file ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData -> Ranks );
}
2014-02-10 16:28:50 -06:00
2014-02-10 14:55:18 -06:00
// Hash the image files
2014-02-10 15:18:28 -06:00
$Files = $this -> _GetFiles ( PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . 'images' );
2014-02-10 16:28:50 -06:00
$this -> SetData ( 'ImageCount' , count ( $Files ));
2014-02-10 14:55:18 -06:00
foreach ( $Files as $File ) {
$Hashes [] = md5_file ( $File );
}
2014-02-10 16:28:50 -06:00
2014-02-10 14:55:18 -06:00
sort ( $Hashes );
$CalculatedChecksum = md5 ( implode ( ',' , $Hashes ));
if ( $CalculatedChecksum != $MetaData -> MD5 ) {
return FALSE ;
}
else {
return TRUE ;
}
}
/**
2014-02-10 15:18:28 -06:00
* Returns a list of all files in a directory , recursively ( Thanks @ businessdad )
2014-02-10 14:55:18 -06:00
*
2014-02-10 15:18:28 -06:00
* @ param string Directory The directory to scan for files
2014-02-10 14:55:18 -06:00
* @ result array A list of Files and , optionally , Directories .
*/
2014-02-10 15:18:28 -06:00
protected function _GetFiles ( $Directory ) {
2014-02-10 14:55:18 -06:00
$Files = array_diff ( scandir ( $Directory ), array ( '.' , '..' ));
$Result = array ();
foreach ( $Files as $File ) {
$FileName = $Directory . '/' . $File ;
if ( is_dir ( $FileName )) {
2014-02-10 15:18:28 -06:00
$Result = array_merge ( $Result , $this -> _GetFiles ( $FileName ));
2014-02-10 16:28:50 -06:00
continue ;
2014-02-10 14:55:18 -06:00
}
$Result [] = $FileName ;
}
return $Result ;
}
2014-02-06 14:44:21 -06:00
}