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