Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
77.72% covered (warning)
77.72%
307 / 395
20.00% covered (danger)
20.00%
4 / 20
CRAP
0.00% covered (danger)
0.00%
0 / 1
TsumegosController
77.14% covered (warning)
77.14%
297 / 385
20.00% covered (danger)
20.00%
4 / 20
405.05
0.00% covered (danger)
0.00%
0 / 1
 deduceRelevantSetConnection
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
4.07
 getMatchingSetConnectionOfOtherTsumego
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 tsumegoOrSetLink
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 play
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
6.17
 inArrayX
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 duplicatesearch
91.67% covered (success)
91.67%
22 / 24
0.00% covered (danger)
0.00%
0 / 1
2.00
 getTheIdForTheThing
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getStartingPlayer
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
4.18
 findUt
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 commentCoordinates
93.94% covered (success)
93.94%
62 / 66
0.00% covered (danger)
0.00%
0 / 1
31.21
 convertCoord
55.00% covered (warning)
55.00%
22 / 40
0.00% covered (danger)
0.00%
0 / 1
56.45
 convertCoord2
56.41% covered (warning)
56.41%
22 / 39
0.00% covered (danger)
0.00%
0 / 1
53.13
 edit
100.00% covered (success)
100.00%
53 / 53
100.00% covered (success)
100.00%
1 / 1
18
 mergeForm
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 mergeFinalForm
96.88% covered (success)
96.88%
31 / 32
0.00% covered (danger)
0.00%
0 / 1
7
 performMerge
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 setupSgf
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
3.05
 setupSgfStep2
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
4.47
 setupNewSgfStep2
