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