1: <?php if(!defined('APPLICATION')) exit();
2:
3:
4: 5: 6: 7: 8: 9:
10: class YagaController extends DashboardController {
11:
12: 13: 14: 15:
16: public $Uses = array('Form');
17:
18: 19: 20: 21: 22: 23:
24: public function Initialize() {
25: parent::Initialize();
26: $this->Application = 'Yaga';
27: Gdn_Theme::Section('Dashboard');
28: if($this->Menu) {
29: $this->Menu->HighlightRoute('/yaga');
30: }
31: $this->AddSideMenu('yaga/settings');
32:
33: $this->AddCssFile('yaga.css');
34: }
35:
36: 37: 38:
39: public function Index() {
40: $this->Settings();
41: }
42:
43: 44: 45:
46: public function Settings() {
47: $this->Permission('Garden.Settings.Manage');
48: $this->Title(T('Yaga.Settings'));
49:
50:
51: $ConfigModule = new ConfigurationModule($this);
52:
53: $ConfigModule->Initialize(array(
54: 'Yaga.Reactions.Enabled' => array(
55: 'LabelCode' => 'Use Reactions',
56: 'Control' => 'Checkbox'
57: ),
58: 'Yaga.Badges.Enabled' => array(
59: 'LabelCode' => 'Use Badges',
60: 'Control' => 'Checkbox'
61: ),
62: 'Yaga.Ranks.Enabled' => array(
63: 'LabelCode' => 'Use Ranks',
64: 'Control' => 'Checkbox'
65: ),
66: 'Yaga.LeaderBoard.Enabled' => array(
67: 'LabelCode' => 'Show leaderboard on activity page',
68: 'Control' => 'Checkbox'
69: ),
70: 'Yaga.LeaderBoard.Limit' => array(
71: 'LabelCode' => 'Maximum number of leaders to show',
72: 'Control' => 'Textbox',
73: 'Options' => array(
74: 'Size' => 45,
75: 'class' => 'SmallInput'
76: )
77: )
78: ));
79: $this->ConfigurationModule = $ConfigModule;
80:
81: $this->Render();
82: }
83:
84: 85: 86:
87: public function Import() {
88: $this->Title(T('Yaga.Import'));
89: $this->SetData('TransportType', 'Import');
90:
91: if(!class_exists('ZipArchive')) {
92: $this->Form->AddError(T('Yaga.Error.TransportRequirements'));
93: }
94:
95: if($this->Form->IsPostBack() == TRUE) {
96:
97: $Upload = new Gdn_Upload();
98: $TmpZip = $Upload->ValidateUpload('FileUpload', FALSE);
99:
100: $ZipFile = FALSE;
101: if($TmpZip) {
102:
103: $TargetFile = $Upload->GenerateTargetName(PATH_UPLOADS, 'zip');
104: $BaseName = pathinfo($TargetFile, PATHINFO_BASENAME);
105:
106:
107: $Parts = $Upload->SaveAs($TmpZip, $BaseName);
108: $ZipFile = PATH_UPLOADS . DS . $Parts['SaveName'];
109: $this->SetData('TransportPath', $ZipFile);
110: }
111:
112: $Include = $this->_FindIncludes();
113: if(count($Include)) {
114: $Info = $this->_ExtractZip($ZipFile);
115: $this->_ImportData($Info, $Include);
116: Gdn_FileSystem::RemoveFolder(PATH_UPLOADS . DS . 'import' . DS . 'yaga');
117: }
118: else {
119: $this->Form->AddError(T('Yaga.Error.Includes'));
120: }
121: }
122:
123: if($this->Form->ErrorCount() == 0 && $this->Form->IsPostBack()) {
124: $this->Render('transport-success');
125: }
126: else {
127: $this->Render();
128: }
129: }
130:
131: 132: 133:
134: public function Export() {
135: $this->Title(T('Yaga.Export'));
136: $this->SetData('TransportType', 'Export');
137:
138: if(!class_exists('ZipArchive')) {
139: $this->Form->AddError(T('Yaga.Error.TransportRequirements'));
140: }
141:
142: if($this->Form->IsPostBack()) {
143: $Include = $this->_FindIncludes();
144: if(count($Include)) {
145: $Filename = $this->_ExportData($Include);
146: $this->SetData('TransportPath', $Filename);
147: }
148: else {
149: $this->Form->AddError(T('Yaga.Error.Includes'));
150: }
151: }
152:
153: if($this->Form->ErrorCount() == 0 && $this->Form->IsPostBack()) {
154: $this->Render('transport-success');
155: }
156: else {
157: $this->Render();
158: }
159: }
160:
161: 162: 163: 164: 165: 166:
167: protected function _FindIncludes() {
168: $FormValues = $this->Form->FormValues();
169: $Sections = $FormValues['Checkboxes'];
170:
171:
172: $Include = array();
173: foreach($Sections as $Section) {
174: $Include[$Section] = $FormValues[$Section];
175: }
176: return $Include;
177: }
178:
179: 180: 181: 182: 183: 184: 185: 186:
187: protected function _ExportData($Include = array(), $Path = NULL) {
188: $StartTime = microtime(TRUE);
189: $Info = new stdClass();
190: $Info->Version = C('Yaga.Version', '?.?');
191: $Info->StartDate = date('Y-m-d H:i:s');
192:
193: if(is_null($Path)) {
194: $Path = PATH_UPLOADS . DS . 'export' . date('Y-m-d-His') . '.yaga.zip';
195: }
196: $FH = new ZipArchive();
197: $Images = array();
198: $Hashes = array();
199:
200: if($FH->open($Path, ZipArchive::CREATE) !== TRUE) {
201: $this->Form->AddError(sprintf(T('Yaga.Error.ArchiveCreate'), $FH->getStatusString()));
202: return FALSE;
203: }
204:
205:
206: $Info->Config = 'configs.yaga';
207: $Configs = Gdn::Config('Yaga', array());
208: unset($Configs['Version']);
209: $ConfigData = serialize($Configs);
210: $FH->addFromString('configs.yaga', $ConfigData);
211: $Hashes[] = md5($ConfigData);
212:
213:
214: if($Include['Action']) {
215: $Info->Action = 'actions.yaga';
216: $Actions = Yaga::ActionModel()->Get('Sort', 'asc');
217: $this->SetData('ActionCount', count($Actions));
218: $ActionData = serialize($Actions);
219: $FH->addFromString('actions.yaga', $ActionData);
220: $Hashes[] = md5($ActionData);
221: }
222:
223:
224: if($Include['Rank']) {
225: $Info->Rank = 'ranks.yaga';
226: $Ranks = Yaga::RankModel()->Get('Level', 'asc');
227: $this->SetData('RankCount', count($Ranks));
228: $RankData = serialize($Ranks);
229: $FH->addFromString('ranks.yaga', $RankData);
230: array_push($Images, C('Yaga.Ranks.Photo'), NULL);
231: $Hashes[] = md5($RankData);
232: }
233:
234:
235: if($Include['Badge']) {
236: $Info->Badge = 'badges.yaga';
237: $Badges = Yaga::BadgeModel()->Get();
238: $this->SetData('BadgeCount', count($Badges));
239: $BadgeData = serialize($Badges);
240: $FH->addFromString('badges.yaga', $BadgeData);
241: $Hashes[] = md5($BadgeData);
242: foreach($Badges as $Badge) {
243: array_push($Images, $Badge->Photo);
244: }
245: }
246:
247:
248: $FilteredImages = array_filter($Images);
249: $ImageCount = count($FilteredImages);
250: $this->SetData('ImageCount', $ImageCount);
251: if($ImageCount > 0) {
252: $FH->addEmptyDir('images');
253: }
254:
255: foreach($FilteredImages as $Image) {
256: if($FH->addFile(PATH_UPLOADS . DS . $Image, 'images' . DS . $Image) !== TRUE) {
257: $this->Form->AddError(sprintf(T('Yaga.Error.AddFile'), $FH->getStatusString()));
258: return FALSE;
259: }
260: $Hashes[] = md5_file(PATH_UPLOADS . DS . $Image);
261: }
262:
263:
264: sort($Hashes);
265: $Info->MD5 = md5(implode(',', $Hashes));
266: $Info->EndDate = date('Y-m-d H:i:s');
267:
268: $EndTime = microtime(TRUE);
269: $TotalTime = $EndTime - $StartTime;
270: $m = floor($TotalTime / 60);
271: $s = $TotalTime - ($m * 60);
272:
273: $Info->ElapsedTime = sprintf('%02d:%02.2f', $m, $s);
274:
275: $FH->setArchiveComment(serialize($Info));
276: if($FH->close()) {
277: return $Path;
278: }
279: else {
280: $this->Form->AddError(sprintf(T('Yaga.Error.ArchiveSave'), $FH->getStatusString()));
281: return FALSE;
282: }
283: }
284:
285: 286: 287: 288: 289: 290:
291: protected function ($Filename) {
292: if(!file_exists($Filename)) {
293: $this->Form->AddError(T('Yaga.Error.FileDNE'));
294: return FALSE;
295: }
296:
297: $ZipFile = new ZipArchive();
298: $Result = $ZipFile->open($Filename);
299: if($Result !== TRUE) {
300: $this->Form->AddError(T('Yaga.Error.ArchiveOpen'));
301: return FALSE;
302: }
303:
304:
305: $Comment = $ZipFile->comment;
306: $MetaData = unserialize($Comment);
307:
308: $Result = $ZipFile->extractTo(PATH_UPLOADS . DS . 'import' . DS . 'yaga');
309: if($Result !== TRUE) {
310: $this->Form->AddError(T('Yaga.Error.ArchiveExtract'));
311: return FALSE;
312: }
313:
314: $ZipFile->close();
315:
316:
317: if($this->_ValidateChecksum($MetaData) === TRUE) {
318: return $MetaData;
319: }
320: else {
321: $this->Form->AddError(T('Yaga.Error.ArchiveChecksum'));
322: return FALSE;
323: }
324: }
325:
326: 327: 328: 329: 330: 331: 332: 333: 334:
335: protected function _ImportData($Info, $Include) {
336: if(!$Info) {
337: return FALSE;
338: }
339:
340:
341: $Configs = unserialize(file_get_contents(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $Info->Config));
342: $Configurations = $this->_NestedToDotNotation($Configs, 'Yaga');
343: foreach($Configurations as $Name => $Value) {
344: SaveToConfig($Name, $Value);
345: }
346:
347:
348: foreach($Include as $Key => $Value) {
349: if($Value) {
350: $Data = unserialize(file_get_contents(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $Info->$Key));
351: Gdn::SQL()->EmptyTable($Key);
352: $ModelName = $Key . 'Model';
353: $Model = Yaga::$ModelName();
354: foreach($Data as $Datum) {
355: $Model->Insert((array)$Datum);
356: }
357: $this->SetData($Key . 'Count', $Model->GetCount());
358: }
359: }
360:
361:
362: if(Gdn_FileSystem::Copy(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . 'images' . DS, PATH_UPLOADS . DS) === FALSE) {
363: $this->Form->AddError(T('Yaga.Error.TransportCopy'));
364: }
365:
366: return TRUE;
367: }
368:
369: 370: 371: 372: 373: 374: 375: 376:
377: protected function _NestedToDotNotation($Configs, $Prefix = '') {
378: $ConfigStrings = array();
379:
380: foreach($Configs as $Name => $Value) {
381: if(is_array($Value)) {
382: $ConfigStrings = array_merge($ConfigStrings, $this->_NestedToDotNotation($Value, "$Prefix.$Name"));
383: }
384: else {
385: $ConfigStrings["$Prefix.$Name"] = $Value;
386: }
387: }
388:
389: return $ConfigStrings;
390: }
391:
392: 393: 394: 395: 396: 397:
398: protected function _ValidateChecksum($MetaData) {
399: $Hashes = array();
400:
401:
402: $Hashes[] = md5_file(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData->Config);
403:
404:
405: if(property_exists($MetaData, 'Action')) {
406: $Hashes[] = md5_file(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData->Action);
407: }
408:
409: if(property_exists($MetaData, 'Badge')) {
410: $Hashes[] = md5_file(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData->Badge);
411: }
412:
413: if(property_exists($MetaData, 'Rank')) {
414: $Hashes[] = md5_file(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . $MetaData->Rank);
415: }
416:
417:
418: $Files = $this->_GetFiles(PATH_UPLOADS . DS . 'import' . DS . 'yaga' . DS . 'images');
419: $this->SetData('ImageCount', count($Files));
420: foreach($Files as $File) {
421: $Hashes[] = md5_file($File);
422: }
423:
424: sort($Hashes);
425: $CalculatedChecksum = md5(implode(',', $Hashes));
426:
427: if($CalculatedChecksum != $MetaData->MD5) {
428: return FALSE;
429: }
430: else {
431: return TRUE;
432: }
433: }
434:
435: 436: 437: 438: 439: 440:
441: protected function _GetFiles($Directory) {
442: $Files = array_diff(scandir($Directory), array('.', '..'));
443: $Result = array();
444: foreach($Files as $File) {
445: $FileName = $Directory . '/' . $File;
446: if(is_dir($FileName)) {
447: $Result = array_merge($Result, $this->_GetFiles($FileName));
448: continue;
449: }
450: $Result[] = $FileName;
451: }
452: return $Result;
453: }
454:
455: }
456: