Refine the search REST ressource.
[Project_proches_de_moi-server.git] / src / Controller / PersonController.php
CommitLineData
dec6d031
JB
1<?php
2namespace App\Controller;
3
4use App\Entity\Person;
3d47ccc8
JB
5use App\Entity\Localisation;
6use \Datetime;
199445c0 7use \NotNull;
1d9d8d51 8use Symfony\Bundle\FrameworkBundle\Controller\Controller;
f0640a52 9use FOS\RestBundle\Controller\FOSRestController;
dec6d031 10use FOS\RestBundle\Controller\Annotations as Rest;
5347d06b
JB
11use FOS\RestBundle\View\ViewHandler;
12use FOS\RestBundle\View\View;
199445c0 13use FOS\RestBundle\Request\ParamFetcherInterface;
dec6d031
JB
14use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
15use Symfony\Component\HttpFoundation\Request;
16use Symfony\Component\HttpFoundation\Response;
17use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
18
f0640a52 19class PersonController extends FOSRestController
dec6d031
JB
20{
21 /**
22 * @Rest\Post(
f0640a52 23 * path = "/api/person/register",
dec6d031
JB
24 * name = "create_person"
25 * )
26 * @Rest\View(StatusCode = Response::HTTP_CREATED)
dec6d031 27 */
f0640a52 28 public function createPersonAction(Request $request)
3d47ccc8
JB
29 {
30 $person = new Person();
f0640a52
JB
31 $person->setFirstname($request->get('firstname'));
32 $person->setLastName($request->get('lastname'));
c4fba949 33 //TODO: email creation should normally have a verification step
f0640a52
JB
34 $person->setEmail($request->get('email'));
35 $person->setPassword($request->get('password'));
36 $person->setOnline(false);
37
dec6d031
JB
38 $em = $this->getDoctrine()->getManager();
39
40 $em->persist($person);
41 $em->flush();
42
199445c0
JB
43 return $this->view($person, Response::HTTP_CREATED,
44 ['Location' => $this->generateUrl('show_person',
45 ['id' => $person->getId(),
46 UrlGeneratorInterface::ABSOLUTE_URL])]);
dec6d031
JB
47 }
48
49 /**
98f85207 50 * @Rest\Delete("/api/person/{id}")
dec6d031
JB
51 * @Rest\View(statusCode = Response::HTTP_NO_CONTENT)
52 */
53 public function removePersonAction(Request $request)
54 {
3d47ccc8 55 //TODO: check that the authenticated user have the same id
dec6d031 56 $em = $this->getDoctrine()->getManager();
282545e5 57 $person = $em->getRepository('App:Person')->find($request->get('id'));
3d47ccc8
JB
58 $friends = $em->getRepository('App:Friendship')->findBy(['person' => $request->get('id')]);
59 $friends_with_me = $em->getRepository('App:Friendship')->findBy(['friend' => $request->get('id')]);
60 $localisations = $em->getRepository('App:Localisation')->findBy(['person' => $request->get('id')]);
dec6d031 61
3d47ccc8
JB
62 if (!empty($localisations)) {
63 foreach ($localisations as $localisation) {
64 $em->remove($localisation);
65 }
66 $em->flush();
67 }
68
69 if (!empty($friends)) {
70 foreach ($friends as $friend) {
71 $em->remove($friend);
72 }
73 $em->flush();
74 }
75
76 if (!empty($friends_with_me)) {
77 foreach ($friends_with_me as $friend) {
78 $em->remove($friend);
79 }
dec6d031
JB
80 $em->flush();
81 }
3d47ccc8
JB
82
83 if (!empty($person)) {
84 $em->remove($person);
85 $em->flush();
86 }
dec6d031
JB
87 }
88
89 /**
90 * @Rest\Put(
3d47ccc8 91 * path = "/api/person/{id}",
dec6d031
JB
92 * name = "update_person"
93 * )
94 * @Rest\View(StatusCode = Response::HTTP_CREATED)
95 */
96 public function updatePersonAction(Request $request)
97 {
3d47ccc8 98 //TODO: check that the authenticated user have the same id
dec6d031 99 $em = $this->getDoctrine()->getManager();
282545e5 100 $person = $em->getRepository('App:Person')->find($request->get('id'));
dec6d031 101
51963d7f 102 if (empty($person)) {
1faa29dc 103 return $this->PersonNotFound();
dec6d031
JB
104 }
105
106 $person->setFirstName($request->get('firstname'));
107 $person->setLastName($request->get('lastname'));
c4fba949 108 //TODO: email update should normally have a verification step
dec6d031
JB
109 $person->setEmail($request->get('email'));
110
111 $em->merge($person);
112 $em->flush();
113
199445c0
JB
114 return $this->view($person, Response::HTTP_CREATED,
115 ['Location' => $this->generateUrl('show_person',
116 ['id' => $person->getId(),
117 UrlGeneratorInterface::ABSOLUTE_URL])]);
dec6d031
JB
118 }
119
c4fba949
JB
120 /**
121 * @Rest\Post(
122 * path = "/api/person/authenticate",
123 * name = "authenticate_person"
124 * )
125 * @Rest\View(StatusCode = Response::HTTP_ACCEPTED)
126 */
127 public function authenticatePersonAction(Request $request)
128 {
129 $em = $this->getDoctrine()->getManager();
130 $person = $em->getRepository('App:Person')->findOneBy(['email' => $request->get('email')]);
131
132 if (empty($person)) {
133 return $this->PersonNotFound();
134 }
135
136 if ($request->get('password') != $person->getPassword()) {
137 return $this->PersonWrongPassword();
138 } else {
199445c0
JB
139 return $this->view($person, Response::HTTP_ACCEPTED,
140 ['Location' => $this->generateUrl('show_person',
141 ['id' => $person->getId(),
142 UrlGeneratorInterface::ABSOLUTE_URL])]);
c4fba949
JB
143 }
144 }
145
dec6d031 146 /**
84fd6c7f
JB
147 * @Rest\Get("/api/person/{id}/localisations")
148 * @Rest\View()
dec6d031 149 */
84fd6c7f 150 public function getLocalisationsAction(Request $request)
dec6d031 151 {
f0640a52 152 //TODO: Check that the authenticated user is allowed to see the localisation
84fd6c7f
JB
153 $em = $this->getDoctrine()->getManager();
154 $localisations = $em->getRepository('App:Localisation')->findBy(['person' => $request->get('id')]);
dec6d031 155
84fd6c7f
JB
156 if (empty($localisations)) {
157 return $this->PersonLocalisationsNotFound();
158 }
159
160 return $localisations;
dec6d031
JB
161 }
162
c4fba949
JB
163 /**
164 * @Rest\Get(
165 * path = "/api/person/{id}/localisations/fuzzy/{distance}",
166 * name = "person_localisations_fuzzy",
167 * requirements = {"id"="\d+", "distance"="\d+"}
168 * )
169 * @Rest\View()
170 */
171 public function getLocalisationsFuzzyAction(Request $request)
172 {
173 //TODO: Check that the authenticated user is allowed to see the localisation
174 $em = $this->getDoctrine()->getManager();
175 $localisations = $em->getRepository('App:Localisation')->findBy(['person' => $request->get('id')]);
176
177 if (empty($localisations)) {
178 return $this->PersonLocalisationsNotFound();
179 }
180
181 if (!$this->chk_distance($request->get('distance'), 200, 500)) {
182 return $this->PersonLocalisationFuzzyWrongDistance();
183 }
184
185 $fuzzy_localisations = array_map(function($item) use ($request) { return $this->randomizeLocation($item, $request->get('distance'), 200, 500); }, $localisations);
186
187 return $fuzzy_localisations;
188 }
189
190 private function getLastLocalisation($em, $id) {
199445c0
JB
191 $query = $em->createQuery("SELECT l1 FROM App\Entity\Localisation l1
192 WHERE l1.person = :person and l1.timestamp =
193 (SELECT MAX(l2.timestamp) FROM App\Entity\Localisation l2
194 WHERE l2.person = l1.person)");
c4fba949 195 $query->setParameter('person', $id);
19b09998
JB
196 $result = $query->getResult();
197 if (!empty($result)) {
198 return $result[0];
199 }
c4fba949
JB
200 }
201
4c4feb3e 202 /**
84fd6c7f
JB
203 * @Rest\Get("/api/person/{id}/localisation")
204 * @Rest\View()
4c4feb3e 205 */
84fd6c7f 206 public function getLocalisationAction(Request $request)
4c4feb3e 207 {
f0640a52 208 //TODO: Check that the authenticated user is allowed to see the localisation
4c4feb3e 209 $em = $this->getDoctrine()->getManager();
787fc3b7 210
c4fba949 211 $localisation = $this->getLastLocalisation($em, $request->get('id'));
4c4feb3e 212
f0640a52 213 if (empty($localisation)) {
84fd6c7f 214 return $this->PersonLocalisationNotFound();
4c4feb3e
JB
215 }
216
f0640a52 217 return $localisation;
4c4feb3e
JB
218 }
219
c4fba949
JB
220 private function chk_distance($distance, $min, $max) {
221 if ($distance >= $min && $distance <= $max) {
222 return true;
223 } else {
224 return false;
225 }
226 }
227
228 private function randomizeLocation($localisation, $distance, $min, $max) {
229 // Generate random float in [0, 1[, [0, 1)
230 $u = rand(0, getrandmax() - 1) / getrandmax();
231 $v = rand(0, getrandmax() - 1) / getrandmax();
232
233 if ($this->chk_distance($distance, $min, $max)) {
234 $r = $distance / 111300;
235 } else {
236 return $this->PersonLocalisationFuzzyWrongDistance();
237 }
238
239 $w = $r * sqrt($u);
240 $t = 2 * pi() * $v;
241
242 $x = $w * cos($t);
243 $lng_off = $x / cos(deg2rad($localisation->getLatitude()));
244 $lat_off = $w * sin($t);
245
246 $fuzzy_localisation = new Localisation();
247 $fuzzy_localisation->setTimestamp($localisation->getTimestamp());
248 $fuzzy_localisation->setLatitude($localisation->getLatitude() + $lat_off);
249 $fuzzy_localisation->setLongitude($localisation->getLongitude() + $lng_off);
250 return $fuzzy_localisation;
251 }
252
253 /**
254 * @Rest\Get(
255 * path = "/api/person/{id}/localisation/fuzzy/{distance}",
256 * name = "person_localisation_fuzzy",
257 * requirements = {"id"="\d+", "distance"="\d+"}
258 * )
259 * @Rest\View()
260 */
261 public function getLocalisationFuzzyAction(Request $request)
262 {
263 //TODO: Check that the authenticated user is allowed to see the localisation
264 $em = $this->getDoctrine()->getManager();
265
266 $localisation = $this->getLastLocalisation($em, $request->get('id'));
267
268 if (empty($localisation)) {
269 return $this->PersonLocalisationNotFound();
270 }
271
272 return $this->randomizeLocation($localisation, $request->get('distance'), 200, 500);
273 }
274
dec6d031 275 /**
98f85207 276 * @Rest\Post("/api/person/{id}/localisation")
43f58db4 277 * @Rest\View(StatusCode = Response::HTTP_CREATED)
dec6d031
JB
278 */
279 public function updateLocalisationAction(Request $request)
280 {
3d47ccc8
JB
281 //TODO: Check that the authenticated user is allowed to update the localisation
282 $em = $this->getDoctrine()->getManager();
283
284 $person = $em->getRepository('App:Person')->find($request->get('id'));
285
286 if (empty($person)) {
287 return $this->PersonNotFound();
288 }
289
290 $datetime = new DateTime($request->get('timestamp'));
291
dec6d031 292 $localisation = new Localisation();
3d47ccc8
JB
293 $localisation->setPerson($person);
294 $localisation->setTimestamp($datetime);
dec6d031
JB
295 $localisation->setLatitude($request->get('latitude'));
296 $localisation->setLongitude($request->get('longitude'));
297
dec6d031
JB
298 $em->persist($localisation);
299 $em->flush();
300 }
301
302 /**
f0640a52
JB
303 * @Rest\Get(
304 * path = "/api/person/{id}",
305 * name = "show_person",
306 * requirements = {"id"="\d+"}
307 * )
308 * @Rest\View()
309 */
310 public function showPerson(Request $request)
311 {
5347d06b
JB
312 $em = $this->getDoctrine()->getManager();
313 $person = $em->getRepository('App:Person')->find($request->get('id'));
51963d7f 314
5347d06b 315 if (empty($person)) {
1faa29dc 316 return $this->PersonNotFound();
51963d7f
JB
317 }
318
1faa29dc 319 return $person;
f0640a52
JB
320 }
321
f0640a52
JB
322 /**
323 * @Rest\Get(
324 * path = "/api/person/{id}/friends",
325 * name = "show_person_friends",
326 * requirements = {"id"="\d+"}
327 * )
328 * @Rest\View()
329 */
330 public function showPersonFriends(Request $request)
331 {
5347d06b
JB
332 $em = $this->getDoctrine()->getManager();
333 $person = $em->getRepository('App:Person')->find($request->get('id'));
334
335 if (empty($person)) {
1faa29dc 336 return $this->PersonNotFound();
5347d06b 337 }
51963d7f 338
1faa29dc 339 return $person->getFriends();
f0640a52
JB
340 }
341
c4fba949
JB
342 /**
343 * @Rest\Get(
344 * path = "/api/person/{id}/friendswithme",
345 * name = "show_person_friends_with_me",
346 * requirements = {"id"="\d+"}
347 * )
348 * @Rest\View()
349 */
350 public function showPersonFriendsWithMe(Request $request)
351 {
352 $em = $this->getDoctrine()->getManager();
353 $person = $em->getRepository('App:Person')->find($request->get('id'));
354
355 if (empty($person)) {
356 return $this->PersonNotFound();
357 }
358
80ec112f
JB
359 $friends_with_me = $person->getFriendsWithMe();
360
361 return $friends_with_me;
c4fba949
JB
362 }
363
f0640a52
JB
364 /**
365 * @Rest\Get(
366 * path = "/api/persons",
367 * name = "show_persons"
368 * )
369 * @Rest\View()
370 */
371 public function showPersons(Request $request)
372 {
373 $em = $this->getDoctrine()->getManager();
374 $persons = $em->getRepository('App:Person')->findAll();
375
376 if (empty($persons)) {
84fd6c7f 377 return $this->PersonsNotFound();
f0640a52
JB
378 }
379
380 return $persons;
381 }
382
8629835e
JB
383 /**
384 * @Rest\Put(
385 * path = "/api/person/{id}/online",
386 * name = "set_person_online"
387 * )
388 * @Rest\View(StatusCode = Response::HTTP_CREATED)
389 */
390 public function onlinePersonAction(Request $request)
391 {
392 //TODO: check that the authenticated user have the same id
393 $em = $this->getDoctrine()->getManager();
394 $person = $em->getRepository('App:Person')->find($request->get('id'));
395
396 if (empty($person)) {
397 return $this->PersonNotFound();
398 }
399
400 $person->setOnline(true);
401
402 $em->merge($person);
403 $em->flush();
404 }
405
406 /**
407 * @Rest\Put(
408 * path = "/api/person/{id}/offline",
409 * name = "set_person_offline"
410 * )
411 * @Rest\View(StatusCode = Response::HTTP_CREATED)
412 */
413 public function offlinePersonAction(Request $request)
414 {
415 //TODO: check that the authenticated user have the same id
416 $em = $this->getDoctrine()->getManager();
417 $person = $em->getRepository('App:Person')->find($request->get('id'));
418
419 if (empty($person)) {
420 return $this->PersonNotFound();
421 }
422
423 $person->setOnline(false);
424
425 $em->merge($person);
426 $em->flush();
427 }
428
80ec112f 429 /**
199445c0 430 * @Rest\Get(
80ec112f
JB
431 * path = "/api/person/search",
432 * name = "search_person"
433 * )
199445c0 434 * @Rest\QueryParam(name="keyword")
80ec112f
JB
435 * @Rest\View()
436 */
199445c0 437 public function searchPerson(ParamFetcherInterface $paramFetcher)
80ec112f
JB
438 {
439 $em = $this->getDoctrine()->getManager();
440 $query = $em->createQuery("SELECT DISTINCT p FROM App\Entity\Person p WHERE
199445c0
JB
441 p.firstname LIKE :keyword OR
442 p.lastname LIKE :keyword OR
80ec112f 443 p.email LIKE :keyword");
199445c0 444 $query->setParameter('keyword', '%'.$paramFetcher->get('keyword').'%');
80ec112f
JB
445 $persons = $query->getResult();
446
447 if (empty($persons)) {
199445c0 448 return $this->PersonsNotFound();
80ec112f
JB
449 }
450
451 return $persons;
452 }
453
f0640a52
JB
454 private function PersonNotFound() {
455 return View::create(['message' => 'Person not found'], Response::HTTP_NOT_FOUND);
456 }
b6077893 457
f0640a52
JB
458 private function PersonsNotFound() {
459 return View::create(['message' => 'Persons not found'], Response::HTTP_NOT_FOUND);
460 }
84fd6c7f 461
f0640a52
JB
462 private function PersonLocalisationNotFound() {
463 return View::create(['message' => 'Person localisation not found'], Response::HTTP_NOT_FOUND);
464 }
84fd6c7f 465
f0640a52
JB
466 private function PersonLocalisationsNotFound() {
467 return View::create(['message' => 'Person localisations not found'], Response::HTTP_NOT_FOUND);
468 }
b6077893 469
c4fba949
JB
470 private function PersonWrongPassword() {
471 return View::create(['message' => 'Supplied password do not match'], Response::HTTP_UNAUTHORIZED);
472 }
473 private function PersonLocalisationFuzzyWrongDistance() {
474 return View::create(['message' => 'Distance range do not match'], Response::HTTP_NOT_ACCEPTABLE);
475 }
476
dec6d031 477}