Add new REST ressources.
[Project_proches_de_moi-server.git] / src / Controller / PersonController.php
1 <?php
2 namespace App\Controller;
3
4 use App\Entity\Person;
5 use App\Entity\Localisation;
6 use \Datetime;
7 use Symfony\Bundle\FrameworkBundle\Controller\Controller;
8 use FOS\RestBundle\Controller\FOSRestController;
9 use FOS\RestBundle\Controller\Annotations as Rest;
10 use FOS\RestBundle\View\ViewHandler;
11 use FOS\RestBundle\View\View;
12 use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
13 use Symfony\Component\HttpFoundation\Request;
14 use Symfony\Component\HttpFoundation\Response;
15 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16
17 class PersonController extends FOSRestController
18 {
19 /**
20 * @Rest\Post(
21 * path = "/api/person/register",
22 * name = "create_person"
23 * )
24 * @Rest\View(StatusCode = Response::HTTP_CREATED)
25 */
26 public function createPersonAction(Request $request)
27 {
28 $person = new Person();
29 $person->setFirstname($request->get('firstname'));
30 $person->setLastName($request->get('lastname'));
31 //TODO: email creation should normally have a verification step
32 $person->setEmail($request->get('email'));
33 $person->setPassword($request->get('password'));
34 $person->setOnline(false);
35
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 /**
45 * @Rest\Delete("/api/person/{id}")
46 * @Rest\View(statusCode = Response::HTTP_NO_CONTENT)
47 */
48 public function removePersonAction(Request $request)
49 {
50 //TODO: check that the authenticated user have the same id
51 $em = $this->getDoctrine()->getManager();
52 $person = $em->getRepository('App:Person')->find($request->get('id'));
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')]);
56
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 }
75 $em->flush();
76 }
77
78 if (!empty($person)) {
79 $em->remove($person);
80 $em->flush();
81 }
82 }
83
84 /**
85 * @Rest\Put(
86 * path = "/api/person/{id}",
87 * name = "update_person"
88 * )
89 * @Rest\View(StatusCode = Response::HTTP_CREATED)
90 */
91 public function updatePersonAction(Request $request)
92 {
93 //TODO: check that the authenticated user have the same id
94 $em = $this->getDoctrine()->getManager();
95 $person = $em->getRepository('App:Person')->find($request->get('id'));
96
97 if (empty($person)) {
98 return $this->PersonNotFound();
99 }
100
101 $person->setFirstName($request->get('firstname'));
102 $person->setLastName($request->get('lastname'));
103 //TODO: email update should normally have a verification step
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
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
135 /**
136 * @Rest\Get("/api/person/{id}/localisations")
137 * @Rest\View()
138 */
139 public function getLocalisationsAction(Request $request)
140 {
141 //TODO: Check that the authenticated user is allowed to see the localisation
142 $em = $this->getDoctrine()->getManager();
143 $localisations = $em->getRepository('App:Localisation')->findBy(['person' => $request->get('id')]);
144
145 if (empty($localisations)) {
146 return $this->PersonLocalisationsNotFound();
147 }
148
149 return $localisations;
150 }
151
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);
182 return $query->getResult()[0];
183 }
184
185 /**
186 * @Rest\Get("/api/person/{id}/localisation")
187 * @Rest\View()
188 */
189 public function getLocalisationAction(Request $request)
190 {
191 //TODO: Check that the authenticated user is allowed to see the localisation
192 $em = $this->getDoctrine()->getManager();
193
194 $localisation = $this->getLastLocalisation($em, $request->get('id'));
195
196 if (empty($localisation)) {
197 return $this->PersonLocalisationNotFound();
198 }
199
200 return $localisation;
201 }
202
203 private function chk_distance($distance, $min, $max) {
204 if ($distance >= $min && $distance <= $max) {
205 return true;
206 } else {
207 return false;
208 }
209 }
210
211 private function randomizeLocation($localisation, $distance, $min, $max) {
212 // Generate random float in [0, 1[, [0, 1)
213 $u = rand(0, getrandmax() - 1) / getrandmax();
214 $v = rand(0, getrandmax() - 1) / getrandmax();
215
216 if ($this->chk_distance($distance, $min, $max)) {
217 $r = $distance / 111300;
218 } else {
219 return $this->PersonLocalisationFuzzyWrongDistance();
220 }
221
222 $w = $r * sqrt($u);
223 $t = 2 * pi() * $v;
224
225 $x = $w * cos($t);
226 $lng_off = $x / cos(deg2rad($localisation->getLatitude()));
227 $lat_off = $w * sin($t);
228
229 $fuzzy_localisation = new Localisation();
230 $fuzzy_localisation->setTimestamp($localisation->getTimestamp());
231 $fuzzy_localisation->setLatitude($localisation->getLatitude() + $lat_off);
232 $fuzzy_localisation->setLongitude($localisation->getLongitude() + $lng_off);
233 return $fuzzy_localisation;
234 }
235
236 /**
237 * @Rest\Get(
238 * path = "/api/person/{id}/localisation/fuzzy/{distance}",
239 * name = "person_localisation_fuzzy",
240 * requirements = {"id"="\d+", "distance"="\d+"}
241 * )
242 * @Rest\View()
243 */
244 public function getLocalisationFuzzyAction(Request $request)
245 {
246 //TODO: Check that the authenticated user is allowed to see the localisation
247 $em = $this->getDoctrine()->getManager();
248
249 $localisation = $this->getLastLocalisation($em, $request->get('id'));
250
251 if (empty($localisation)) {
252 return $this->PersonLocalisationNotFound();
253 }
254
255 return $this->randomizeLocation($localisation, $request->get('distance'), 200, 500);
256 }
257
258 /**
259 * @Rest\Post("/api/person/{id}/localisation")
260 * @Rest\View(StatusCode = Response::HTTP_CREATED)
261 */
262 public function updateLocalisationAction(Request $request)
263 {
264 //TODO: Check that the authenticated user is allowed to update the localisation
265 $em = $this->getDoctrine()->getManager();
266
267 $person = $em->getRepository('App:Person')->find($request->get('id'));
268
269 if (empty($person)) {
270 return $this->PersonNotFound();
271 }
272
273 $datetime = new DateTime($request->get('timestamp'));
274
275 $localisation = new Localisation();
276 $localisation->setPerson($person);
277 $localisation->setTimestamp($datetime);
278 $localisation->setLatitude($request->get('latitude'));
279 $localisation->setLongitude($request->get('longitude'));
280
281 $em->persist($localisation);
282 $em->flush();
283 }
284
285 /**
286 * @Rest\Get(
287 * path = "/api/person/{id}",
288 * name = "show_person",
289 * requirements = {"id"="\d+"}
290 * )
291 * @Rest\View()
292 */
293 public function showPerson(Request $request)
294 {
295 $em = $this->getDoctrine()->getManager();
296 $person = $em->getRepository('App:Person')->find($request->get('id'));
297
298 if (empty($person)) {
299 return $this->PersonNotFound();
300 }
301
302 return $person;
303 }
304
305 /**
306 * @Rest\Get(
307 * path = "/api/person/{id}/friends",
308 * name = "show_person_friends",
309 * requirements = {"id"="\d+"}
310 * )
311 * @Rest\View()
312 */
313 public function showPersonFriends(Request $request)
314 {
315 $em = $this->getDoctrine()->getManager();
316 $person = $em->getRepository('App:Person')->find($request->get('id'));
317
318 if (empty($person)) {
319 return $this->PersonNotFound();
320 }
321
322 return $person->getFriends();
323 }
324
325 /**
326 * @Rest\Get(
327 * path = "/api/person/{id}/friendswithme",
328 * name = "show_person_friends_with_me",
329 * requirements = {"id"="\d+"}
330 * )
331 * @Rest\View()
332 */
333 public function showPersonFriendsWithMe(Request $request)
334 {
335 $em = $this->getDoctrine()->getManager();
336 $person = $em->getRepository('App:Person')->find($request->get('id'));
337
338 if (empty($person)) {
339 return $this->PersonNotFound();
340 }
341
342 return $person->getFriendsWithMe();
343 }
344
345 /**
346 * @Rest\Get(
347 * path = "/api/persons",
348 * name = "show_persons"
349 * )
350 * @Rest\View()
351 */
352 public function showPersons(Request $request)
353 {
354 $em = $this->getDoctrine()->getManager();
355 $persons = $em->getRepository('App:Person')->findAll();
356
357 if (empty($persons)) {
358 return $this->PersonsNotFound();
359 }
360
361 return $persons;
362 }
363
364 /**
365 * @Rest\Put(
366 * path = "/api/person/{id}/online",
367 * name = "set_person_online"
368 * )
369 * @Rest\View(StatusCode = Response::HTTP_CREATED)
370 */
371 public function onlinePersonAction(Request $request)
372 {
373 //TODO: check that the authenticated user have the same id
374 $em = $this->getDoctrine()->getManager();
375 $person = $em->getRepository('App:Person')->find($request->get('id'));
376
377 if (empty($person)) {
378 return $this->PersonNotFound();
379 }
380
381 $person->setOnline(true);
382
383 $em->merge($person);
384 $em->flush();
385 }
386
387 /**
388 * @Rest\Put(
389 * path = "/api/person/{id}/offline",
390 * name = "set_person_offline"
391 * )
392 * @Rest\View(StatusCode = Response::HTTP_CREATED)
393 */
394 public function offlinePersonAction(Request $request)
395 {
396 //TODO: check that the authenticated user have the same id
397 $em = $this->getDoctrine()->getManager();
398 $person = $em->getRepository('App:Person')->find($request->get('id'));
399
400 if (empty($person)) {
401 return $this->PersonNotFound();
402 }
403
404 $person->setOnline(false);
405
406 $em->merge($person);
407 $em->flush();
408 }
409
410 private function PersonNotFound() {
411 return View::create(['message' => 'Person not found'], Response::HTTP_NOT_FOUND);
412 }
413
414 private function PersonsNotFound() {
415 return View::create(['message' => 'Persons not found'], Response::HTTP_NOT_FOUND);
416 }
417
418 private function PersonLocalisationNotFound() {
419 return View::create(['message' => 'Person localisation not found'], Response::HTTP_NOT_FOUND);
420 }
421
422 private function PersonLocalisationsNotFound() {
423 return View::create(['message' => 'Person localisations not found'], Response::HTTP_NOT_FOUND);
424 }
425
426 private function PersonWrongPassword() {
427 return View::create(['message' => 'Supplied password do not match'], Response::HTTP_UNAUTHORIZED);
428 }
429 private function PersonLocalisationFuzzyWrongDistance() {
430 return View::create(['message' => 'Distance range do not match'], Response::HTTP_NOT_ACCEPTABLE);
431 }
432
433 }