Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
69.28% |
627 / 905 |
|
20.00% |
4 / 20 |
CRAP | |
0.00% |
0 / 1 |
| SetsController | |
68.97% |
618 / 896 |
|
20.00% |
4 / 20 |
1581.85 | |
0.00% |
0 / 1 |
| sandbox | |
87.18% |
68 / 78 |
|
0.00% |
0 / 1 |
19.76 | |||
| create | |
0.00% |
0 / 50 |
|
0.00% |
0 / 1 |
42 | |||
| remove | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
56 | |||
| add | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
| index | |
100.00% |
73 / 73 |
|
100.00% |
1 / 1 |
15 | |||
| getDifficultyAndSolved | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
90 | |||
| getFirstUnsolvedSetConnectionId | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
4.01 | |||
| ui | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
42 | |||
| decodeQueryType | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
| addTsumego | |
86.21% |
25 / 29 |
|
0.00% |
0 / 1 |
6.09 | |||
| view | |
71.54% |
264 / 369 |
|
0.00% |
0 / 1 |
313.79 | |||
| updateAchievementConditions | |
84.00% |
21 / 25 |
|
0.00% |
0 / 1 |
5.10 | |||
| findUt | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
| getDifficultyColor | |
54.55% |
6 / 11 |
|
0.00% |
0 / 1 |
9.38 | |||
| getSizeColor | |
53.33% |
8 / 15 |
|
0.00% |
0 / 1 |
7.54 | |||
| getDateColor | |
23.53% |
4 / 17 |
|
0.00% |
0 / 1 |
36.62 | |||
| getSolvedColor | |
95.83% |
46 / 48 |
|
0.00% |
0 / 1 |
3 | |||
| getExistingRanksArray | |
100.00% |
50 / 50 |
|
100.00% |
1 / 1 |
1 | |||
| resetProgress | |
92.59% |
25 / 27 |
|
0.00% |
0 / 1 |
6.01 | |||
| changeCollectionSize | |
66.67% |
4 / 6 |
|
0.00% |
0 / 1 |
2.15 | |||
| 1 | <?php |
| 2 | |
| 3 | use function PHPUnit\Framework\isNull; |
| 4 | |
| 5 | App::uses('SgfParser', 'Utility'); |
| 6 | App::uses('TsumegoUtil', 'Utility'); |
| 7 | App::uses('AppException', 'Utility'); |
| 8 | App::uses('TsumegoButton', 'Utility'); |
| 9 | App::uses('TsumegoButtons', 'Utility'); |
| 10 | App::uses('SetsSelector', 'Utility'); |
| 11 | App::uses('AdminActivityLogger', 'Utility'); |
| 12 | App::uses('AdminActivityType', 'Model'); |
| 13 | App::uses('Progress', 'Utility'); |
| 14 | |
| 15 | class SetsController extends AppController |
| 16 | { |
| 17 | public $helpers = ['Html', 'Form']; |
| 18 | |
| 19 | public $title = 'tsumego-hero.com'; |
| 20 | |
| 21 | /** |
| 22 | * @return void |
| 23 | */ |
| 24 | public function sandbox() |
| 25 | { |
| 26 | $this->loadModel('User'); |
| 27 | $this->loadModel('Tsumego'); |
| 28 | $this->loadModel('TsumegoStatus'); |
| 29 | $this->loadModel('Favorite'); |
| 30 | $this->loadModel('SetConnection'); |
| 31 | |
| 32 | $this->set('_page', 'sandbox'); |
| 33 | $this->set('_title', 'Tsumego Hero - Collections'); |
| 34 | $setsNew = []; |
| 35 | |
| 36 | if (isset($this->params['url']['restore'])) |
| 37 | { |
| 38 | $restore = $this->Set->findById($this->params['url']['restore']); |
| 39 | if ($restore['Set']['public'] == -1) |
| 40 | { |
| 41 | $restore['Set']['public'] = 0; |
| 42 | $this->Set->save($restore); |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | $sets = $this->Set->find('all', [ |
| 47 | 'order' => ['Set.order'], |
| 48 | 'conditions' => ['public' => 0], |
| 49 | ]) ?: []; |
| 50 | $u = $this->User->findById(Auth::getUserID()); |
| 51 | |
| 52 | if (Auth::isLoggedIn()) |
| 53 | { |
| 54 | $uts = $this->TsumegoStatus->find('all', ['conditions' => ['user_id' => Auth::getUserID()]]); |
| 55 | if (!$uts) |
| 56 | $uts = []; |
| 57 | $tsumegoStatusMap = []; |
| 58 | $utsCount4 = count($uts); |
| 59 | for ($l = 0; $l < $utsCount4; $l++) |
| 60 | $tsumegoStatusMap[$uts[$l]['TsumegoStatus']['tsumego_id']] = $uts[$l]['TsumegoStatus']['status']; |
| 61 | } |
| 62 | $overallCounter = 0; |
| 63 | |
| 64 | $setsCount = count($sets); |
| 65 | for ($i = 0; $i < $setsCount; $i++) |
| 66 | { |
| 67 | $ts = TsumegoUtil::collectTsumegosFromSet($sets[$i]['Set']['id']); |
| 68 | $sets[$i]['Set']['anz'] = count($ts); |
| 69 | $counter = 0; |
| 70 | $elo = 0; |
| 71 | $tsCount3 = count($ts); |
| 72 | for ($k = 0; $k < $tsCount3; $k++) |
| 73 | { |
| 74 | |
| 75 | $elo += $ts[$k]['Tsumego']['rating']; |
| 76 | if (Auth::isLoggedIn()) |
| 77 | if (isset($tsumegoStatusMap[$ts[$k]['Tsumego']['id']])) |
| 78 | if ($tsumegoStatusMap[$ts[$k]['Tsumego']['id']] == 'S' || $tsumegoStatusMap[$ts[$k]['Tsumego']['id']] == 'W' || $tsumegoStatusMap[$ts[$k]['Tsumego']['id']] == 'C') |
| 79 | $counter++; |
| 80 | } |
| 81 | if (count($ts) > 0) |
| 82 | $elo = $elo / count($ts); |
| 83 | else |
| 84 | $elo = 0; |
| 85 | $date = new DateTime($sets[$i]['Set']['created']); |
| 86 | $month = date('F', strtotime($sets[$i]['Set']['created'])); |
| 87 | $setday = $date->format('d. '); |
| 88 | $setyear = $date->format('Y'); |
| 89 | if ($setday[0] == 0) |
| 90 | $setday = substr($setday, -3); |
| 91 | $sets[$i]['Set']['created'] = $date->format('Ymd'); |
| 92 | $sets[$i]['Set']['createdDisplay'] = $setday . $month . ' ' . $setyear; |
| 93 | $percent = 0; |
| 94 | if (count($ts) > 0) |
| 95 | $percent = $counter / count($ts) * 100; |
| 96 | $overallCounter += count($ts); |
| 97 | $sets[$i]['Set']['solvedNum'] = $counter; |
| 98 | $sets[$i]['Set']['solved'] = round($percent, 1); |
| 99 | $sets[$i]['Set']['solvedColor'] = $this->getSolvedColor($sets[$i]['Set']['solved']); |
| 100 | $sets[$i]['Set']['topicColor'] = $sets[$i]['Set']['color']; |
| 101 | $sets[$i]['Set']['difficultyColor'] = $this->getDifficultyColor($sets[$i]['Set']['difficulty']); |
| 102 | $sets[$i]['Set']['sizeColor'] = $this->getSizeColor($sets[$i]['Set']['anz']); |
| 103 | $sets[$i]['Set']['dateColor'] = $this->getDateColor($sets[$i]['Set']['created']); |
| 104 | |
| 105 | $sn = []; |
| 106 | $sn['id'] = $sets[$i]['Set']['id']; |
| 107 | $sn['name'] = $sets[$i]['Set']['title']; |
| 108 | $sn['amount'] = count($ts); |
| 109 | $sn['color'] = $sets[$i]['Set']['color']; |
| 110 | $sn['difficulty'] = Rating::getReadableRankFromRating($elo); |
| 111 | $sn['solved'] = round($percent, 1); |
| 112 | array_push($setsNew, $sn); |
| 113 | } |
| 114 | |
| 115 | $adminsList = $this->User->find('all', ['order' => 'id ASC', 'conditions' => ['isAdmin >' => 0]]) ?: []; |
| 116 | $admins = []; |
| 117 | foreach ($adminsList as $item) |
| 118 | $admins[] = $item['User']['name']; |
| 119 | |
| 120 | $this->set('admins', $admins); |
| 121 | $this->set('sets', $sets); |
| 122 | $this->set('setsNew', $setsNew); |
| 123 | $this->set('overallCounter', $overallCounter); |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * @param int|null $tid Tsumego ID |
| 128 | * @return void |
| 129 | */ |
| 130 | public function create($tid = null) |
| 131 | { |
| 132 | $this->loadModel('Tsumego'); |
| 133 | $this->loadModel('SetConnection'); |
| 134 | $redirect = false; |
| 135 | $t = []; |
| 136 | if (isset($this->data['Set'])) |
| 137 | { |
| 138 | $s = $this->Set->find('all', ['order' => 'id DESC']); |
| 139 | if (!$s) |
| 140 | $s = []; |
| 141 | $ss = []; |
| 142 | $sCount = count($s); |
| 143 | for ($i = 0; $i < $sCount; $i++) |
| 144 | if ($s[$i]['Set']['id'] < 6472) |
| 145 | array_push($ss, $s[$i]); |
| 146 | |
| 147 | $seed = str_split('abcdefghijklmnopqrstuvwxyz0123456789'); |
| 148 | shuffle($seed); |
| 149 | $rand = ''; |
| 150 | foreach (array_rand($seed, 6) as $k) |
| 151 | $rand .= $seed[$k]; |
| 152 | $hashName = '6473k339312/_' . $rand . '_' . $this->data['Set']['title']; |
| 153 | $hashName2 = '_' . $rand . '_' . $this->data['Set']['title']; |
| 154 | |
| 155 | $set = []; |
| 156 | $set['Set']['id'] = $ss[0]['Set']['id'] + 1; |
| 157 | $set['Set']['title'] = $this->data['Set']['title']; |
| 158 | $set['Set']['public'] = 0; |
| 159 | $set['Set']['image'] = 'b1.png'; |
| 160 | $set['Set']['difficulty'] = 4; |
| 161 | $set['Set']['author'] = 'various creators'; |
| 162 | $set['Set']['order'] = Constants::$DEFAULT_SET_ORDER; |
| 163 | |
| 164 | $this->Set->create(); |
| 165 | $this->Set->save($set); |
| 166 | |
| 167 | $tMax = $this->Tsumego->find('first', ['order' => 'id DESC']); |
| 168 | |
| 169 | $t = []; |
| 170 | $t['Tsumego']['id'] = $tMax['Tsumego']['id'] + 1; |
| 171 | $t['Tsumego']['difficulty'] = 4; |
| 172 | $t['Tsumego']['variance'] = 100; |
| 173 | $t['Tsumego']['description'] = 'b to kill'; |
| 174 | $t['Tsumego']['author'] = Auth::getUser()['name']; |
| 175 | $this->Tsumego->create(); |
| 176 | $this->Tsumego->save($t); |
| 177 | |
| 178 | $sc = []; |
| 179 | $sc['SetConnection']['set_id'] = $ss[0]['Set']['id'] + 1; |
| 180 | $sc['SetConnection']['tsumego_id'] = $tMax['Tsumego']['id'] + 1; |
| 181 | $sc['SetConnection']['num'] = 1; |
| 182 | $this->SetConnection->create(); |
| 183 | $this->SetConnection->save($sc); |
| 184 | |
| 185 | mkdir($hashName, 0777); |
| 186 | copy('6473k339312/__new/1.sgf', $hashName . '/1.sgf'); |
| 187 | |
| 188 | $redirect = true; |
| 189 | } |
| 190 | $this->set('t', $t); |
| 191 | $this->set('redirect', $redirect); |
| 192 | } |
| 193 | |
| 194 | /** |
| 195 | * @param int $id Set ID |
| 196 | * @return void |
| 197 | */ |
| 198 | public function remove($id) |
| 199 | { |
| 200 | $this->loadModel('Tsumego'); |
| 201 | $redirect = false; |
| 202 | |
| 203 | if (isset($this->data['Set'])) |
| 204 | if (strpos(';' . $this->data['Set']['hash'], '6473k339312-') == 1) |
| 205 | { |
| 206 | $setID = (int) str_replace('6473k339312-', '', $this->data['Set']['hash']); |
| 207 | |
| 208 | $s = $this->Set->findById($setID); |
| 209 | if ($s['Set']['public'] == 0 || $s['Set']['public'] == -1) |
| 210 | $this->Set->delete($setID); |
| 211 | $ts = TsumegoUtil::collectTsumegosFromSet($setID); |
| 212 | if (count($ts) < 50) |
| 213 | foreach ($ts as $item) |
| 214 | $this->Tsumego->delete($item['Tsumego']['id']); |
| 215 | $redirect = true; |
| 216 | } |
| 217 | //$this->set('t', $t); |
| 218 | $this->set('redirect', $redirect); |
| 219 | } |
| 220 | |
| 221 | /** |
| 222 | * @param int $tid Tsumego ID |
| 223 | * @return void |
| 224 | */ |
| 225 | public function add($tid) |
| 226 | { |
| 227 | $this->loadModel('Tsumego'); |
| 228 | |
| 229 | if (isset($this->data['Tsumego'])) |
| 230 | { |
| 231 | $t = []; |
| 232 | $t['Tsumego']['difficulty'] = $this->data['Tsumego']['difficulty']; |
| 233 | $t['Tsumego']['variance'] = $this->data['Tsumego']['variance']; |
| 234 | $t['Tsumego']['description'] = $this->data['Tsumego']['description']; |
| 235 | $this->Tsumego->save($t); |
| 236 | } |
| 237 | $ts = TsumegoUtil::collectTsumegosFromSet($tid); |
| 238 | $this->set('t', $ts[0]); |
| 239 | } |
| 240 | |
| 241 | public function index(): void |
| 242 | { |
| 243 | $this->loadModel('User'); |
| 244 | $this->loadModel('Tsumego'); |
| 245 | $this->loadModel('Favorite'); |
| 246 | $this->loadModel('AchievementCondition'); |
| 247 | $this->loadModel('TsumegoStatus'); |
| 248 | $this->loadModel('SetConnection'); |
| 249 | $this->loadModel('UserContribution'); |
| 250 | $this->set('_page', 'set'); |
| 251 | $this->set('_title', 'Tsumego Hero - Collections'); |
| 252 | |
| 253 | $setTiles = []; |
| 254 | $difficultyTiles = []; |
| 255 | $sets = []; |
| 256 | $tagList = []; |
| 257 | |
| 258 | $overallCounter = 0; |
| 259 | $problemsCount = 0; |
| 260 | $achievementUpdate = []; |
| 261 | |
| 262 | $tsumegoFilters = new TsumegoFilters(); |
| 263 | if ($tsumegoFilters->query == 'favorites') |
| 264 | $tsumegoFilters->setQuery('topics'); |
| 265 | |
| 266 | //setTiles |
| 267 | $setsRaw = $this->Set->find('all', [ |
| 268 | 'order' => ['Set.order', 'Set.id'], |
| 269 | 'conditions' => ['public' => 1], |
| 270 | ]) ?: []; |
| 271 | foreach ($setsRaw as $set) |
| 272 | $setTiles [] = $set['Set']['title']; |
| 273 | |
| 274 | //difficultyTiles |
| 275 | $dt = SetsController::getExistingRanksArray(); |
| 276 | foreach ($dt as $item) |
| 277 | $difficultyTiles[] = $item['rank']; |
| 278 | |
| 279 | //tagTiles |
| 280 | $tags = $this->Tag->find('all', [ |
| 281 | 'conditions' => [ |
| 282 | 'approved' => 1, |
| 283 | 'NOT' => ['name' => 'Tsumego'], |
| 284 | ], |
| 285 | ]); |
| 286 | |
| 287 | $tagTiles = []; |
| 288 | foreach ($tags as $tag) |
| 289 | $tagTiles[] = $tag['Tag']['name']; |
| 290 | |
| 291 | $setsSelector = new SetsSelector($tsumegoFilters); |
| 292 | |
| 293 | if (Auth::isLoggedIn()) |
| 294 | { |
| 295 | $aCondition = $this->AchievementCondition->find('first', [ |
| 296 | 'order' => 'value DESC', |
| 297 | 'conditions' => [ |
| 298 | 'user_id' => Auth::getUserID(), |
| 299 | 'category' => 'set']]) ?: []; |
| 300 | $aCondition['AchievementCondition']['category'] = 'set'; |
| 301 | $aCondition['AchievementCondition']['user_id'] = Auth::getUserID(); |
| 302 | $aCondition['AchievementCondition']['value'] = $overallCounter; |
| 303 | ClassRegistry::init('AchievementCondition')->save($aCondition); |
| 304 | $achievementChecker = new AchievementChecker(); |
| 305 | $achievementChecker->checkSetCompletedAchievements(); |
| 306 | $achievementChecker->finalize(); |
| 307 | $this->set('achievementUpdate', $achievementChecker->updated); |
| 308 | Auth::saveUser(); |
| 309 | } |
| 310 | |
| 311 | $ranksArray = SetsController::getExistingRanksArray(); |
| 312 | foreach ($ranksArray as &$rank) |
| 313 | { |
| 314 | $rank['id'] = $rank['rank']; |
| 315 | $rank['name'] = $rank['rank']; |
| 316 | } |
| 317 | |
| 318 | if ($tsumegoFilters->query == 'topics' && empty($tsumegoFilters->sets)) |
| 319 | $queryRefresh = false; |
| 320 | elseif ($tsumegoFilters->query == 'difficulty' && empty($tsumegoFilters->ranks)) |
| 321 | $queryRefresh = false; |
| 322 | elseif ($tsumegoFilters->query == 'tags' && empty($tsumegoFilters->tags)) |
| 323 | $queryRefresh = false; |
| 324 | else |
| 325 | $queryRefresh = true; |
| 326 | |
| 327 | $this->set('setsSelector', $setsSelector); |
| 328 | $this->set('ranksArray', $ranksArray); |
| 329 | $this->set('tagList', $tagList); |
| 330 | $this->set('setTiles', $setTiles); |
| 331 | $this->set('difficultyTiles', $difficultyTiles); |
| 332 | $this->set('tagTiles', $tagTiles); |
| 333 | $this->set('tsumegoFilters', $tsumegoFilters); |
| 334 | $this->set('hasPremium', Auth::hasPremium()); |
| 335 | $this->set('queryRefresh', $queryRefresh); |
| 336 | } |
| 337 | |
| 338 | public static function getDifficultyAndSolved($currentTagIds, $tsumegoStatusMap) |
| 339 | { |
| 340 | $tagTsumegoDifficulty = ClassRegistry::init('Tsumego')->find('all', ['conditions' => ['id' => $currentTagIds]]); |
| 341 | if (!$tagTsumegoDifficulty) |
| 342 | $tagTsumegoDifficulty = []; |
| 343 | $tagDifficultyResult = 0; |
| 344 | $statusCounter = 0; |
| 345 | $tagTsumegoDifficultyCount2 = count($tagTsumegoDifficulty); |
| 346 | for ($j = 0; $j < $tagTsumegoDifficultyCount2; $j++) |
| 347 | { |
| 348 | $tagDifficultyResult += $tagTsumegoDifficulty[$j]['Tsumego']['rating']; |
| 349 | if (isset($tsumegoStatusMap[$tagTsumegoDifficulty[$j]['Tsumego']['id']])) |
| 350 | if ($tsumegoStatusMap[$tagTsumegoDifficulty[$j]['Tsumego']['id']] == 'S' || $tsumegoStatusMap[$tagTsumegoDifficulty[$j]['Tsumego']['id']] == 'W' || $tsumegoStatusMap[$tagTsumegoDifficulty[$j]['Tsumego']['id']] == 'C') |
| 351 | $statusCounter++; |
| 352 | } |
| 353 | if (count($tagTsumegoDifficulty) > 0) |
| 354 | $tagDifficultyResult = $tagDifficultyResult / count($tagTsumegoDifficulty); |
| 355 | else |
| 356 | $tagDifficultyResult = 0; |
| 357 | $tagDifficultyResult = Rating::getReadableRankFromRating($tagDifficultyResult); |
| 358 | $return = []; |
| 359 | $return['difficulty'] = $tagDifficultyResult; |
| 360 | if (count($currentTagIds) > 0) |
| 361 | $return['solved'] = round($statusCounter / count($currentTagIds) * 100, 2); |
| 362 | else |
| 363 | $return['solved'] = 0; |
| 364 | |
| 365 | return $return; |
| 366 | } |
| 367 | |
| 368 | /** |
| 369 | * Gets the first unsolved set connection ID from a collection of tsumego buttons. |
| 370 | * Falls back to the first button if all are solved. |
| 371 | * |
| 372 | * @param TsumegoButtons $tsumegoButtons Iterator of TsumegoButton objects |
| 373 | * @return int|null The setConnectionID of the first unsolved button, or first button if all solved, or null if empty |
| 374 | */ |
| 375 | private function getFirstUnsolvedSetConnectionId($tsumegoButtons) |
| 376 | { |
| 377 | if (empty($tsumegoButtons)) |
| 378 | return null; |
| 379 | if ($firstUnsolvedButton = array_find((array) $tsumegoButtons, function ($tsumegoButton) { |
| 380 | return !TsumegoUtil::isSolvedStatus($tsumegoButton->status); |
| 381 | })) |
| 382 | return $firstUnsolvedButton->setConnectionID; |
| 383 | if ($firstRecentlyUnsolved = array_find((array) $tsumegoButtons, function ($tsumegoButton) { |
| 384 | return !TsumegoUtil::isRecentlySolved($tsumegoButton->status); |
| 385 | })) |
| 386 | return $firstRecentlyUnsolved->setConnectionID; |
| 387 | return $tsumegoButtons[0]->setConnectionID; |
| 388 | } |
| 389 | |
| 390 | /** |
| 391 | * @param int|null $id Set ID |
| 392 | * @return void |
| 393 | */ |
| 394 | public function ui($id = null) |
| 395 | { |
| 396 | $s = $this->Set->findById($id); |
| 397 | $redirect = false; |
| 398 | |
| 399 | if (isset($_FILES['adminUpload'])) |
| 400 | { |
| 401 | $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
| 402 | $randstring = 'set_'; |
| 403 | for ($i = 0; $i < 6; $i++) |
| 404 | $randstring .= $characters[rand(0, strlen($characters))]; |
| 405 | $filename = $randstring . '_' . $_FILES['adminUpload']['name']; |
| 406 | |
| 407 | $errors = []; |
| 408 | $file_name = $_FILES['adminUpload']['name']; |
| 409 | $file_size = $_FILES['adminUpload']['size']; |
| 410 | $file_tmp = $_FILES['adminUpload']['tmp_name']; |
| 411 | $file_type = $_FILES['adminUpload']['type']; |
| 412 | $array = explode('.', $_FILES['adminUpload']['name']); |
| 413 | $file_ext = strtolower(end($array)); |
| 414 | $extensions = ['png', 'jpg']; |
| 415 | |
| 416 | if (in_array($file_ext, $extensions) === false) |
| 417 | $errors[] = 'png/jpg allowed.'; |
| 418 | if ($file_size > 2097152) |
| 419 | $errors[] = 'The file is too large.'; |
| 420 | |
| 421 | if (empty($errors) == true) |
| 422 | { |
| 423 | $uploadfile = $_SERVER['DOCUMENT_ROOT'] . '/app/webroot/img/' . $filename; |
| 424 | move_uploaded_file($file_tmp, $uploadfile); |
| 425 | } |
| 426 | |
| 427 | $s['Set']['image'] = $filename; |
| 428 | $this->Set->save($s); |
| 429 | |
| 430 | $redirect = true; |
| 431 | } |
| 432 | |
| 433 | $this->set('id', $id); |
| 434 | $this->set('s', $s); |
| 435 | $this->set('redirect', $redirect); |
| 436 | } |
| 437 | |
| 438 | private function decodeQueryType($input) |
| 439 | { |
| 440 | if (is_numeric($input)) |
| 441 | return 'topics'; |
| 442 | if ($input == 'favorites') |
| 443 | return 'favorites'; |
| 444 | try |
| 445 | { |
| 446 | Rating::getRankFromReadableRank($input); |
| 447 | return 'difficulty'; |
| 448 | } |
| 449 | catch (Exception $e) |
| 450 | { |
| 451 | return 'tags'; |
| 452 | } |
| 453 | } |
| 454 | |
| 455 | public function addTsumego($setID) |
| 456 | { |
| 457 | if (!isset($this->data['Tsumego'])) |
| 458 | return; |
| 459 | |
| 460 | $tsumegoModel = ClassRegistry::init('Tsumego'); |
| 461 | |
| 462 | $tsumegoModel->getDataSource()->begin(); |
| 463 | |
| 464 | try |
| 465 | { |
| 466 | $tsumego = []; |
| 467 | $tsumego['num'] = $this->data['Tsumego']['num']; |
| 468 | $tsumego['difficulty'] = 40; |
| 469 | $tsumego['variance'] = $this->data['Tsumego']['variance']; |
| 470 | $tsumego['description'] = $this->data['Tsumego']['description']; |
| 471 | $tsumego['hint'] = $this->data['Tsumego']['hint']; |
| 472 | $tsumego['author'] = $this->data['Tsumego']['author']; |
| 473 | $tsumegoModel->create(); |
| 474 | $tsumegoModel->save($tsumego); |
| 475 | |
| 476 | $tsumego['id'] = $tsumegoModel->id; |
| 477 | $setConnection = []; |
| 478 | $setConnection['set_id'] = $setID; |
| 479 | $setConnection['tsumego_id'] = $tsumego['id']; |
| 480 | $setConnection['num'] = $this->data['Tsumego']['num']; |
| 481 | ClassRegistry::init('SetConnection')->create(); |
| 482 | ClassRegistry::init('SetConnection')->save($setConnection); |
| 483 | |
| 484 | // Save SGF if provided (either from textarea or file upload) |
| 485 | $fileUpload = isset($_FILES['adminUpload']) && $_FILES['adminUpload']['error'] === UPLOAD_ERR_OK ? $_FILES['adminUpload'] : null; |
| 486 | $sgfDataOrFile = $this->data['Tsumego']['sgf'] ?? $fileUpload; |
| 487 | |
| 488 | if ($sgfDataOrFile) |
| 489 | ClassRegistry::init('Sgf')->uploadSgf($sgfDataOrFile, $tsumego['id'], Auth::getUserID(), Auth::isAdmin()); |
| 490 | $tsumegoModel->getDataSource()->commit(); |
| 491 | } |
| 492 | catch (Exception $e) |
| 493 | { |
| 494 | $tsumegoModel->getDataSource()->rollback(); |
| 495 | throw $e; |
| 496 | } |
| 497 | return $this->redirect('/sets/view/' . $setID); |
| 498 | } |
| 499 | |
| 500 | public function view(string|int|null $id = null, int $partition = 1): void |
| 501 | { |
| 502 | // transferring from 1 indexed for humans to 0 indexed for us programmers. |
| 503 | $partition = $partition - 1; |
| 504 | $this->loadModel('Tsumego'); |
| 505 | $this->loadModel('TsumegoStatus'); |
| 506 | $this->loadModel('Favorite'); |
| 507 | $this->loadModel('AdminActivity'); |
| 508 | $this->loadModel('TsumegoAttempt'); |
| 509 | $this->loadModel('ProgressDeletion'); |
| 510 | $this->loadModel('Achievement'); |
| 511 | $this->loadModel('AchievementStatus'); |
| 512 | $this->loadModel('AchievementCondition'); |
| 513 | $this->loadModel('Sgf'); |
| 514 | $this->loadModel('SetConnection'); |
| 515 | $this->loadModel('Tag'); |
| 516 | $this->loadModel('Tag'); |
| 517 | $this->loadModel('User'); |
| 518 | $this->loadModel('UserContribution'); |
| 519 | |
| 520 | if (is_null($id)) |
| 521 | throw new AppException("Set to view not specified"); |
| 522 | |
| 523 | if ($id != '1') |
| 524 | $this->set('_page', 'set'); |
| 525 | else |
| 526 | $this->set('_page', 'favs'); |
| 527 | $tsIds = []; |
| 528 | $refreshView = false; |
| 529 | $avgTime = 0; |
| 530 | $accuracy = 0; |
| 531 | $allVcActive = false; |
| 532 | $allVcInactive = false; |
| 533 | $allArActive = false; |
| 534 | $allArInactive = false; |
| 535 | $allPassActive = false; |
| 536 | $allPassInactive = false; |
| 537 | $pdCounter = 0; |
| 538 | $acS = null; |
| 539 | $acA = null; |
| 540 | |
| 541 | $tsumegoFilters = new TsumegoFilters(self::decodeQueryType($id)); |
| 542 | if (Auth::isLoggedIn()) |
| 543 | if (Auth::isAdmin()) |
| 544 | { |
| 545 | $aad = $this->AdminActivity->find('first', ['order' => 'id DESC']); |
| 546 | // Check if last activity was a problem deletion - if so, actually delete it |
| 547 | if (isset($aad['AdminActivity']['type']) && $aad['AdminActivity']['type'] == AdminActivityType::PROBLEM_DELETE) |
| 548 | { |
| 549 | $scDelete = $this->SetConnection->find('first', ['order' => 'created DESC', 'conditions' => ['tsumego_id' => $aad['AdminActivity']['tsumego_id']]]); |
| 550 | $this->SetConnection->delete($scDelete['SetConnection']['id']); |
| 551 | $this->Tsumego->delete($aad['AdminActivity']['tsumego_id']); |
| 552 | } |
| 553 | } |
| 554 | if (isset($this->params['url']['add'])) |
| 555 | { |
| 556 | $overallCount = $this->Tsumego->find('first', ['order' => 'id DESC']); |
| 557 | $scTcount = $this->SetConnection->find('first', ['conditions' => ['set_id' => $id, 'num' => 1]]); |
| 558 | $setCount = $this->Tsumego->findById($scTcount['SetConnection']['tsumego_id']); |
| 559 | $setCount['Tsumego']['id'] = $overallCount['Tsumego']['id'] + 1; |
| 560 | $setCount['Tsumego']['set_id'] = $scTcount['SetConnection']['set_id']; |
| 561 | $setCount['Tsumego']['num'] += 1; |
| 562 | $setCount['Tsumego']['variance'] = 100; |
| 563 | if (Auth::getUserID() == 72) |
| 564 | $setCount['Tsumego']['author'] = 'Joschka Zimdars'; |
| 565 | elseif (Auth::getUserID() == 1206) |
| 566 | $setCount['Tsumego']['author'] = 'Innokentiy Zabirov'; |
| 567 | elseif (Auth::getUserID() == 3745) |
| 568 | $setCount['Tsumego']['author'] = 'Dennis Olevanov'; |
| 569 | else |
| 570 | $setCount['Tsumego']['author'] = Auth::getUser()['name']; |
| 571 | $this->Tsumego->create(); |
| 572 | $this->Tsumego->save($setCount); |
| 573 | $set = $this->Set->findById($id); |
| 574 | AdminActivityLogger::log(AdminActivityType::PROBLEM_ADD, $this->Tsumego->id, $id, null, $set['Set']['title']); |
| 575 | } |
| 576 | |
| 577 | Util::setCookie('lastSet', $id); |
| 578 | $tsumegoButtons = new TsumegoButtons($tsumegoFilters, null, $partition, $id); |
| 579 | $this->set('startingSetConnectionID', $this->getFirstUnsolvedSetConnectionId($tsumegoButtons)); |
| 580 | |
| 581 | if ($tsumegoFilters->query == 'difficulty') |
| 582 | { |
| 583 | $set = []; |
| 584 | $set['Set']['id'] = $id; |
| 585 | $set['Set']['title'] = $id . $tsumegoButtons->getPartitionTitleSuffix(); |
| 586 | $set['Set']['image'] = $id . 'Rank.png'; |
| 587 | $set['Set']['multiplier'] = 1; |
| 588 | $set['Set']['public'] = 1; |
| 589 | $elo = Rating::getRankMinimalRatingFromReadableRank($id); |
| 590 | $set['Set']['difficulty'] = $elo; |
| 591 | } |
| 592 | elseif ($tsumegoFilters->query == 'tags') |
| 593 | { |
| 594 | $set['Set']['id'] = $id; |
| 595 | $set['Set']['image'] = ''; |
| 596 | $set['Set']['multiplier'] = 1; |
| 597 | $set['Set']['public'] = 1; |
| 598 | $tagName = $this->Tag->findByName($id); |
| 599 | if ($tagName && isset($tagName['Tag']['description'])) |
| 600 | $set['Set']['description'] = $tagName['Tag']['description']; |
| 601 | $set['Set']['title'] = $id . $tsumegoButtons->getPartitionTitleSuffix(); |
| 602 | } |
| 603 | elseif ($tsumegoFilters->query == 'topics') |
| 604 | { |
| 605 | $set = ClassRegistry::init('Set')->findById($id); |
| 606 | $set['Set']['title'] = $set['Set']['title'] . $tsumegoButtons->getPartitionTitleSuffix(); |
| 607 | $allArActive = true; |
| 608 | $allArInactive = true; |
| 609 | $allPassActive = true; |
| 610 | $allPassInactive = true; |
| 611 | foreach ($tsumegoButtons as $tsumegoButton) |
| 612 | { |
| 613 | if (!$tsumegoButton->alternativeResponse) |
| 614 | $allArActive = false; |
| 615 | if (!$tsumegoButton->passEnabled) |
| 616 | $allPassActive = false; |
| 617 | } |
| 618 | foreach ($tsumegoButtons as $tsumegoButton) |
| 619 | $tsIds [] = $tsumegoButton->tsumegoID; |
| 620 | if ($set['Set']['public'] == 0) |
| 621 | $this->set('_page', 'sandbox'); |
| 622 | $this->set('isFav', false); |
| 623 | if (isset($this->data['Set']['title'])) |
| 624 | { |
| 625 | $this->Set->create(); |
| 626 | $changeSet = $set; |
| 627 | $changeSet['Set']['title'] = $this->data['Set']['title']; |
| 628 | $changeSet['Set']['title2'] = $this->data['Set']['title2']; |
| 629 | $this->set('data', $changeSet['Set']['title']); |
| 630 | $this->Set->save($changeSet, true); |
| 631 | $oldTitle = $set['Set']['title']; |
| 632 | $set = $this->Set->findById($id); |
| 633 | AdminActivityLogger::log(AdminActivityType::SET_TITLE_EDIT, null, $id, $oldTitle, $this->data['Set']['title']); |
| 634 | } |
| 635 | if (isset($this->data['Set']['description'])) |
| 636 | { |
| 637 | $this->Set->create(); |
| 638 | $changeSet = $set; |
| 639 | $changeSet['Set']['description'] = $this->data['Set']['description']; |
| 640 | $this->set('data', $changeSet['Set']['description']); |
| 641 | $this->Set->save($changeSet, true); |
| 642 | $oldDescription = $set['Set']['description']; |
| 643 | $set = $this->Set->findById($id); |
| 644 | AdminActivityLogger::log(AdminActivityType::SET_DESCRIPTION_EDIT, null, $id, $oldDescription, $this->data['Set']['description']); |
| 645 | } |
| 646 | if (isset($this->data['Set']['setDifficulty'])) |
| 647 | if ($this->data['Set']['setDifficulty'] != 1200 && $this->data['Set']['setDifficulty'] >= 900 && $this->data['Set']['setDifficulty'] <= 2900) |
| 648 | { |
| 649 | $setDifficultyTsumegoSet = TsumegoUtil::collectTsumegosFromSet($set['Set']['id']); |
| 650 | $setDifficulty = $this->data['Set']['setDifficulty']; |
| 651 | $setDifficultyTsumegoSetCount = count($setDifficultyTsumegoSet); |
| 652 | for ($i = 0; $i < $setDifficultyTsumegoSetCount; $i++) |
| 653 | { |
| 654 | $setDifficultyTsumegoSet[$i]['Tsumego']['rating'] |
| 655 | = Util::clampOptional( |
| 656 | $this->data['Set']['setDifficulty'], |
| 657 | $setDifficultyTsumegoSet[$i]['Tsumego']['minimum_rating'], |
| 658 | $setDifficultyTsumegoSet[$i]['Tsumego']['maximum_rating']); |
| 659 | $this->Tsumego->save($setDifficultyTsumegoSet[$i]); |
| 660 | } |
| 661 | AdminActivityLogger::log(AdminActivityType::SET_RATING_EDIT, null, $id); |
| 662 | } |
| 663 | if (isset($this->data['Set']['color'])) |
| 664 | { |
| 665 | $this->Set->create(); |
| 666 | $changeSet = $set; |
| 667 | $changeSet['Set']['color'] = $this->data['Set']['color']; |
| 668 | $this->set('data', $changeSet['Set']['color']); |
| 669 | $this->Set->save($changeSet, true); |
| 670 | $oldColor = $set['Set']['color']; |
| 671 | $set = $this->Set->findById($id); |
| 672 | AdminActivityLogger::log(AdminActivityType::SET_COLOR_EDIT, null, $id, $oldColor, $this->data['Set']['color']); |
| 673 | } |
| 674 | if (isset($this->data['Set']['order'])) |
| 675 | { |
| 676 | $this->Set->create(); |
| 677 | $changeSet = $set; |
| 678 | $changeSet['Set']['order'] = $this->data['Set']['order']; |
| 679 | $this->set('data', $changeSet['Set']['order']); |
| 680 | $this->Set->save($changeSet, true); |
| 681 | $oldOrder = $set['Set']['order']; |
| 682 | $set = $this->Set->findById($id); |
| 683 | AdminActivityLogger::log(AdminActivityType::SET_ORDER_EDIT, null, $id, $oldOrder, $this->data['Set']['order']); |
| 684 | } |
| 685 | if (isset($this->data['Settings'])) |
| 686 | { |
| 687 | if ($this->data['Settings']['r39'] == 'on') |
| 688 | { |
| 689 | foreach ($tsumegoButtons as $tsumegoButton) |
| 690 | { |
| 691 | $tsumego = ClassRegistry::init('Tsumego')->findById($tsumegoButton->tsumegoID); |
| 692 | $tsumego['alternative_response'] = true; |
| 693 | ClassRegistry::init('Tsumego')->save($tsumego); |
| 694 | } |
| 695 | $allArActive = true; |
| 696 | AdminActivityLogger::log(AdminActivityType::SET_ALTERNATIVE_RESPONSE, null, $id, null, '1'); |
| 697 | } |
| 698 | if ($this->data['Settings']['r39'] == 'off') |
| 699 | { |
| 700 | foreach ($tsumegoButtons as $tsumegoButton) |
| 701 | { |
| 702 | $tsumego = ClassRegistry::init('Tsumego')->findById($tsumegoButton->tsumegoID); |
| 703 | $tsumego['alternative_response'] = false; |
| 704 | ClassRegistry::init('Tsumego')->save($tsumego); |
| 705 | } |
| 706 | $allArInactive = true; |
| 707 | AdminActivityLogger::log(AdminActivityType::SET_ALTERNATIVE_RESPONSE, null, $id, null, '0'); |
| 708 | } |
| 709 | if ($this->data['Settings']['r43'] == 'yes') |
| 710 | { |
| 711 | foreach ($tsumegoButtons as $tsumegoButton) |
| 712 | { |
| 713 | $tsumego = ClassRegistry::init('Tsumego')->findById($tsumegoButton->tsumegoID); |
| 714 | $tsumego['pass'] = true; |
| 715 | ClassRegistry::init('Tsumego')->save($tsumego); |
| 716 | } |
| 717 | $allPassActive = true; |
| 718 | AdminActivityLogger::log(AdminActivityType::SET_PASS_MODE, null, $id, null, '1'); |
| 719 | } |
| 720 | if ($this->data['Settings']['r43'] == 'no') |
| 721 | { |
| 722 | foreach ($tsumegoButtons as $tsumegoButton) |
| 723 | { |
| 724 | $tsumego = ClassRegistry::init('Tsumego')->findById($tsumegoButton->tsumegoID); |
| 725 | $tsumego['pass'] = false; |
| 726 | ClassRegistry::init('Tsumego')->save($tsumego); |
| 727 | } |
| 728 | $allPassInactive = true; |
| 729 | AdminActivityLogger::log(AdminActivityType::SET_PASS_MODE, null, $id, null, '0'); |
| 730 | } |
| 731 | $this->set('formRedirect', true); |
| 732 | } |
| 733 | } |
| 734 | elseif ($tsumegoFilters->query = 'favorites') |
| 735 | { |
| 736 | $allUts = $this->TsumegoStatus->find('all', ['conditions' => ['user_id' => Auth::getUserID()]]) ?: []; |
| 737 | $idMap = []; |
| 738 | $statusMap = []; |
| 739 | $allUtsCount = count($allUts); |
| 740 | for ($i = 0; $i < $allUtsCount; $i++) |
| 741 | { |
| 742 | array_push($idMap, $allUts[$i]['TsumegoStatus']['tsumego_id']); |
| 743 | array_push($statusMap, $allUts[$i]['TsumegoStatus']['status']); |
| 744 | } |
| 745 | $fav = $this->Favorite->find('all', ['order' => 'created', 'direction' => 'DESC', 'conditions' => ['user_id' => Auth::getUserID()]]) ?: []; |
| 746 | if (!empty($fav)) |
| 747 | $this->set('achievementUpdate', new AchievementChecker()->checkSetAchievements(-1)->finalize()->updated); |
| 748 | $ts = []; |
| 749 | $difficultyCount = 0; |
| 750 | $solvedCount = 0; |
| 751 | $sizeCount = 0; |
| 752 | $favCount = count($fav); |
| 753 | for ($i = 0; $i < $favCount; $i++) |
| 754 | { |
| 755 | $tx = $this->Tsumego->find('first', ['conditions' => ['id' => $fav[$i]['Favorite']['tsumego_id']]]); |
| 756 | $difficultyCount += $tx['Tsumego']['difficulty']; |
| 757 | $utx = $this->findUt($fav[$i]['Favorite']['tsumego_id'], $allUts, $idMap); |
| 758 | if ($utx['TsumegoStatus']['status'] == 'S' || $utx['TsumegoStatus']['status'] == 'W' || $utx['TsumegoStatus']['status'] == 'C') |
| 759 | $solvedCount++; |
| 760 | $sizeCount++; |
| 761 | array_push($ts, $tx); |
| 762 | } |
| 763 | $allUtsCount = count($allUts); |
| 764 | for ($i = 0; $i < $allUtsCount; $i++) |
| 765 | { |
| 766 | $tsCount2 = count($ts); |
| 767 | for ($j = 0; $j < $tsCount2; $j++) |
| 768 | if ($allUts[$i]['TsumegoStatus']['tsumego_id'] == $ts[$j]['Tsumego']['id']) |
| 769 | $ts[$j]['Tsumego']['status'] = $allUts[$i]['TsumegoStatus']['status']; |
| 770 | } |
| 771 | $percent = Util::getPercent($solvedCount, $sizeCount); |
| 772 | $set = []; |
| 773 | $set['Set']['id'] = 1; |
| 774 | $set['Set']['title'] = 'Favorites'; |
| 775 | $set['Set']['title2'] = null; |
| 776 | $set['Set']['author'] = Auth::getUser()['name']; |
| 777 | $set['Set']['description'] = ''; |
| 778 | $set['Set']['image'] = 'fav'; |
| 779 | $set['Set']['order'] = 0; |
| 780 | $set['Set']['public'] = 1; |
| 781 | $set['Set']['created'] = 20180322; |
| 782 | $set['Set']['createdDisplay'] = '22. March 2018'; |
| 783 | $set['Set']['solvedNum'] = $sizeCount; |
| 784 | $set['Set']['solved'] = round($percent, 1); |
| 785 | $set['Set']['solvedColor'] = '#eee'; |
| 786 | $set['Set']['topicColor'] = '#eee'; |
| 787 | $set['Set']['difficultyColor'] = '#eee'; |
| 788 | $set['Set']['sizeColor'] = '#eee'; |
| 789 | $set['Set']['dateColor'] = '#eee'; |
| 790 | $this->set('isFav', true); |
| 791 | } |
| 792 | |
| 793 | if ($tsumegoButtons->description) |
| 794 | $set['Set']['description'] = $tsumegoButtons->description; |
| 795 | |
| 796 | $this->set('_title', $set['Set']['title'] . ' on Tsumego Hero'); |
| 797 | |
| 798 | if (Auth::isLoggedIn() && $tsumegoFilters->query == 'topics') |
| 799 | { |
| 800 | $ur = $this->TsumegoAttempt->find('all', [ |
| 801 | 'order' => 'created DESC', |
| 802 | 'conditions' => [ |
| 803 | 'user_id' => Auth::getUserID(), |
| 804 | 'tsumego_id' => $tsIds, |
| 805 | ], |
| 806 | ]) ?: []; |
| 807 | foreach ($tsumegoButtons as $tsumegoButton) |
| 808 | { |
| 809 | $urTemp = []; |
| 810 | $urSum = ''; |
| 811 | $tsumegoButton->seconds = 0; |
| 812 | $solvedSeconds = []; // Track all successful solve times to find minimum (best) |
| 813 | $urCount2 = count($ur); |
| 814 | for ($j = 0; $j < $urCount2; $j++) |
| 815 | if ($tsumegoButton->tsumegoID == $ur[$j]['TsumegoAttempt']['tsumego_id']) |
| 816 | { |
| 817 | array_push($urTemp, $ur[$j]); |
| 818 | if ($ur[$j]['TsumegoAttempt']['solved']) |
| 819 | $solvedSeconds[] = $ur[$j]['TsumegoAttempt']['seconds']; |
| 820 | |
| 821 | if (!$ur[$j]['TsumegoAttempt']['solved']) |
| 822 | { |
| 823 | $mis = $ur[$j]['TsumegoAttempt']['misplays']; |
| 824 | if ($mis == 0) |
| 825 | $mis = 1; |
| 826 | while ($mis > 0) |
| 827 | { |
| 828 | $urSum .= 'F'; |
| 829 | $mis--; |
| 830 | } |
| 831 | } |
| 832 | else |
| 833 | $urSum .= $ur[$j]['TsumegoAttempt']['solved']; |
| 834 | } |
| 835 | // Use minimum (best) solve time from all successful attempts |
| 836 | if (!empty($solvedSeconds)) |
| 837 | $tsumegoButton->seconds = min($solvedSeconds); |
| 838 | $tsumegoButton->performance = $urSum; |
| 839 | } |
| 840 | } |
| 841 | |
| 842 | $problemSolvedPercent = $tsumegoButtons->getProblemsSolvedPercent(); |
| 843 | $setRating = $tsumegoButtons->getProblemsRating(); |
| 844 | $this->set('setRating', $setRating); |
| 845 | |
| 846 | $this->set('problemSolvedPercent', $problemSolvedPercent); |
| 847 | |
| 848 | $scoring = true; |
| 849 | if (Auth::isLoggedIn() && $tsumegoFilters->query == 'topics') |
| 850 | { |
| 851 | $pd = $this->ProgressDeletion->find('all', [ |
| 852 | 'conditions' => [ |
| 853 | 'user_id' => Auth::getUserID(), |
| 854 | 'set_id' => $id]]) ?: []; |
| 855 | $pdCounter = 0; |
| 856 | $pdCount = count($pd); |
| 857 | for ($i = 0; $i < $pdCount; $i++) |
| 858 | { |
| 859 | $date = date_create($pd[$i]['ProgressDeletion']['created']); |
| 860 | $pd[$i]['ProgressDeletion']['d'] = $date->format('Y') . '-' . $date->format('m'); |
| 861 | if (date('Y-m') == $pd[$i]['ProgressDeletion']['d']) |
| 862 | $pdCounter++; |
| 863 | } |
| 864 | $urSecCounter = 0; |
| 865 | $urSecAvg = 0; |
| 866 | $pSsum = 0; |
| 867 | $pFsum = 0; |
| 868 | foreach ($tsumegoButtons as $tsumegoButton) |
| 869 | { |
| 870 | if ($tsumegoButton->seconds == 0) |
| 871 | if (TsumegoUtil::isSolvedStatus($tsumegoButton->status)) |
| 872 | $tss = 60; |
| 873 | else |
| 874 | $tss = 0; |
| 875 | else |
| 876 | $tss = $tsumegoButton->seconds; |
| 877 | $urSecAvg += $tss; |
| 878 | $urSecCounter++; |
| 879 | |
| 880 | if ($tsumegoButton->performance == '') |
| 881 | if (TsumegoUtil::isSolvedStatus($tsumegoButton->status)) |
| 882 | $tss2 = 'F'; |
| 883 | else |
| 884 | $tss2 = ''; |
| 885 | else |
| 886 | $tss2 = $tsumegoButton->performance; |
| 887 | $pS = substr_count($tss2, '1'); |
| 888 | $pF = substr_count($tss2, 'F'); |
| 889 | $pSsum += $pS; |
| 890 | $pFsum += $pF; |
| 891 | } |
| 892 | if ($urSecCounter == 0) |
| 893 | $avgTime = 60; |
| 894 | else |
| 895 | $avgTime = round($urSecAvg / $urSecCounter, 2); |
| 896 | if ($pSsum + $pFsum == 0) |
| 897 | $accuracy = 0; |
| 898 | else |
| 899 | $accuracy = round($pSsum / ($pSsum + $pFsum) * 100, 2); |
| 900 | $avgTime2 = $avgTime; |
| 901 | if ($problemSolvedPercent >= 100) |
| 902 | { |
| 903 | $achievementChecker = new AchievementChecker(); |
| 904 | if ($set['Set']['id'] != 210) |
| 905 | { |
| 906 | $this->updateAchievementConditions($set['Set']['id'], $avgTime2, $accuracy); |
| 907 | $achievementChecker->checkSetAchievements($set['Set']['id'], $setRating); |
| 908 | } |
| 909 | if ($id == 50 || $id == 52 || $id == 53 || $id == 54) |
| 910 | $achievementChecker->setAchievementSpecial('cc1'); |
| 911 | elseif ($id == 41 || $id == 49 || $id == 65 || $id == 66) |
| 912 | $achievementChecker->setAchievementSpecial('cc2'); |
| 913 | elseif ($id == 186 || $id == 187 || $id == 196 || $id == 203) |
| 914 | $achievementChecker->setAchievementSpecial('cc3'); |
| 915 | elseif ($id == 190 || $id == 193 || $id == 198) |
| 916 | $achievementChecker->setAchievementSpecial('1000w1'); |
| 917 | elseif ($id == 216) |
| 918 | $achievementChecker->setAchievementSpecial('1000w2'); |
| 919 | $achievementChecker->finalize(); |
| 920 | $this->set('achievementUpdate', $achievementChecker->updated); |
| 921 | } |
| 922 | |
| 923 | $acS = $this->AchievementCondition->find('first', [ |
| 924 | 'order' => 'value ASC', |
| 925 | 'conditions' => [ |
| 926 | 'set_id' => $id, |
| 927 | 'user_id' => Auth::getUserID(), |
| 928 | 'category' => 's']]); |
| 929 | $acA = $this->AchievementCondition->find('first', [ |
| 930 | 'order' => 'value DESC', |
| 931 | 'conditions' => [ |
| 932 | 'set_id' => $id, |
| 933 | 'user_id' => Auth::getUserID(), |
| 934 | 'category' => '%']]); |
| 935 | } |
| 936 | else |
| 937 | $scoring = false; |
| 938 | |
| 939 | $allTags = $this->Tag->find('all') ?: []; |
| 940 | $allTagsSorted = []; |
| 941 | $allTagsKeys = []; |
| 942 | $allTagsCount = count($allTags); |
| 943 | for ($i = 0; $i < $allTagsCount; $i++) |
| 944 | { |
| 945 | array_push($allTagsSorted, $allTags[$i]['Tag']['name']); |
| 946 | $allTagsKeys[$allTags[$i]['Tag']['name']] = $allTags[$i]; |
| 947 | } |
| 948 | sort($allTagsSorted); |
| 949 | $s2Tags = []; |
| 950 | $allTagsSortedCount = count($allTagsSorted); |
| 951 | for ($i = 0; $i < $allTagsSortedCount; $i++) |
| 952 | array_push($s2Tags, $allTagsKeys[$allTagsSorted[$i]]); |
| 953 | |
| 954 | $allTags = $s2Tags; |
| 955 | |
| 956 | if ($tsumegoFilters->query == 'topics') |
| 957 | { |
| 958 | $this->set('allVcActive', $allVcActive); |
| 959 | $this->set('allVcInactive', $allVcInactive); |
| 960 | $this->set('allArActive', $allArActive); |
| 961 | $this->set('allArInactive', $allArInactive); |
| 962 | $this->set('allPassActive', $allPassActive); |
| 963 | $this->set('allPassInactive', $allPassInactive); |
| 964 | $this->set('pdCounter', $pdCounter); |
| 965 | $this->set('acS', $acS); |
| 966 | $this->set('acA', $acA); |
| 967 | } |
| 968 | |
| 969 | $this->set('tsumegoFilters', $tsumegoFilters); |
| 970 | $this->set('allTags', $allTags); |
| 971 | $this->set('tsumegoButtons', $tsumegoButtons); |
| 972 | $this->set('set', $set); |
| 973 | $this->set('refreshView', $refreshView); |
| 974 | $this->set('avgTime', $avgTime); |
| 975 | $this->set('accuracy', $accuracy); |
| 976 | $this->set('scoring', $scoring); |
| 977 | $this->set('partition', $partition); |
| 978 | } |
| 979 | |
| 980 | /** |
| 981 | * @param int $sid Set ID |
| 982 | * @param float $avgTime Average time |
| 983 | * @param float $accuracy Accuracy percentage |
| 984 | * @return void |
| 985 | */ |
| 986 | public function updateAchievementConditions($sid, $avgTime, $accuracy) |
| 987 | { |
| 988 | $uid = Auth::getUserID(); |
| 989 | $acS = $this->AchievementCondition->find('first', ['order' => 'value ASC', 'conditions' => ['set_id' => $sid, 'user_id' => $uid, 'category' => 's']]); |
| 990 | $acA = $this->AchievementCondition->find('first', ['order' => 'value DESC', 'conditions' => ['set_id' => $sid, 'user_id' => $uid, 'category' => '%']]); |
| 991 | |
| 992 | if ($acS == null) |
| 993 | { |
| 994 | $aCond = []; |
| 995 | $aCond['AchievementCondition']['user_id'] = $uid; |
| 996 | $aCond['AchievementCondition']['set_id'] = $sid; |
| 997 | $aCond['AchievementCondition']['value'] = $avgTime; |
| 998 | $aCond['AchievementCondition']['category'] = 's'; |
| 999 | $this->AchievementCondition->create(); |
| 1000 | $this->AchievementCondition->save($aCond); |
| 1001 | } |
| 1002 | elseif ($avgTime < $acS['AchievementCondition']['value']) |
| 1003 | { |
| 1004 | $acS['AchievementCondition']['value'] = $avgTime; |
| 1005 | $this->AchievementCondition->save($acS); |
| 1006 | } |
| 1007 | if ($acA == null) |
| 1008 | { |
| 1009 | $aCond = []; |
| 1010 | $aCond['AchievementCondition']['user_id'] = $uid; |
| 1011 | $aCond['AchievementCondition']['set_id'] = $sid; |
| 1012 | $aCond['AchievementCondition']['value'] = $accuracy; |
| 1013 | $aCond['AchievementCondition']['category'] = '%'; |
| 1014 | $this->AchievementCondition->create(); |
| 1015 | $this->AchievementCondition->save($aCond); |
| 1016 | } |
| 1017 | elseif ($accuracy > $acA['AchievementCondition']['value']) |
| 1018 | { |
| 1019 | $acA['AchievementCondition']['value'] = $accuracy; |
| 1020 | $this->AchievementCondition->save($acA); |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 1024 | private function findUt($id = null, $allUts = null, $map = null) |
| 1025 | { |
| 1026 | $currentUt = array_search($id, $map); |
| 1027 | $ut = $allUts[$currentUt]; |
| 1028 | if ($currentUt == 0) |
| 1029 | if ($id != $map[0]) |
| 1030 | $ut = null; |
| 1031 | |
| 1032 | return $ut; |
| 1033 | } |
| 1034 | |
| 1035 | private function getDifficultyColor($difficulty = null) |
| 1036 | { |
| 1037 | if ($difficulty == 1) |
| 1038 | return '#33cc33'; |
| 1039 | if ($difficulty == 2) |
| 1040 | return '#709533'; |
| 1041 | if ($difficulty == 3) |
| 1042 | return '#2e3370'; |
| 1043 | if ($difficulty == 4) |
| 1044 | return '#ac5d33'; |
| 1045 | if ($difficulty == 5) |
| 1046 | return '#e02e33'; |
| 1047 | |
| 1048 | return 'white'; |
| 1049 | } |
| 1050 | |
| 1051 | private function getSizeColor($size = null) |
| 1052 | { |
| 1053 | $colors = []; |
| 1054 | array_push($colors, '#cc6600'); |
| 1055 | array_push($colors, '#ac4e26'); |
| 1056 | array_push($colors, '#963e3e'); |
| 1057 | array_push($colors, '#802e58'); |
| 1058 | array_push($colors, '#60167d'); |
| 1059 | if ($size < 30) |
| 1060 | return $colors[0]; |
| 1061 | if ($size < 60) |
| 1062 | return $colors[1]; |
| 1063 | if ($size < 110) |
| 1064 | return $colors[2]; |
| 1065 | if ($size < 202) |
| 1066 | return $colors[3]; |
| 1067 | |
| 1068 | return $colors[4]; |
| 1069 | } |
| 1070 | |
| 1071 | private function getDateColor($date = null) |
| 1072 | { |
| 1073 | $current = '20180705'; |
| 1074 | $dist = $current - $date; |
| 1075 | |
| 1076 | if ($dist < 7) |
| 1077 | return '#0033cc'; |
| 1078 | if ($dist < 100) |
| 1079 | return '#0f33ad'; |
| 1080 | if ($dist < 150) |
| 1081 | return '#1f338f'; |
| 1082 | if ($dist < 200) |
| 1083 | return '#2e3370'; |
| 1084 | if ($dist < 300) |
| 1085 | return '#3d3352'; |
| 1086 | if ($dist < 400) |
| 1087 | return '#4c3333'; |
| 1088 | if ($dist < 500) |
| 1089 | return '#57331f'; |
| 1090 | |
| 1091 | return '#663300'; |
| 1092 | } |
| 1093 | |
| 1094 | private function getSolvedColor($percent = null) |
| 1095 | { |
| 1096 | $colors = []; |
| 1097 | |
| 1098 | array_push($colors, '#333333'); |
| 1099 | array_push($colors, '#2e3d47'); |
| 1100 | array_push($colors, '#2b4252'); |
| 1101 | array_push($colors, '#29475c'); |
| 1102 | array_push($colors, '#264c66'); |
| 1103 | array_push($colors, '#245270'); |
| 1104 | array_push($colors, '#21577a'); |
| 1105 | array_push($colors, '#1f5c85'); |
| 1106 | array_push($colors, '#1c618f'); |
| 1107 | array_push($colors, '#1a6699'); |
| 1108 | |
| 1109 | array_push($colors, '#176ba3'); |
| 1110 | array_push($colors, '#1470ad'); |
| 1111 | array_push($colors, '#1275b8'); |
| 1112 | array_push($colors, '#0f7ac2'); |
| 1113 | array_push($colors, '#0d80cc'); |
| 1114 | array_push($colors, '#0a85d6'); |
| 1115 | array_push($colors, '#088ae0'); |
| 1116 | array_push($colors, '#058feb'); |
| 1117 | array_push($colors, '#0394f5'); |
| 1118 | array_push($colors, '#0099ff'); |
| 1119 | |
| 1120 | array_push($colors, '#039cf8'); |
| 1121 | array_push($colors, '#069ef2'); |
| 1122 | array_push($colors, '#09a1eb'); |
| 1123 | array_push($colors, '#0ca4e4'); |
| 1124 | array_push($colors, '#10a6dd'); |
| 1125 | array_push($colors, '#13a9d6'); |
| 1126 | array_push($colors, '#16acd0'); |
| 1127 | array_push($colors, '#19afc9'); |
| 1128 | array_push($colors, '#1cb1c2'); |
| 1129 | array_push($colors, '#1fb4bc'); |
| 1130 | |
| 1131 | array_push($colors, '#22b7b5'); |
| 1132 | array_push($colors, '#25b9ae'); |
| 1133 | array_push($colors, '#28bca7'); |
| 1134 | array_push($colors, '#2bbfa0'); |
| 1135 | array_push($colors, '#2ec29a'); |
| 1136 | array_push($colors, '#32c493'); |
| 1137 | array_push($colors, '#35c78c'); |
| 1138 | array_push($colors, '#38ca86'); |
| 1139 | array_push($colors, '#3bcc7f'); |
| 1140 | array_push($colors, '#3ecf78'); |
| 1141 | $steps = 2.5; |
| 1142 | $colorsCount = count($colors); |
| 1143 | for ($i = 0; $i < $colorsCount; $i++) |
| 1144 | { |
| 1145 | if ($percent <= $steps) |
| 1146 | return $colors[$i]; |
| 1147 | $steps += 2.5; |
| 1148 | } |
| 1149 | |
| 1150 | return '#333333'; |
| 1151 | } |
| 1152 | |
| 1153 | public static function getExistingRanksArray() |
| 1154 | { |
| 1155 | $ranksArray = []; |
| 1156 | $ranksArray[0]['rank'] = '15k'; |
| 1157 | $ranksArray[1]['rank'] = '14k'; |
| 1158 | $ranksArray[2]['rank'] = '13k'; |
| 1159 | $ranksArray[3]['rank'] = '12k'; |
| 1160 | $ranksArray[4]['rank'] = '11k'; |
| 1161 | $ranksArray[5]['rank'] = '10k'; |
| 1162 | $ranksArray[6]['rank'] = '9k'; |
| 1163 | $ranksArray[7]['rank'] = '8k'; |
| 1164 | $ranksArray[8]['rank'] = '7k'; |
| 1165 | $ranksArray[9]['rank'] = '6k'; |
| 1166 | $ranksArray[10]['rank'] = '5k'; |
| 1167 | $ranksArray[11]['rank'] = '4k'; |
| 1168 | $ranksArray[12]['rank'] = '3k'; |
| 1169 | $ranksArray[13]['rank'] = '2k'; |
| 1170 | $ranksArray[14]['rank'] = '1k'; |
| 1171 | $ranksArray[15]['rank'] = '1d'; |
| 1172 | $ranksArray[16]['rank'] = '2d'; |
| 1173 | $ranksArray[17]['rank'] = '3d'; |
| 1174 | $ranksArray[18]['rank'] = '4d'; |
| 1175 | $ranksArray[19]['rank'] = '5d'; |
| 1176 | $ranksArray[20]['rank'] = '6d'; |
| 1177 | $ranksArray[21]['rank'] = '7d'; |
| 1178 | $ranksArray[22]['rank'] = '8d'; |
| 1179 | $ranksArray[23]['rank'] = '9d'; |
| 1180 | $ranksArray[0]['color'] = 'rgba(63, 201, 196, [o])'; |
| 1181 | $ranksArray[1]['color'] = 'rgba(63, 190, 201, [o])'; |
| 1182 | $ranksArray[2]['color'] = 'rgba(63, 173, 201, [o])'; |
| 1183 | $ranksArray[3]['color'] = 'rgba(63, 157, 201, [o])'; |
| 1184 | $ranksArray[4]['color'] = 'rgba(63, 141, 201, [o])'; |
| 1185 | $ranksArray[5]['color'] = 'rgba(88, 158, 244, [o])'; |
| 1186 | $ranksArray[6]['color'] = 'rgba(88, 140, 244, [o])'; |
| 1187 | $ranksArray[7]['color'] = 'rgba(88, 122, 244, [o])'; |
| 1188 | $ranksArray[8]['color'] = 'rgba(88, 103, 244, [o])'; |
| 1189 | $ranksArray[9]['color'] = 'rgba(90, 88, 244, [o])'; |
| 1190 | $ranksArray[10]['color'] = 'rgba(109, 88, 244, [o])'; |
| 1191 | $ranksArray[11]['color'] = 'rgba(127, 88, 244, [o])'; |
| 1192 | $ranksArray[12]['color'] = 'rgba(145, 88, 244, [o])'; |
| 1193 | $ranksArray[13]['color'] = 'rgba(163, 88, 244, [o])'; |
| 1194 | $ranksArray[14]['color'] = 'rgba(182, 88, 244, [o])'; |
| 1195 | $ranksArray[15]['color'] = 'rgba(200, 88, 244, [o])'; |
| 1196 | $ranksArray[16]['color'] = 'rgba(218, 88, 244, [o])'; |
| 1197 | $ranksArray[17]['color'] = 'rgba(236, 88, 244, [o])'; |
| 1198 | $ranksArray[18]['color'] = 'rgba(244, 88, 234, [o])'; |
| 1199 | $ranksArray[19]['color'] = 'rgba(244, 88, 187, [o])'; |
| 1200 | $ranksArray[20]['color'] = 'rgba(244, 88, 145, [o])'; |
| 1201 | $ranksArray[21]['color'] = 'rgba(244, 88, 127, [o])'; |
| 1202 | $ranksArray[22]['color'] = 'rgba(244, 88, 101, [o])'; |
| 1203 | $ranksArray[23]['color'] = 'rgba(244, 88, 88, [o])'; |
| 1204 | |
| 1205 | return $ranksArray; |
| 1206 | } |
| 1207 | |
| 1208 | public function resetProgress(int $setID, int $partition): mixed |
| 1209 | { |
| 1210 | if (!Auth::isLoggedIn()) |
| 1211 | return $this->redirect('/sets/view/' . $setID); |
| 1212 | |
| 1213 | if ($this->data['reset-check'] != 'reset') |
| 1214 | { |
| 1215 | CookieFlash::set('Reset check wasn\'t correctly typed', 'error'); |
| 1216 | return $this->redirect('/sets/view/' . $setID); |
| 1217 | } |
| 1218 | |
| 1219 | $partition = $partition - 1; |
| 1220 | |
| 1221 | $tsumegoFilters = new TsumegoFilters(); |
| 1222 | if ($tsumegoFilters->collectionSize != 200) |
| 1223 | { |
| 1224 | CookieFlash::set('Reset is only possible for collection size 200', 'error'); |
| 1225 | return $this->redirect('/sets/view/' . $setID); |
| 1226 | } |
| 1227 | $tsumegoFilters->query = 'topics'; |
| 1228 | $tsumegoButtons = new TsumegoButtons($tsumegoFilters, null, $partition, $setID); |
| 1229 | $tsumegoIDToClear = []; |
| 1230 | foreach ($tsumegoButtons as $tsumegoButton) |
| 1231 | $tsumegoIDToClear[] = $tsumegoButton->tsumegoID; |
| 1232 | |
| 1233 | $problemsInSet = Util::query(" |
| 1234 | SELECT |
| 1235 | COUNT(DISTINCT tsumego.id) AS total |
| 1236 | FROM tsumego |
| 1237 | JOIN set_connection ON set_connection.tsumego_id = tsumego.id AND set_connection.set_id = ?", [$setID])[0]["total"]; |
| 1238 | if (TsumegoStatus::getProblemsSolvedInSet($setID) < $problemsInSet * 0.5) |
| 1239 | return $this->redirect('sets/' . $setID); |
| 1240 | |
| 1241 | Util::query(" |
| 1242 | DELETE tsumego_status FROM tsumego_status |
| 1243 | WHERE tsumego_status.user_id = ? AND tsumego_status.tsumego_id IN(" . implode(',', $tsumegoIDToClear) . ")", [Auth::getUserID()]); |
| 1244 | $progresDeletion = []; |
| 1245 | $progresDeletion['user_id'] = Auth::getUserID(); |
| 1246 | $progresDeletion['set_id'] = $setID; |
| 1247 | ClassRegistry::init('ProgressDeletion')->create(); |
| 1248 | ClassRegistry::init('ProgressDeletion')->save($progresDeletion); |
| 1249 | return $this->redirect('/sets/view/' . $setID); |
| 1250 | } |
| 1251 | |
| 1252 | public function changeCollectionSize(): mixed |
| 1253 | { |
| 1254 | $collectionSize = $this->data['collection_size']; |
| 1255 | if (is_null($collectionSize)) |
| 1256 | { |
| 1257 | CookieFlash::set('Collection size to change not provided', 'error'); |
| 1258 | return $this->redirect('/sets'); |
| 1259 | } |
| 1260 | Preferences::set('collection_size', $this->data['collection_size']); |
| 1261 | return $this->redirect('/sets'); |
| 1262 | } |
| 1263 | } |