87.50% covered (warning)
87.50%
21 / 24
0.00% covered (danger)
0.00%
0 / 1
5.05
 history
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
2.02
1<?php
2
3App::uses('SgfParser', 'Utility');
4App::uses('TsumegoUtil', 'Utility');
5App::uses('AdminActivityUtil', 'Utility');
6App::uses('TsumegoButton', 'Utility');
7App::uses('AppException', 'Utility');
8App::uses('CookieFlash', 'Utility');
9App::uses('TsumegoMerger', 'Utility');
10App::uses('SimilarSearchResultItem', 'Utility');
11App::uses('SimilarSearchLogic', 'Utility');
12require_once(__DIR__ . "/Component/Play.php");
13
14class TsumegosController extends AppController
15{
16    public $helpers = ['Html', 'Form'];
17
18    private function deduceRelevantSetConnection(array $setConnections): array
19    {
20        if (!isset($this->params->query['sid']))
21            return $setConnections[0];
22        foreach ($setConnections as $setConnection)
23            if ($setConnection['SetConnection']['set_id'] == $this->params->query['sid'])
24                return $setConnection;
25        throw new AppException("Problem doesn't exist in the specified set");
26    }
27
28    public static function getMatchingSetConnectionOfOtherTsumego(int $tsumegoID, int $currentSetID): ?int
29    {
30        if ($setConnections = ClassRegistry::init('SetConnection')->find('all', ['conditions' => ['tsumego_id' => $tsumegoID]]))
31            if ($result = array_find($setConnections, function (array $setConnection) use (&$currentSetID): bool {
32                return $setConnection['SetConnection']['set_id'] == $currentSetID;
33            }))
34                return $result['SetConnection']['id'];
35        return null;
36    }
37
38    public static function tsumegoOrSetLink($tsumegoFilters, ?int $setConnectionID, string $setID): string
39    {
40        if ($setConnectionID)
41            return '/' . $setConnectionID;
42        return '/sets/view/' . $setID; // edge of the set (last or first), so we return to the set
43    }
44
45    public function play($id = null, $setConnectionID = null)
46    {
47        if (Auth::isLoggedIn() && !Auth::isInLevelMode())
48        {
49            Auth::getUser()['mode'] = Constants::$LEVEL_MODE;
50            Auth::saveUser();
51        }
52
53        if ($setConnectionID)
54            return new Play(function ($name, $value) { $this->set($name, $value); })->play($setConnectionID, $this->params, $this->data);
55
56        if (!$id)
57            throw new AppException("Tsumego id not provided");
58
59        $setConnections = TsumegoUtil::getSetConnectionsWithTitles($id);
60        if (!$setConnections)
61            throw new AppException("Problem without any set connection"); // some redirect/nicer message ?
62        $setConnection = $this->deduceRelevantSetConnection($setConnections);
63        return new Play(function ($name, $value) { $this->set($name, $value); })->play($setConnection['SetConnection']['id'], $this->params, $this->data);
64    }
65
66    public static function inArrayX($x, $newArray)
67    {
68        $newArrayCount = count($newArray);
69
70        for ($i = 0; $i < $newArrayCount; $i++)
71            if ($x['TagConnection']['tag_id'] == $newArray[$i]['TagConnection']['tag_id'] && $x['TagConnection']['approved'] == 1)
72                return true;
73
74        return false;
75    }
76
77    public function duplicatesearch($setConnectionID): mixed
78    {
79        $this->loadModel('Sgf');
80        $this->loadModel('Set');
81
82        $setConnection = ClassRegistry::init('SetConnection')->findById($setConnectionID);
83        if (!$setConnection)
84        {
85            CookieFlash::set('Problem not found', 'error');
86            return $this->redirect('/sets');
87        }
88
89        $similarSearchLogic = new SimilarSearchLogic($setConnection['SetConnection']);
90        $similarSearchLogic->execute();
91
92        $this->set('result', $similarSearchLogic->result);
93        $tsumegoStatus = ClassRegistry::init('TsumegoStatus')->find('first', [
94            'conditions' => [
95                'user_id' => Auth::getUserID(),
96                'tsumego_id' => $similarSearchLogic->sourceTsumego['id']]])['TsumegoStatus'];
97        $this->set(
98            'sourceTsumegoButton',
99            new TsumegoButton(
100                $similarSearchLogic->sourceTsumego['id'],
101                $setConnectionID,
102                $similarSearchLogic->setConnection['num'],
103                $tsumegoStatus['status'],
104                $similarSearchLogic->sourceTsumego['rating']));
105        $this->set('sourceSetName', ClassRegistry::init('Set')->findById($setConnection['SetConnection']['set_id'])['Set']['title']);
106        $this->set('sourceMoveCount', $similarSearchLogic->sourceMoveCount);
107        return null;
108    }
109
110    public static function getTheIdForTheThing($num)
111    {
112        $t = [];
113        $s = ClassRegistry::init('Set')->find('all', ['order' => 'id ASC', 'conditions' => ['public' => 1]]) ?: [];
114        $sCount = count($s);
115
116        for ($i = 0; $i < $sCount; $i++)
117        {
118            $sc = ClassRegistry::init('SetConnection')->find('all', ['order' => 'tsumego_id ASC', 'conditions' => ['set_id' => $s[$i]['Set']['id']]]) ?: [];
119            $scCount = count($sc);
120
121            for ($j = 0; $j < $scCount; $j++)
122                array_push($t, $sc[$j]['SetConnection']['tsumego_id']);
123        }
124        if ($num >= count($t))
125            return -1;
126
127        return $t[$num];
128    }
129
130    public static function getStartingPlayer($sgf)
131    {
132        $bStart = strpos($sgf, ';B');
133        $wStart = strpos($sgf, ';W');
134        if ($wStart == 0)
135            return 0;
136        if ($bStart == 0)
137            return 1;
138        if ($bStart <= $wStart)
139            return 0;
140
141        return 1;
142    }
143
144    public static function findUt($id = null, $utsMap = null)
145    {
146        if (!isset($utsMap[$id]))
147            return null;
148        $ut = [];
149        $ut['TsumegoStatus']['tsumego_id'] = $id;
150        $ut['TsumegoStatus']['user_id'] = Auth::getUserID();
151        $ut['TsumegoStatus']['status'] = $utsMap[$id];
152        $ut['TsumegoStatus']['created'] = date('Y-m-d H:i:s');
153
154        return $ut;
155    }
156
157    public static function commentCoordinates($c = null, $counter = null, $noSyntax = null)
158    {
159        if (!is_string($c))
160            return [$c, ''];
161        $m = str_split($c);
162        $n = '';
163        $n2 = '';
164        $hasLink = false;
165        $mCount = count($m);
166
167        for ($i = 0; $i < $mCount; $i++)
168        {
169            if (isset($m[$i + 1]))
170                if (preg_match('/[a-tA-T]/', $m[$i]) && is_numeric($m[$i + 1]))
171                    if (!preg_match('/[a-tA-T]/', $m[$i - 1]) && !is_numeric($m[$i - 1]))
172                        if (is_numeric($m[$i + 2]))
173                        {
174                            if (!preg_match('/[a-tA-T]/', $m[$i + 3]) && !is_numeric($m[$i + 3]))
175                            {
176                                $n .= $m[$i] . $m[$i + 1] . $m[$i + 2] . ' ';
177                                $n2 .= $i . '/' . ($i + 2) . ' ';
178                            }
179                        }
180                        elseif (!preg_match('/[a-tA-T]/', $m[$i + 2]))
181                        {
182                            $n .= $m[$i] . $m[$i + 1] . ' ';
183                            $n2 .= $i . '/' . ($i + 1) . ' ';
184                        }
185
186            if ($m[$i] == '<' && $m[$i + 1] == '/' && $m[$i + 2] == 'a' && $m[$i + 3] == '>')
187                $hasLink = true;
188        }
189        if (substr($n, -1) == ' ')
190            $n = substr($n, 0, -1);
191        if (substr($n2, -1) == ' ')
192            $n2 = substr($n2, 0, -1);
193
194        if ($hasLink)
195            $n2 = [];
196        $coordForBesogo = [];
197
198        if (is_string($n2) && strlen($n2) > 1)
199        {
200            $n2x = explode(' ', $n2);
201            $fn = 1;
202            $n2xCount = count($n2x);
203            for ($i = $n2xCount - 1; $i >= 0; $i--)
204            {
205                $n2xx = explode('/', $n2x[$i]);
206                $a = substr($c, 0, (int) $n2xx[0]);
207                $cx = substr($c, (int) $n2xx[0], (int) $n2xx[1] - (int) $n2xx[0] + 1);
208                if ($noSyntax)
209                    $b = '<span class="go-coord" title="Hover to highlight on board" id="ccIn' . $counter . $fn . '" onmouseover="ccIn' . $counter . $fn . '(event)" onmouseout="ccOut' . $counter . $fn . '()">';
210                else
211                    $b = '<span class=\"go-coord\" title="Hover to highlight on board" id="ccIn' . $counter . $fn . '" onmouseover=\"ccIn' . $counter . $fn . '(event)\" onmouseout=\"ccOut' . $counter . $fn . '()\">';
212
213                $d = '</span>';
214                $e = substr($c, $n2xx[1] + 1, strlen($c) - 1);
215                $coordForBesogo[$i] = $cx;
216                $c = $a . $b . $cx . $d . $e;
217                $fn++;
218            }
219        }
220
221        $xx = explode(' ', $n);
222        $coord1 = 0;
223        $finalCoord = '';
224        $xxCount = count($xx);
225
226        for ($i = 0; $i < $xxCount; $i++)
227            if (strlen($xx[$i]) > 1)
228            {
229                $xxxx = [];
230                $xxx = str_split($xx[$i]);
231                $xxxCount = count($xxx);
232
233                for ($j = 0; $j < $xxxCount; $j++)
234                {
235                    if (preg_match('/[0-9]/', $xxx[$j]))
236                        array_push($xxxx, $xxx[$j]);
237                    if (preg_match('/[a-tA-T]/', $xxx[$j]))
238                        $coord1 = TsumegosController::convertCoord($xxx[$j]);
239                }
240                $coord2 = TsumegosController::convertCoord2(implode('', $xxxx));
241                if ($coord1 != -1 && $coord2 != -1)
242                    $finalCoord .= $coord1 . '-' . $coord2 . '-' . $coordForBesogo[$i] . ' ';
243            }
244        if (substr($finalCoord, -1) == ' ')
245            $finalCoord = substr($finalCoord, 0, -1);
246
247        $array = [];
248        array_push($array, $c);
249        array_push($array, $finalCoord);
250
251        return $array;
252    }
253
254    public static function convertCoord($l = null)
255    {
256        switch (strtolower($l))
257        {
258            case 'a':
259                return 0;
260            case 'b':
261                return 1;
262            case 'c':
263                return 2;
264            case 'd':
265                return 3;
266            case 'e':
267                return 4;
268            case 'f':
269                return 5;
270            case 'g':
271                return 6;
272            case 'h':
273                return 7;
274            case 'j':
275                return 8;
276            case 'k':
277                return 9;
278            case 'l':
279                return 10;
280            case 'm':
281                return 11;
282            case 'n':
283                return 12;
284            case 'o':
285                return 13;
286            case 'p':
287                return 14;
288            case 'q':
289                return 15;
290            case 'r':
291                return 16;
292            case 's':
293                return 17;
294            case 't':
295                return 18;
296        }
297
298        return 0;
299    }
300    public static function convertCoord2($n = null)
301    {
302        switch ($n)
303        {
304            case '0':
305                return 19;
306            case '1':
307                return 18;
308            case '2':
309                return 17;
310            case '3':
311                return 16;
312            case '4':
313                return 15;
314            case '5':
315                return 14;
316            case '6':
317                return 13;
318            case '7':
319                return 12;
320            case '8':
321                return 11;
322            case '9':
323                return 10;
324            case '10':
325                return 9;
326            case '11':
327                return 8;
328            case '12':
329                return 7;
330            case '13':
331                return 6;
332            case '14':
333                return 5;
334            case '15':
335                return 4;
336            case '16':
337                return 3;
338            case '17':
339                return 2;
340            case '18':
341                return 1;
342        }
343
344        return 0;
345    }
346
347    public function edit($tsumegoID)
348    {
349        if (!Auth::isAdmin())
350            return $this->redirect($this->data['redirect']);
351        $tsumego = ClassRegistry::init('Tsumego')->findById($tsumegoID);
352        if (!$tsumego)
353        {
354            CookieFlash::set("Tsumego with id=" . $tsumegoID . ' doesn\'t exist.', 'error');
355            return $this->redirect('/sets');
356        }
357        $tsumego = $tsumego['Tsumego'];
358
359        if ($this->data['delete'] == 'delete')
360        {
361            $tsumego['deleted'] = date('Y-m-d H:i:s');
362            ClassRegistry::init('Tsumego')->save($tsumego);
363            AdminActivityLogger::log(AdminActivityType::PROBLEM_DELETE, $tsumegoID);
364            return $this->redirect("/sets");
365        }
366
367        try
368        {
369            $rating = Rating::parseRatingOrReadableRank($this->data['rating']);
370        }
371        catch (RatingParseException $e)
372        {
373            CookieFlash::set("Rating parse error:" . $e->getMessage(), 'error');
374            return $this->redirect($this->data['redirect']);
375        }
376
377        $minimumRating = null;
378        if (!empty($this->data['minimum-rating']))
379        {
380            try
381            {
382                $minimumRating = Rating::parseRatingOrReadableRank($this->data['minimum-rating']);
383            }
384            catch (RatingParseException $e)
385            {
386                CookieFlash::set("Minimum rating parse error:" . $e->getMessage(), 'error');
387                return $this->redirect($this->data['redirect']);
388            }
389        }
390
391        $maximumRating = null;
392        if (!empty($this->data['maximum-rating']))
393        {
394            try
395            {
396                $maximumRating = Rating::parseRatingOrReadableRank($this->data['maximum-rating']);
397            }
398            catch (RatingParseException $e)
399            {
400                CookieFlash::set("Maximum rating parse error:" . $e->getMessage(), 'error');
401                return $this->redirect($this->data['redirect']);
402            }
403        }
404
405        if (!is_null($minimumRating)
406            && !is_null($maximumRating)
407            && $minimumRating > $maximumRating)
408        {
409            CookieFlash::set("Minimum rating can't be bigger than maximum", 'error');
410            return $this->redirect($this->data['redirect']);
411        }
412
413        if ($tsumego['description'] != $this->data['description'])
414        {
415            AdminActivityLogger::log(AdminActivityType::DESCRIPTION_EDIT, $tsumegoID, null, $tsumego['description'], $this->data['description']);
416            $tsumego['description'] = $this->data['description'];
417        }
418
419        if ($tsumego['hint'] != $this->data['hint'])
420        {
421            AdminActivityLogger::log(AdminActivityType::HINT_EDIT, $tsumegoID, null, $tsumego['hint'], $this->data['hint']);
422            $tsumego['hint'] = $this->data['hint'];
423        }
424        if ($tsumego['author'] != $this->data['author'])
425        {
426            AdminActivityLogger::log(AdminActivityType::AUTHOR_EDIT, $tsumegoID, null, $tsumego['author'], $this->data['author']);
427            $tsumego['author'] = $this->data['author'];
428        }
429        if ($tsumego['minimum_rating'] != $minimumRating)
430        {
431            AdminActivityLogger::log(AdminActivityType::MINIMUM_RATING_EDIT, $tsumegoID, null, Util::strOrNull($tsumego['minimum_rating']), Util::strOrNull($minimumRating));
432            $tsumego['minimum_rating'] = $minimumRating;
433        }
434
435        if ($tsumego['maximum_rating'] != $maximumRating)
436        {
437            AdminActivityLogger::log(AdminActivityType::MAXIMUM_RATING_EDIT, $tsumegoID, null, Util::strOrNull($tsumego['maximum_rating']), Util::strOrNull($maximumRating));
438            $tsumego['maximum_rating'] = $maximumRating;
439        }
440
441        if ($tsumego['rating'] != $rating)
442            AdminActivityLogger::log(AdminActivityType::RATING_EDIT, $tsumegoID, null, Util::strOrNull($tsumego['rating']), Util::strOrNull($rating));
443
444        $tsumego['rating'] = Util::clampOptional($rating, $minimumRating, $maximumRating);
445
446        ClassRegistry::init('Tsumego')->save($tsumego);
447        return $this->redirect($this->data['redirect']);
448    }
449
450    public function mergeForm(): mixed
451    {
452        if (!Auth::isAdmin())
453        {
454            CookieFlash::set('error', 'You are not authorized to access this page.');
455            return $this->redirect('/');
456        }
457        $this->set('_page', 'sandbox');
458        $this->set('_title', 'Merge Duplicates');
459        return null;
460    }
461
462    public function mergeFinalForm(): mixed
463    {
464        if (!Auth::isAdmin())
465            return $this->redirect('/');
466        $masterSetConnectionID = $this->request->data['master-id'];
467        $slaveSetConnectionID = $this->request->data['slave-id'];
468        $masterSetConnection = ClassRegistry::init('SetConnection')->findById($masterSetConnectionID);
469        if (!$masterSetConnection)
470        {
471            CookieFlash::set('Master set connection does not exist.', 'error');
472            $this->redirect('/tsumegos/mergeForm');
473        }
474        $masterSetConnection = $masterSetConnection['SetConnection'];
475
476        $slaveSetConnection = ClassRegistry::init('SetConnection')->findById($slaveSetConnectionID);
477        if (!$slaveSetConnection)
478        {
479            CookieFlash::set('Slave set connection does not exist.', 'error');
480            $this->redirect('/tsumegos/mergeForm');
481        }
482        $slaveSetConnection = $slaveSetConnection['SetConnection'];
483
484        if ($slaveSetConnection['tsumego_id'] == $masterSetConnection['tsumego_id'])
485        {
486            CookieFlash::set('These are already merged.', 'error');
487            $this->redirect('/tsumegos/mergeForm');
488        }
489        $masterSetConnectionBrothers = ClassRegistry::init('SetConnection')->find('all', ['conditions' => ['tsumego_id' => $masterSetConnection['tsumego_id']]]);
490        $slaveSetConnectionBrothers = ClassRegistry::init('SetConnection')->find('all', ['conditions' => ['tsumego_id' => $slaveSetConnection['tsumego_id']]]);
491        $masterTsumego = ClassRegistry::init('Tsumego')->findById($masterSetConnection['tsumego_id']);
492        $slaveTsumego = ClassRegistry::init('Tsumego')->findById($slaveSetConnection['tsumego_id']);
493
494        $masterSetConnectionBrothersButtons = [];
495        foreach ($masterSetConnectionBrothers as $masterSetConnectionBrother)
496            $masterSetConnectionBrothersButtons [] = TsumegoButton::createFromSetConnection($masterSetConnectionBrother['SetConnection']);
497        $this->set('masterTsumegoButtons', $masterSetConnectionBrothersButtons);
498        $this->set('masterTsumegoID', $masterSetConnection['tsumego_id']);
499
500        $slaveSetConnectionBrothersButtons = [];
501        foreach ($slaveSetConnectionBrothers as $slaveSetConnectionBrother)
502            $slaveSetConnectionBrothersButtons [] = TsumegoButton::createFromSetConnection($slaveSetConnectionBrother['SetConnection']);
503        $this->set('slaveTsumegoButtons', $slaveSetConnectionBrothersButtons);
504        $this->set('slaveTsumegoID', $slaveSetConnection['tsumego_id']);
505        return null;
506    }
507
508    public function performMerge()
509    {
510        $merger = new TsumegoMerger($this->request->data['master-tsumego-id'], $this->request->data['slave-tsumego-id']);
511        $flash = $merger->execute();
512        if ($flash)
513            CookieFlash::set($flash['message'], $flash['type']);
514        $this->redirect('/tsumegos/mergeForm');
515    }
516
517    public function setupSgf(): mixed
518    {
519        if (!Auth::isAdmin())
520        {
521            CookieFlash::set('No rights to call this', 'error');
522            return $this->redirect('/sets');
523        }
524
525        $sgf = ClassRegistry::init('Sgf')->find('first', ['conditions' => ['OR' => ['first_move_color' => null, 'correct_moves' => null]]]);
526        if (!$sgf)
527        {
528            CookieFlash::set('All sgfs converted', 'success');
529            return $this->redirect('/sets');
530        }
531        $sgf = $sgf['Sgf'];
532        $this->set('sgf', $sgf['sgf']);
533        $this->set('sgfID', $sgf['id']);
534        return null;
535    }
536
537    public function setupSgfStep2($sgfID, $firstMoveColor, $correctMoves = null)
538    {
539        if (!Auth::isAdmin())
540            return;
541        $sgf = ClassRegistry::init("Sgf")->findById($sgfID);
542        if (!$sgf)
543            return;
544        $sgf = $sgf['Sgf'];
545        if (empty($sgf['sgf']))
546        {
547            ClassRegistry::init("Sgf")->delete($sgfID);
548            return $this->redirect('/tsumegos/setupSgf');
549        }
550        $sgf['first_move_color'] = $firstMoveColor;
551        $sgf['correct_moves'] = $correctMoves ?? '';
552        ClassRegistry::init('Sgf')->save($sgf);
553        return $this->redirect('/tsumegos/setupSgf');
554    }
555
556    public function setupNewSgfStep2()
557    {
558        if (!Auth::isLoggedIn())
559            return;
560
561        $setConnectionID = $this->data["setConnectionID"];
562
563        $setConnection = ClassRegistry::init("SetConnection")->findById($setConnectionID);
564        if (!$setConnection)
565            return;
566        $tsumegoID = $setConnection['SetConnection']['tsumego_id'];
567
568        $sgfData = $this->data['sgf'];
569        $firstMoveColor = $this->data['firstMoveColor'];
570        $correctMoves = $this->data['correctMoves'];
571
572        $tsumego = ClassRegistry::init("Tsumego")->findById($tsumegoID);
573        if (!$tsumego)
574            return;
575
576        $tsumego = $tsumego['Tsumego'];
577        $sgf = [];
578        $sgf['sgf'] = $sgfData;
579        $sgf['user_id'] = Auth::getUserId();
580        $sgf['tsumego_id'] = $tsumego['id'];
581        $sgf['accepted'] = Auth::isAdmin() ? true : false;
582        $sgf['first_move_color'] = $firstMoveColor;
583        $sgf['correct_moves'] = $correctMoves;
584        ClassRegistry::init("Sgf")->create();
585        ClassRegistry::init("Sgf")->save($sgf);
586        return $this->redirect('/' . $setConnectionID);
587    }
588
589    public function history($setConnectionID)
590    {
591        $setConnection = ClassRegistry::init("SetConnection")->findById($setConnectionID);
592        if (!$setConnection)
593        {
594            CookieFlash::set('Specified set connection not found', 'error');
595            return $this->redirect('/sets');
596        }
597
598        $setConnection = $setConnection['SetConnection'];
599        $tsumegoID = $setConnection['tsumego_id'];
600
601        $dailyResults = Util::query("
602            SELECT
603                DATE(created) AS day,
604                MAX(tsumego_rating) AS Rating
605            FROM tsumego_attempt
606            WHERE tsumego_id = :tsumego_id AND tsumego_rating != 0
607            GROUP BY DATE(created)
608            ORDER BY day ASC
609        ", ['tsumego_id' => $tsumegoID]);
610        $this->set('dailyResults', $dailyResults);
611        $this->set('setConnection', $setConnection);
612        $this->set('urlParams', $this->params['url']);
613        $this->set('set', ClassRegistry::init("Set")->findById($setConnection['set_id'])['Set']);
614    }
615}