1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: wechsler |
5
|
|
|
* Date: 28/01/2017 |
6
|
|
|
* Time: 16:08 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Phase\TakeATicketBundle\Controller; |
10
|
|
|
|
11
|
|
|
use Phase\TakeATicket\Model\Instrument; |
12
|
|
|
use Phase\TakeATicket\Model\Platform; |
13
|
|
|
use Phase\TakeATicketBundle\Entity\User; |
14
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
15
|
|
|
use Symfony\Component\HttpFoundation\JsonResponse; |
16
|
|
|
use Symfony\Component\HttpFoundation\Request; |
17
|
|
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException; |
18
|
|
|
|
19
|
|
|
class AjaxController extends BaseController |
20
|
|
|
{ |
21
|
|
|
const MANAGER_REQUIRED_ROLE = 'ROLE_ADMIN'; |
22
|
|
|
const BAND_IDENTIFIER_BAND_NAME = 1; |
23
|
|
|
const BAND_IDENTIFIER_PERFORMERS = 2; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var int Whether to identify band by its name or a list of performers |
27
|
|
|
*/ |
28
|
|
|
protected $bandIdentifier = self::BAND_IDENTIFIER_PERFORMERS; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @return JsonResponse |
32
|
|
|
* |
33
|
|
|
* FIXME does not honour config.displayOptions.songInPreview - always shows track! |
34
|
|
|
*/ |
35
|
|
|
public function nextSongsAction() |
36
|
|
|
{ |
37
|
|
|
// $this->setJsonErrorHandler(); |
|
|
|
|
38
|
|
|
// $includePrivate = $this->app['security']->isGranted(self::MANAGER_REQUIRED_ROLE); |
|
|
|
|
39
|
|
|
$includePrivate = false; |
40
|
|
|
$next = $this->getDataStore()->fetchUpcomingTickets($includePrivate); |
41
|
|
|
if ($includePrivate) { |
42
|
|
|
$show = $next; |
43
|
|
|
} else { |
44
|
|
|
$show = []; |
45
|
|
|
foreach ($next as $k => $ticket) { |
46
|
|
|
$show[$k] = $ticket; |
47
|
|
|
if ($ticket['blocking']) { |
48
|
|
|
break; |
49
|
|
|
} |
50
|
|
|
} |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
return new JsonResponse($show); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
public function reloadPerformersAction() |
57
|
|
|
{ |
58
|
|
|
$performers = $this->getDataStore()->generatePerformerStats(); |
59
|
|
|
return new JsonResponse($performers); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
public function songSearchAction(Request $request) |
63
|
|
|
{ |
64
|
|
|
$searchString = $request->get('searchString'); |
65
|
|
|
$searchCount = 10; |
66
|
|
|
if ($request->get('searchCount')) { |
67
|
|
|
$searchCount = $request->get('searchCount'); |
68
|
|
|
} |
69
|
|
|
$dataStore = $this->getDataStore(); |
70
|
|
|
$songs = $dataStore->findSongsBySearchString($searchString, $searchCount); |
71
|
|
|
// Need to add sources, instruments |
72
|
|
|
$hydrated = []; |
73
|
|
|
|
74
|
|
|
foreach ($songs as $song) { |
75
|
|
|
$song = $dataStore->expandSongData($song); |
76
|
|
|
|
77
|
|
|
$hydrated[] = $song; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'ok', 'searchString' => $searchString, 'songs' => $hydrated]); |
81
|
|
|
|
82
|
|
|
return $jsonResponse; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
View Code Duplication |
public function useTicketAction(Request $request) |
|
|
|
|
86
|
|
|
{ |
87
|
|
|
// $this->setJsonErrorHandler(); |
|
|
|
|
88
|
|
|
|
89
|
|
|
$this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE); |
90
|
|
|
|
91
|
|
|
$id = $request->get('ticketId'); |
92
|
|
|
$res = $this->getDataStore()->markTicketUsedById($id); |
93
|
|
|
//FIXME fetch ticket with extra data |
94
|
|
|
if ($res) { |
95
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'ok']); |
96
|
|
|
} else { |
97
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'fail'], 500); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
return $jsonResponse; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
public function remotesRedirectAction() |
104
|
|
|
{ |
105
|
|
|
return new JsonResponse($this->getDataStore()->fetchSetting('remotesUrl')); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
public function saveTicketAction(Request $request) |
109
|
|
|
{ |
110
|
|
|
if (!$this->getDataStore()->fetchSetting('selfSubmission')) { |
111
|
|
|
$this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
$title = $request->get('title'); |
115
|
|
|
$songKey = $request->get('songId'); |
116
|
|
|
$band = $request->get('band') ?: []; // band must be array even if null (as passed by AJAX if no performers) |
117
|
|
|
$private = $request->get('private') === 'true' ? 1 : 0; |
118
|
|
|
$blocking = $request->get('blocking') === 'true' ? 1 : 0; |
119
|
|
|
$existingTicketId = $request->get('existingTicketId'); |
120
|
|
|
$submissionKey = trim($request->get('submissionKey')); |
121
|
|
|
$userId = null; |
122
|
|
|
|
123
|
|
|
if ($this->isGranted(self::MANAGER_REQUIRED_ROLE)) { |
124
|
|
|
$user = $this->getUser(); |
125
|
|
|
/** @var User $user */ |
126
|
|
|
$userId = $user->getId(); |
127
|
|
|
} else { |
128
|
|
|
$blocking = 0; |
129
|
|
|
$private = 1; |
130
|
|
|
if ($existingTicketId) { |
131
|
|
|
throw new AccessDeniedException('Cannot modify existing tickets'); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
// Check song is unused, check no performers have more than 3 upcoming songs |
135
|
|
|
// Ensure that name format is valid |
136
|
|
|
|
137
|
|
|
$dataErrors = []; |
138
|
|
|
$fixableError = false; |
139
|
|
|
|
140
|
|
|
$ticketsForSong = $this->getDataStore()->getQueueEntriesForSongId($songKey); |
141
|
|
|
|
142
|
|
|
if (count($ticketsForSong)) { |
143
|
|
|
$dataErrors[] = 'The song is already taken'; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
$performerStats = $this->getDataStore()->generatePerformerStats(); |
147
|
|
|
|
148
|
|
|
foreach ($band as $instrumentCandidates) { |
149
|
|
|
foreach ($instrumentCandidates as $candidate) { |
150
|
|
|
$candidate = trim($candidate); |
151
|
|
|
if ($candidate) { |
152
|
|
|
if (preg_match('/\w+ \w+/', $candidate)) { |
153
|
|
|
foreach ($performerStats as $performerStat) { |
154
|
|
|
if (($performerStat['songsPending'] > 2) && |
155
|
|
|
!strcasecmp($candidate, $performerStat['performerName']) |
156
|
|
|
) { |
157
|
|
|
$dataErrors[] = "$candidate has too many songs pending"; |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
} else { |
161
|
|
|
$dataErrors[] = "'$candidate' is not a valid name"; |
162
|
|
|
} |
163
|
|
|
} |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
if ($this->getDataStore()->fetchSetting('selfSubmissionKey') && |
168
|
|
|
strcasecmp($submissionKey, $this->getDataStore()->fetchSetting('selfSubmissionKey')) |
169
|
|
|
) { |
170
|
|
|
$dataErrors[] = 'Secret code wrong or missing'; |
171
|
|
|
$fixableError = 'E_BAD_SECRET'; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
if ($dataErrors) { |
|
|
|
|
175
|
|
|
$responseData = [ |
176
|
|
|
'status' => 'error', |
177
|
|
|
'message' => implode(', ', $dataErrors) |
178
|
|
|
]; |
179
|
|
|
if ($fixableError) { |
|
|
|
|
180
|
|
|
$responseData['error'] = $fixableError; // more than one error = faily death. |
181
|
|
|
} |
182
|
|
|
return new JsonResponse($responseData, 200); |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
$song = null; |
187
|
|
|
$songId = null; |
188
|
|
|
|
189
|
|
|
if (preg_match('/^[a-f0-9]{6}$/i', $songKey)) { |
190
|
|
|
$song = $this->getDataStore()->fetchSongByKey($songKey); |
191
|
|
|
} elseif (preg_match('/^\d+$/', $songKey)) { |
192
|
|
|
$song = $this->getDataStore()->fetchSongRowById($songKey); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
if ($song) { |
196
|
|
|
$songId = $song['id']; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
if (!$title) { |
200
|
|
|
$title = null; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
if ($existingTicketId) { |
204
|
|
|
$ticketId = $existingTicketId; |
205
|
|
|
} else { |
206
|
|
|
$ticketId = $this->getDataStore()->storeNewTicket($title, $songId, $userId); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
// update even new tickets so that we can add any new columns easily |
210
|
|
|
$updated = ['title' => $title, 'songId' => $songId, 'blocking' => $blocking, 'private' => $private]; |
211
|
|
|
|
212
|
|
|
$this->getDataStore()->updateTicketById( |
213
|
|
|
$ticketId, |
214
|
|
|
$updated |
215
|
|
|
); |
216
|
|
|
|
217
|
|
|
// think this is legacy? |
218
|
|
|
if ($this->bandIdentifier === self::BAND_IDENTIFIER_PERFORMERS) { |
219
|
|
|
$this->getDataStore()->storeBandToTicket($ticketId, $band); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
$ticket = $this->getDataStore()->fetchTicketById($ticketId); |
223
|
|
|
|
224
|
|
|
$ticket = $this->getDataStore()->expandTicketData($ticket); |
225
|
|
|
|
226
|
|
|
$responseData = [ |
227
|
|
|
'ticket' => $ticket, |
228
|
|
|
'performers' => $this->getDataStore()->generatePerformerStats(), |
229
|
|
|
'status' => 'ok' |
230
|
|
|
]; |
231
|
|
|
|
232
|
|
|
if ($ticketId) { |
233
|
|
|
$jsonResponse = new JsonResponse($responseData); |
234
|
|
|
} else { |
235
|
|
|
$jsonResponse = new JsonResponse($responseData, 500); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
return $jsonResponse; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
View Code Duplication |
public function deleteTicketAction(Request $request) |
|
|
|
|
242
|
|
|
{ |
243
|
|
|
$this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE); |
244
|
|
|
|
245
|
|
|
$id = $request->get('ticketId'); |
246
|
|
|
$res = $this->getDataStore()->deleteTicketById($id); |
247
|
|
|
if ($res) { |
248
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'ok']); |
249
|
|
|
} else { |
250
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'fail'], 500); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
return $jsonResponse; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Opaque hash that changes when new tickets are added (may cover further changes in future) |
258
|
|
|
* |
259
|
|
|
* @return JsonResponse |
260
|
|
|
* @throws \Doctrine\DBAL\DBALException |
261
|
|
|
*/ |
262
|
|
|
public function lastUpdateHashAction() |
263
|
|
|
{ |
264
|
|
|
return new JsonResponse(['hash' => count($this->getDataStore()->fetchUndeletedTickets())]); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
public function newTicketOrderAction(Request $request) |
268
|
|
|
{ |
269
|
|
|
$this->denyAccessUnlessGranted(self::MANAGER_REQUIRED_ROLE); |
270
|
|
|
|
271
|
|
|
$idOrder = $request->get('idOrder'); |
272
|
|
|
|
273
|
|
|
if (!is_array($idOrder)) { |
274
|
|
|
throw new \InvalidArgumentException('Order must be array!'); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
$res = true; |
278
|
|
|
foreach ($idOrder as $offset => $id) { |
279
|
|
|
$res = $res && $this->getDataStore()->updateTicketOffsetById($id, $offset); |
280
|
|
|
} |
281
|
|
|
if ($res) { |
282
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'ok']); |
283
|
|
|
} else { |
284
|
|
|
$jsonResponse = new JsonResponse(['ok' => 'fail', 'message' => 'Failed to store new sort order'], 500); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
return $jsonResponse; |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.