Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.77% covered (success)
95.77%
136 / 142
72.73% covered (warning)
72.73%
8 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
CronController
95.74% covered (success)
95.74%
135 / 141
72.73% covered (warning)
72.73%
8 / 11
39
0.00% covered (danger)
0.00%
0 / 1
 daily
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
 dailyUsersReset
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 dailyTsumegoStatusReset
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 dailyStalingSolvedTsumegoStatuses
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 deduceUserOfTheDay
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
6.40
 deduceQuoteToUse
83.33% covered (warning)
83.33%
10 / 12
0.00% covered (danger)
0.00%
0 / 1
6.17
 createDayRecord
100.00% covered (success)
100.00%
59 / 59
100.00% covered (success)
100.00%
1 / 1
14
 publish
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 publishSingle
90.00% covered (success)
90.00%
18 / 20
0.00% covered (danger)
0.00%
0 / 1
3.01
 updatePopularTags
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 updateSolvedCounts
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3App::uses('TsumegoUtil', 'Util');
4
5class CronController extends AppController
6{
7    /* Supposed to be ran daily to reset hearts and hero powers */
8    public function daily($secret)
9    {
10        if ($secret != CRON_SECRET)
11        {
12            $this->response->statusCode(403);
13            $this->response->body('Wrong cron secret.');
14            return $this->response;
15        }
16        $this->dailyTsumegoStatusReset();
17        $this->dailyStalingSolvedTsumegoStatuses();
18        self::createDayRecord();
19        self::publish();
20        $this->dailyUsersReset();
21        $this->updatePopularTags();
22        $this->updateSolvedCounts();
23
24        $this->response->statusCode(200);
25        return $this->response;
26    }
27
28    private function dailyUsersReset()
29    {
30        $query = 'UPDATE user SET';
31        $query .= ' used_refinement=0';
32        $query .= ',used_sprint=0';
33        $query .= ',used_rejuvenation=0';
34        $query .= ',used_potion=0';
35        $query .= ',used_intuition=0';
36        $query .= ',used_revelation=0';
37        $query .= ',damage=0';
38        $query .= ',daily_xp=0';
39        $query .= ',daily_solved=0';
40        $query .= ',readingTrial=30';
41        $query .= ',reuse4=0';
42        ClassRegistry::init('User')->query($query);
43    }
44
45    private function dailyTsumegoStatusReset()
46    {
47        ClassRegistry::init('TsumegoStatus')->query("UPDATE tsumego_status SET status='V' where status='F'");
48        ClassRegistry::init('TsumegoStatus')->query("UPDATE tsumego_status SET status='W' where status='X'");
49    }
50
51    private function dailyStalingSolvedTsumegoStatuses()
52    {
53        ClassRegistry::init('TsumegoStatus')->query("
54UPDATE tsumego_status
55SET status='W'
56WHERE
57    status='S' AND
58    tsumego_status.updated < '" . date('Y-m-d H:i:s', strtotime('-7 days')) . "'");
59    }
60
61    private static function deduceUserOfTheDay(): ?array
62    {
63        $lastDayRecords = ClassRegistry::init('DayRecord')->find('all', ['limit' => '7', 'order' => 'date DESC']) ?: [];
64
65        $excludedUsers = [];
66        foreach ($lastDayRecords as $lastDayRecord)
67            $excludedUsers[$lastDayRecord['DayRecord']['user_id']] = true;
68
69        $topUsers = ClassRegistry::init('User')->find('all', ['limit' => '8', 'order' => 'daily_xp DESC']) ?: [];
70        foreach ($topUsers as $user)
71            if (!isset($excludedUsers[$user['User']['id']]))
72                return $user;
73        return null;
74    }
75
76    private static function deduceQuoteToUse(): string
77    {
78        $latestDayRecords = ClassRegistry::init('DayRecord')->find('all', ['conditions' => ['date' => date('Y-m-d', strtotime('-10 days'))]]) ?: [];
79        $usedQuotes = [];
80        foreach ($latestDayRecords as $latestDayRecord)
81            $usedQuotes[$latestDayRecord['DayRecord']['quote']] = true;
82
83        $allQuotes = [];
84        for ($i = 1; $i < 13; $i++)
85            $allQuotes[] = sprintf('q%02d', $i);
86        shuffle($allQuotes);
87        foreach ($allQuotes as $quote)
88            if (!isset($usedQuotes[$quote]))
89                return $quote;
90        throw new Exception("Quote couldn't be generated");
91    }
92
93    private function createDayRecord()
94    {
95        $userOfTheDay = self::deduceUserOfTheDay();
96        $currentQuote = self::deduceQuoteToUse();
97        $today = date('Y-m-d');
98        $activity = $this->TsumegoAttempt->find('all', ['limit' => 40000, 'conditions' => ['created' => date('Y-m-d', strtotime('yesterday'))]]) ?: [];
99        $visitedProblems = count($activity);
100
101        //how many users today
102        $usersNum = [];
103        $activities = $this->User->find('all', ['limit' => 400, 'order' => 'created DESC']) ?: [];
104        foreach ($activities as $activity)
105        {
106            $a = new DateTime($activity['User']['created']);
107            if ($a->format('Y-m-d') == $today)
108                array_push($usersNum, $activity['User']);
109        }
110        $gemRand1 = rand(0, 2);
111        $gemRand2 = rand(0, 2);
112        $gemRand3 = rand(0, 2);
113
114        $arch1 = ClassRegistry::init('Achievement')->findById(111);
115        if ($gemRand1 == 0)
116            $arch1['Achievement']['description'] = 'Has a chance to trigger once a day on an easy ddk problem.';
117        elseif ($gemRand1 == 1)
118            $arch1['Achievement']['description'] = 'Has a chance to trigger once a day on a regular ddk problem.';
119        elseif ($gemRand1 == 2)
120            $arch1['Achievement']['description'] = 'Has a chance to trigger once a day on a difficult ddk problem.';
121        ClassRegistry::init('Achievement')->save($arch1);
122        $arch2 = ClassRegistry::init('Achievement')->findById(112);
123        if ($gemRand2 == 0)
124            $arch2['Achievement']['description'] = 'Has a chance to trigger once a day on an easy sdk problem.';
125        elseif ($gemRand2 == 1)
126            $arch2['Achievement']['description'] = 'Has a chance to trigger once a day on a regular sdk problem.';
127        elseif ($gemRand2 == 2)
128            $arch2['Achievement']['description'] = 'Has a chance to trigger once a day on a difficult sdk problem.';
129        ClassRegistry::init('Achievement')->save($arch2);
130        $arch3 = ClassRegistry::init('Achievement')->findById(113);
131        if ($gemRand3 == 0)
132            $arch3['Achievement']['description'] = 'Has a chance to trigger once a day on an easy dan problem.';
133        elseif ($gemRand3 == 1)
134            $arch3['Achievement']['description'] = 'Has a chance to trigger once a day on a regular dan problem.';
135        elseif ($gemRand3 == 2)
136            $arch3['Achievement']['description'] = 'Has a chance to trigger once a day on a difficult dan problem.';
137        ClassRegistry::init('Achievement')->save($arch3);
138
139        ClassRegistry::init('DayRecord')->create();
140        $dayRecord = [];
141        $dayRecord['DayRecord']['user_id'] = $userOfTheDay['User']['id'];
142        $dayRecord['DayRecord']['date'] = $today;
143        $dayRecord['DayRecord']['solved'] = $userOfTheDay['User']['daily_solved'];
144        $dayRecord['DayRecord']['quote'] = $currentQuote;
145        $dayRecord['DayRecord']['usercount'] = count($usersNum);
146        $dayRecord['DayRecord']['visitedproblems'] = $visitedProblems;
147        $dayRecord['DayRecord']['gems'] = $gemRand1 . '-' . $gemRand2 . '-' . $gemRand3;
148        $dayRecord['DayRecord']['gemCounter1'] = 0;
149        $dayRecord['DayRecord']['gemCounter2'] = 0;
150        $dayRecord['DayRecord']['gemCounter3'] = 0;
151        $dayRecord['DayRecord']['tsumego_count'] = TsumegoUtil::currentTsumegoCount();
152        ClassRegistry::init('DayRecord')->save($dayRecord);
153
154        ClassRegistry::init('AchievementCondition')->create();
155        $achievementCondition = [];
156        $achievementCondition['AchievementCondition']['user_id'] = $userOfTheDay['User']['id'];
157        $achievementCondition['AchievementCondition']['set_id'] = null;
158        $achievementCondition['AchievementCondition']['category'] = 'uotd';
159        $achievementCondition['AchievementCondition']['value'] = 1;
160        ClassRegistry::init('AchievementCondition')->save($achievementCondition);
161    }
162
163    public static function publish()
164    {
165        $date = date('Y-m-d', strtotime('today'));
166        $todaysSchedule = ClassRegistry::init('Schedule')->find('all', ['conditions' => ['date' => $date]]) ?: [];
167        foreach ($todaysSchedule as $item)
168        {
169            self::publishSingle($item['Schedule']['tsumego_id'], $item['Schedule']['set_id'], $item['Schedule']['date']);
170            $item['Schedule']['published'] = 1;
171            ClassRegistry::init('Schedule')->save($item);
172        }
173    }
174
175    protected static function publishSingle($tsumegoID = null, $to = null, $date = null): void
176    {
177        $tsumego = ClassRegistry::init('Tsumego')->findById($tsumegoID);
178        if (!$tsumego)
179            return;
180        $setConnection = ClassRegistry::init('SetConnection')->find('first', ['conditions' => ['tsumego_id' => $tsumegoID]]);
181        if (!$setConnection)
182            return;
183        $setConnection['SetConnection']['set_id'] = $to;
184        ClassRegistry::init('SetConnection')->save($setConnection);
185
186        // delete tsumego stats
187        $tsumego['Tsumego']['created'] = $date . ' 22:00:00';
188        $tsumego['Tsumego']['solved'] = 0;
189        $tsumego['Tsumego']['failed'] = 0;
190        $tsumego['Tsumego']['userWin'] = 0;
191        $tsumego['Tsumego']['userLoss'] = 0;
192        ClassRegistry::init('Tsumego')->save($tsumego);
193
194        // delete any status made on the tsumego when it was in the sandbox
195        ClassRegistry::init('TsumegoStatus')->deleteAll(['tsumego_id' => $tsumego['Tsumego']['id']]);
196
197        $x = [];
198        $x['PublishDate']['date'] = $date . ' 22:00:00';
199        $x['PublishDate']['tsumego_id'] = $tsumegoID;
200        ClassRegistry::init('PublishDate')->create();
201        ClassRegistry::init('PublishDate')->save($x);
202    }
203
204    private static function updatePopularTags()
205    {
206        ClassRegistry::init('Tag')->query("
207UPDATE tag
208JOIN (
209    SELECT tag_id
210    FROM tag_connection
211    GROUP BY tag_id
212    ORDER BY COUNT(*) DESC
213    LIMIT " . Tag::$POPULAR_COUNT . "
214) AS top_tags ON tag.id = top_tags.tag_id
215SET tag.popular = 1;");
216    }
217
218    private static function updateSolvedCounts()
219    {
220        Util::query("UPDATE user u
221LEFT JOIN (
222    SELECT user_id, COUNT(*) AS cnt
223    FROM tsumego_status
224    WHERE status IN ('S', 'W', 'C', 'X')
225    GROUP BY user_id
226) ts ON ts.user_id = u.id
227SET u.solved = COALESCE(ts.cnt, 0)");
228    }
229}