<?php
namespace Hona\ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Hona\ApiBundle\Exception\ErrorCodeException;
use Hona\ApiBundle\Exception\MissingRequiredFieldsException;
use Hona\ApiBundle\Exception\OutOfTimeWindowException;
use Hona\ApiBundle\Exception\AccessHistoryNeedsToAccessException;
use Hona\ApiBundle\Exception\AccessHistoryNeedsToExitException;
use Hona\ApiBundle\Exception\InvitationCanceledException;
use Hona\ApiBundle\Exception\InvitationRequestNotActiveException;
use Hona\ApiBundle\Library\Utils;
class InvitationController extends EntityController
{
protected $required = array("name", "type");
protected function _validateAfterGET(Request $request, $entity, $uuid, &$data, $clean){
if($entity == "invitation"){
$this->_changeIdForEntity("event", $data, $clean);
$this->_changeIdForEntity("user", $data, $clean);
$this->_changeIdForEntity("address", $data, $clean);
if(!empty($data["image_code_path"])){
$data["image_code_path"] = Utils::addMediaDomainToPath($data["image_code_path"]);
}
if($data["type"] == 3){
$this->_addListEntitiesCustomFunction("interval", "InvitationId", $data["id"], $data);
}
}
}
protected function _validateAfterPUT(Request $request, $entity, $uuid, &$data, $clean){
$this->_changeIdForEntity("event", $data, $clean);
$this->_changeIdForEntity("user", $data, $clean);
$this->_changeIdForEntity("address", $data, $clean);
if(!empty($data["image_code_path"])){
$data["image_code_path"] = Utils::addMediaDomainToPath($data["image_code_path"]);
}
//TODO change this to a function thats support multiple updates
if($data["type"] == 3){
$dataRequest = json_decode($request->getContent(), true);
if(isset($dataRequest["intervals"]) && is_array($dataRequest["intervals"])){
if(isset($dataRequest["intervals"][0]["uuid"])){
$response = $this->forward('HonaApiBundle:Interval:intervalPUT', [
'request' => $request,
'uuid' => $dataRequest["intervals"][0]["uuid"],
'data' => $dataRequest["intervals"][0]
]);
$this->_addListEntitiesCustomFunction("interval", "uuid", $dataRequest["intervals"][0]["uuid"], $data);
}else{
foreach($dataRequest["intervals"] as $interval){
$dataInterval = array();
$dataInterval['invitation'] = $uuid;
$dataInterval['date_start'] = $interval["date_start"];
$dataInterval['date_end'] = $interval["date_end"];
$dataInterval['monday'] = $interval["monday"];
$dataInterval['tuesday'] = $interval["tuesday"];
$dataInterval['wednesday'] = $interval["wednesday"];
$dataInterval['thursday'] = $interval["thursday"];
$dataInterval['friday'] = $interval["friday"];
$dataInterval['saturday'] = $interval["saturday"];
$dataInterval['sunday'] = $interval["sunday"];
$dataInterval['status'] = Utils::ACTIVE;
$response = $this->forward('HonaApiBundle:Interval:intervalPOST', [
'request' => $request,
'data' => $dataInterval
]);
}
$this->_addListEntitiesCustomFunction("interval", "InvitationId", $data["id"], $data);
}
}
}
}
protected function _validateAfterPOST(Request $request, $entity, $uuid, &$data, $clean){
$this->_changeIdForEntity("event", $data, $clean);
$this->_changeIdForEntity("user", $data, $clean);
$this->_changeIdForEntity("address", $data, $clean);
if(!empty($data["image_code_path"])){
$data["image_code_path"] = Utils::addMediaDomainToPath($data["image_code_path"]);
}
if($data["type"] == 3){
$dataRequest = json_decode($request->getContent(), true);
if(isset($dataRequest["intervals"]) && is_array($dataRequest["intervals"])){
foreach($dataRequest["intervals"] as $interval){
$dataInterval = array();
$dataInterval['invitation'] = $uuid;
$dataInterval['date_start'] = $interval["date_start"];
$dataInterval['date_end'] = $interval["date_end"];
$dataInterval['monday'] = $interval["monday"];
$dataInterval['tuesday'] = $interval["tuesday"];
$dataInterval['wednesday'] = $interval["wednesday"];
$dataInterval['thursday'] = $interval["thursday"];
$dataInterval['friday'] = $interval["friday"];
$dataInterval['saturday'] = $interval["saturday"];
$dataInterval['sunday'] = $interval["sunday"];
$dataInterval['status'] = Utils::ACTIVE;
$response = $this->forward('HonaApiBundle:Interval:intervalPOST', [
'request' => $request,
'data' => $dataInterval
]);
}
}else{
$startDate = new \DateTime();
$endDate = new \DateTime();
$dataInterval = array();
$dataInterval['invitation'] = $uuid;
$dataInterval['date_start'] = $startDate;
$dataInterval['date_end'] = $endDate->add(new \DateInterval('P1Y'));
$dataInterval['monday'] = true;
$dataInterval['tuesday'] = true;
$dataInterval['wednesday'] = true;
$dataInterval['thursday'] = true;
$dataInterval['friday'] = true;
$dataInterval['saturday'] = true;
$dataInterval['sunday'] = true;
$dataInterval['status'] = Utils::ACTIVE;
$response = $this->forward('HonaApiBundle:Interval:intervalPOST', [
'request' => $request,
'data' => $dataInterval
]);
}
$this->_addListEntitiesCustomFunction("interval", "InvitationId", $data["id"], $data);
}
}
protected function _validateBeforePOST(Request $request, $entity, &$data){
if(isset($data["event"])){
//This will copy user_id and address_id from event
$this->_changeUuidForId("event", $data, null, array("user", "address"));
}else if(isset($data["user"]) && isset($data["address"])){
$this->_changeUuidForId("user", $data);
$this->_changeUuidForId("address", $data);
//TODO validate if relation user and address is valid probably better with permission change later
$this->_validateRelationship("address",
array("user_id" => $data["user_id"]),
array(
//TODO check index table
"id" => $data["address_id"],
"status" => Utils::ACTIVE
)
);
}else{
throw new MissingRequiredFieldsException(array("event or user+address"));
}
if($data["type"] != 3 && !array_key_exists("date_invitation", $data)){
throw new MissingRequiredFieldsException(array("date_invitation"));
}
/*if($data["type"] == 3 && !array_key_exists("intervals", $data)){
throw new MissingRequiredFieldsException(array("intervals"));
}elseif($data["type"] == 3 && !is_array($data["intervals"])){
throw new MissingRequiredFieldsException(array("intervals"));
}*/
if(!isset($data["status"])){
$data["status"] = Utils::ACTIVE;
}
$data["code"] = Utils::generateAccessCode();
//TODO validate if not in the DB
$data["image_code_path"] = Utils::generateImageForAccessCode($data["code"]);
}
protected function _validateBeforePUT(Request $request, $entity, $uuid, &$data){
$this->_changeUuidForId("event", $data, null, array("user", "address"));
$this->_changeUuidForId("user", $data);
$this->_changeUuidForId("address", $data);
}
/**
* @Route("/invitation/from/invitation_request/{uuid}", name="invitation_from_invitation_request_uuid", methods={"GET"})
* @param $request
*/
public function invitationFromInvitationRequestAction(Request $request, $uuid)
{
$invitation_request = $this->_entityGET($request, "invitation_request", $uuid, null, true, false, 'admin_object');
if(is_array($invitation_request)){
if($invitation_request["status"] == Utils::ACTIVE){
$this->_changeIdForEntity("event", $invitation_request, false);
$data = array(
"name" => $invitation_request["name"],
"last_name" => $invitation_request["last_name"],
"event" => $invitation_request["event"]["uuid"],
"date_invitation" => $invitation_request["event"]["date_event"],
"type" => 1
);
$dataReturn = $this->_entityPOST($request, "invitation", $data, true, false);
if(is_array($dataReturn)){
$this->_entityPUT($request, "invitation_request", $uuid, array(
"status" => Utils::ACCEPTED,
"invitation_id" => $dataReturn["id"]
));
Utils::sendInvitationEmail($this->get("twig"), $dataReturn, $invitation_request["event"], $invitation_request);
$this->_removeIdFields($dataReturn);
return new JsonResponse($dataReturn);
}else{
return $dataReturn;
}
}else{
$exception = new InvitationRequestNotActiveException($uuid);
$data = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
'code' => $exception->getErrorCode()
];
return new JsonResponse($data, $exception->getStatusCode());
}
}else{
return $invitation_request;
}
}
/**
* @Route("/invitation/create", name="invitation_create", methods={"POST"})
* @param $request
*/
public function invitationCreateAction(Request $request)
{
$user = $this->getUser();
$data = json_decode($request->getContent(), true);
$data["user"] = $user->getUuid();
$userHasAddress = Utils::checkUserAddressExists($this->getDoctrine()->getManager(), $data["address"], $user);
if($userHasAddress){
return $this->_entityPOST($request, "invitation", $data);
}else{
$data = [
'message' => "user with no address",
'code' => 20
];
return new JsonResponse($data, 400);
}
}
private function _validateInvitationInterval($dataReturn){
$todayDayDate = new \DateTime();
$todayDayDate->setTimeZone(new \DateTimeZone(Utils::getParameter('default_timezone')));
$todayDay = strtolower($todayDayDate->format('l'));
//TODO update this to support multiple intervals
$dayAllowed = $dataReturn["intervals"][0][$todayDay];
$startDateInvitation = new \DateTime($dataReturn["intervals"][0]["date_start"]);
$endDateInvitation = new \DateTime($dataReturn["intervals"][0]["date_end"]);
$accessTolerance = Utils::getParameter("access_tolerance");
$startDateInvitation->sub(date_interval_create_from_date_string($accessTolerance.' seconds'));
$endDateInvitation->add(date_interval_create_from_date_string($accessTolerance.' seconds'));
$now = new \DateTime();
if(!$dayAllowed || ($now < $startDateInvitation || $now > $endDateInvitation)){
return false;
}
return true;
}
private function _validationRequestCode(Request $request, $data = null){
try{
$user = $this->getUser();
if($data == null){
$data = json_decode($request->getContent(), true);
}
$dataReturn = $this->_entityByFieldGET($request, "invitation", "code", $data["code"], null, true, false);
if(is_array($dataReturn)){
if($dataReturn["status"] != Utils::ACTIVE && $dataReturn["status"] != Utils::HALFACTIVE){
throw new InvitationCanceledException($data["code"]);
}
if(isset($dataReturn["address"]["residential_id"])){
$this->_validateRelationship("control_gate",
array("user_id" => $user->getId()),
array(
//TODO check index table
"uuid" => $data["control_gate"],
"residential_id" => $dataReturn["address"]["residential_id"],
"status" => Utils::ACTIVE
)
);
$accessHistory = $this->_entityByFieldsGET(
$request, "access_history",
array(
"invitation_id" => $dataReturn["id"],
"date_departure" => null
), null, true, false
);
if(is_array($accessHistory)){
//need to exit
$dataReturn["access_history"] = $accessHistory;
}else{
//Validate time window
$startDateInvitation = new \DateTime($dataReturn["date_invitation"]);
$endDateInvitation = new \DateTime($dataReturn["date_invitation"]);
$accessTolerance = Utils::getParameter("access_tolerance");
$startDateInvitation->sub(date_interval_create_from_date_string($accessTolerance.' seconds'));
$endDateInvitation->add(date_interval_create_from_date_string($accessTolerance.' seconds'));
$now = new \DateTime();
if($now < $startDateInvitation || $now > $endDateInvitation){
throw new OutOfTimeWindowException(new \DateTime($dataReturn["date_invitation"]));
}
}
$this->_removeIdFields($dataReturn);
$this->_removeIdFields($dataReturn["event"]);
$this->_removeIdFields($dataReturn["address"]);
$this->_removeIdFields($dataReturn["user"]);
$this->_removeIdFields($dataReturn["access_history"]);
}
}
return $dataReturn;
}catch(ErrorCodeException $exception){
$data = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
'code' => $exception->getErrorCode()
];
return new JsonResponse($data, $exception->getStatusCode());
}catch(HttpException $exception){
$data = [
'message' => $exception->getMessage()
];
return new JsonResponse($data, $exception->getStatusCode());
}
}
/**
* @Route("/invitation/check", name="invitation_check", methods={"POST"})
* @param $request
*/
public function invitationCheckAction(Request $request)
{
$dataReturn = $this->_validationRequestCode($request);
if(is_array($dataReturn)){
return new JsonResponse($dataReturn);
}
return $dataReturn;
}
/**
* @Route("/invitation/cancel", name="invitation_cancel", methods={"POST"})
* @param $request
*/
public function invitationCancelAction(Request $request)
{
$user = $this->getUser();
$data = json_decode($request->getContent(), true);
$dataReturn = $this->_validationRequestCode($request, $data);
if(is_array($dataReturn)){
if(isset($dataReturn["access_history"])){
$exception = new AccessHistoryNeedsToExitException($dataReturn["access_history"]["uuid"]);
$dataReturn = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
'code' => $exception->getErrorCode()
];
return new JsonResponse($dataReturn, $exception->getStatusCode());
}
//forward to create Access History
$content = array(
"status" => Utils::CANCELED
);
$request->initialize(
$request->query->all(),
$request->request->all(),
$request->attributes->all(),
$request->cookies->all(),
$request->files->all(),
$request->server->all(),
json_encode($content)
);
return $this->forward('HonaApiBundle:Invitation:invitationPUT', [
'request' => $request,
'uuid' => $dataReturn["uuid"]
]);
}
return $dataReturn;
}
/**
* @Route("/invitation/registry/access", name="invitation_registry_access", methods={"POST"})
* @param $request
*/
public function invitationRegistyAccessAction(Request $request)
{
$user = $this->getUser();
$data = json_decode($request->getContent(), true);
$dataReturn = $this->_validationRequestCode($request, $data);
if(is_array($dataReturn)){
if(isset($dataReturn["access_history"])){
$exception = new AccessHistoryNeedsToExitException($dataReturn["access_history"]["uuid"]);
$dataReturn = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
'code' => $exception->getErrorCode()
];
return new JsonResponse($dataReturn, $exception->getStatusCode());
}
if($dataReturn["type"] == 3 && isset($dataReturn["intervals"]) && is_array($dataReturn["intervals"])){
if(!$this->_validateInvitationInterval($dataReturn)){
$exception = new OutOfTimeWindowException(new \DateTime());
$dataReturn = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
'code' => $exception->getErrorCode()
];
return new JsonResponse($dataReturn, $exception->getStatusCode());
}
}
if($dataReturn["type"] != 3){
$dataTemp = array(
"status" => Utils::HALFACTIVE
);
$this->_entityPUT($request, "invitation", $dataReturn["uuid"], $dataTemp);
}
//forward to create Access History
$content = array(
"control_gate_entry" => $data["control_gate"],
"user_allow_entry" => $user->getUuid(),
"date_entry" => date("Y-m-d H:i:s"),
"invitation" => $dataReturn["uuid"]
);
$request->initialize(
$request->query->all(),
$request->request->all(),
$request->attributes->all(),
$request->cookies->all(),
$request->files->all(),
$request->server->all(),
json_encode($content)
);
return $this->forward('HonaApiBundle:AccessHistory:accessHistoryPOST', [
'request' => $request
]);
}
return $dataReturn;
}
/**
* @Route("/invitation/registry/exit", name="invitation_registry_exit", methods={"POST"})
* @param $request
*/
public function invitationRegistyExitAction(Request $request)
{
$user = $this->getUser();
$data = json_decode($request->getContent(), true);
$dataReturn = $this->_validationRequestCode($request, $data);
$exception = null;
if(is_array($dataReturn)){
if(isset($dataReturn["access_history"])){
if($dataReturn["access_history"]["uuid"] == $data["access_history"]){
$content = array(
"control_gate_departure" => $data["control_gate"],
"user_allow_departure" => $user->getUuid(),
"date_departure" => date("Y-m-d H:i:s")
);
if($dataReturn["type"] != 3){
$dataTemp = array(
"status" => Utils::USED
);
$this->_entityPUT($request, "invitation", $dataReturn["uuid"], $dataTemp);
}
$request->initialize(
$request->query->all(),
$request->request->all(),
$request->attributes->all(),
$request->cookies->all(),
$request->files->all(),
$request->server->all(),
json_encode($content)
);
return $this->forward('HonaApiBundle:AccessHistory:accessHistoryPUT', [
'request' => $request,
'uuid' => $dataReturn["access_history"]["uuid"]
]);
}else{
$exception = new AccessHistoryNeedsToExitException($dataReturn["access_history"]["uuid"]);
}
}else{
$exception = new AccessHistoryNeedsToAccessException();
}
}
if($exception != null){
$dataReturn = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
'code' => $exception->getErrorCode()
];
return new JsonResponse($dataReturn, $exception->getStatusCode());
}
return $dataReturn;
}
/**
* @Route("/invitation/{uuid}", name="invitation_get_uuid", methods={"GET"})
* @param $request
*/
public function invitationGETAction(Request $request, $uuid)
{
return $this->_entityGET($request, "invitation", $uuid);
}
/**
* @Route("/invitation", name="invitation_post_uuid", methods={"POST"})
* @param $request
*/
public function invitationPOSTAction(Request $request)
{
return $this->_entityPOST($request, "invitation");
}
/**
* @Route("/invitation/{uuid}", name="invitation_put_uuid", methods={"PUT"})
* @param $request
*/
public function invitationPUTAction(Request $request, $uuid)
{
return $this->_entityPUT($request, "invitation", $uuid);
}
/**
* @Route("/invitation/{uuid}", name="invitation_delete_uuid", methods={"DELETE"})
* @param $request
*/
public function invitationDELETEAction(Request $request, $uuid)
{
return $this->_entityDELETE($request, "invitation", $uuid);
}
}