<?php
namespace App\Controller;
use App\Entity\Answer;
use App\Entity\Resource;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use App\Entity\ResourceMessage;
use App\Entity\User;
use App\Helpers\CalCommons;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Ramsey\Uuid\Uuid;
use Doctrine\Common\Collections\Criteria;
class ApiController extends AbstractController {
use ApiTraits\AppControllerTrait,
ApiTraits\ClientControllerTrait;
protected function getCurrentUser() {
if (!$this->container->has('security.token_storage')) {
throw new \LogicException('The Security Bundle is not registered in your application.');
}
if (null === $token = $this->container->get('security.token_storage')->getToken()) {
return;
}
if (!is_object($user = $token->getUser())) {
// e.g. anonymous authentication
return;
}
return $user;
}
/**
* @Route("/password")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*
public function setPW(Request $request, UserPasswordEncoderInterface $passwordEncoder): JsonResponse {
$uamn = $this->getDoctrine()->getManager()->getRepository(User::class);
$user = $uamn->find(1);
$user->setPassword($passwordEncoder->encodePassword($user, "1234"));
$uamn->save($user);
return new JsonResponse(["none"]);
}*/
/**
* @Route("/save", methods={"POST"})
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function saveAction(Request $request) {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$data = json_decode($request->getContent(), true);
$version = $request->query->get("v", "last");
$debug = $this->saveAll($data, $user, "browser", $version);
return new JsonResponse($debug);
}
/**
* @Route("/loadFile", methods={"POST"})
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function serveFileAction(Request $request) {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$data = json_decode($request->getContent(), true);
$message = $this->getDoctrine()
->getRepository(ResourceMessage::class)->findOneBy(["uuid" => $data["messageId"]]);
if (is_null($message)) {
$response = new JsonResponse(["message" => "invalid msgid"]);
$response->setStatusCode(404);
return $response;
}
$userGroupIds = [];
foreach ($user->getGroups() as $group) {
$userGroupIds[$group->getId()] = true;
}
$fileName = "/var/www/prod-01-infra-server/files/" . $message->getAttachment();
if (file_exists($fileName)) {
foreach ($message->getUser()->getGroups() as $foreignGroup) {
if (isset($userGroupIds[$foreignGroup->getId()]))
return new BinaryFileResponse($fileName);
}
}
$response = new JsonResponse(["message" => "not allowed", "file" => $fileName]);
$response->setStatusCode(403);
return $response;
}
/**
* @Route("/saveFeed", methods={"POST"})
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function saveFeedAction(Request $request) {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$resourceId = $request->get("resource");
$resource = $this->getDoctrine()
->getRepository(Resource::class)->findOneBy(["uuid" => $resourceId]);
if (is_null($resource)) {
$response = new JsonResponse(["message" => "invalid resource"]);
$response->setStatusCode(400);
return $response;
}
if (($file = $request->files->get('image'))) {
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = preg_replace("/[^A-Za-z0-9]/", "", $originalFilename);
$fileName = $safeFilename . '-' . uniqid() . '.' . $file->getClientOriginalExtension();
try {
$file->move("/var/www/prod-01-infra-server/files/", $fileName);
$fileUrl = $fileName;
} catch (FileException $e) {
$fileUrl = null;
}
} else
$fileUrl = null;
$data = ["resourceMessages" => [
[
"type" => $request->get("type"),
"message" => $request->get("text"),
"_resource" => $resourceId,
"attachment" => $fileUrl,
"id" => Uuid::uuid4(),
"updatedAt" => (new \DateTime())->getTimestamp() * 1000
]
]];
$this->saveAll($data, $user, "browser", "1");
$version = $request->query->get("v", "last");
$resourceMessages = $this->export($this->getDoctrine()->getRepository(ResourceMessage::class)->findAllWithResourceIn([$resource]), "browser", $version);
return new JsonResponse($resourceMessages);
}
/**
* @Route("/getProjectAttachment/{uuid}/{name}", methods={"GET"})
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function getFileAction($uuid) {
$message = $this->getDoctrine()
->getRepository("App\Entity\ProjectAttachment")->findOneBy(["uuid" => $uuid]);
if (is_null($message)) {
$response = new JsonResponse(["message" => "invalid msgid"]);
$response->setStatusCode(404);
return $response;
}
$fileName = "/var/www/prod-01-infra-server/files/" . $message->getAttachment();
if (file_exists($fileName)) {
return new BinaryFileResponse($fileName);
}
$response = new JsonResponse(["message" => "not allowed", "file" => $fileName]);
$response->setStatusCode(403);
return $response;
}
/**
* @Route("/saveProjectAttachment", methods={"POST"})
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function saveProjectAttachmentAction(Request $request) {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$projectId = $request->get("project");
$project = $this->getDoctrine()
->getRepository("App\Entity\Project")->findOneBy(["uuid" => $projectId]);
if (is_null($project)) {
$response = new JsonResponse(["message" => "invalid project"]);
$response->setStatusCode(400);
return $response;
}
if (($file = $request->files->get('file'))) {
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = preg_replace("/[^A-Za-z0-9]/", "", $originalFilename);
$fileName = $safeFilename . '-' . uniqid() . '.' . $file->getClientOriginalExtension();
try {
$file->move("/var/www/prod-01-infra-server/files/", $fileName);
$fileUrl = $fileName;
} catch (FileException $e) {
$fileUrl = null;
}
} else
$fileUrl = null;
return new JsonResponse(["attachment" => $fileUrl, "user" => $user->getUuid(), "creator" => $user->getName()]);
}
/**
* @Route("/loadReport/{start}/{end}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function loadReportAction($start, $end)
{
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$d = $this->getDoctrine();
$startTime = (new \DateTime())->setTimestamp(ceil($start / 1000));
$endTime = (new \DateTime())->setTimestamp(ceil($end / 1000));
$projects = $this->getDoctrine()->getRepository("App\Entity\Project")->findAllWithRights($user);
$pids = [];
$uuids = [];
$bpo = [];
foreach ($projects as $project) {
$id = $project->getId();
$uuid = $project->getUuid();
$bpokey = $project->getBpokey();
$pids[] = $id;
$uuids[$id] = $uuid;
$bpo[$id] = $bpokey;
}
// $pids = array_map(function ($e) {
// return $e->getId();
// }, $projects);
$projectCrit = Criteria::expr()->in('project', $pids);
$endCrit = Criteria::expr()->lt('start', $endTime);
$startCrit = Criteria::expr()->gt('end', $startTime);
$deletedCrit = Criteria::expr()->eq('deletedAt', NULL);
$jobCriteria = Criteria::create()->where(Criteria::expr()->andX($projectCrit, $deletedCrit, $startCrit, $endCrit));
$jobs = $d->getRepository("App\Entity\Job")->matching($jobCriteria);
$reports = $d->getRepository("App\Entity\Answer")->getReports($jobs);
return new JsonResponse(array_map(function ($x) use ($uuids, $bpo) {
$resourceUuid = '';
if (isset($x['answer']) && $x['answer'] instanceof Answer) {
$answeredBy = $x['answer']->getAnsweredBy();
if ($answeredBy instanceof Resource) {
$resourceUuid = $answeredBy->getUuid();
}
}
return [
"project" => $uuids[$x["pproject"]] ?? "",
"bpokey" => $bpo[$x["pproject"]] ?? "",
"date" => $x["pdate"]->format("Y-m-d"),
"answeredBy" => $resourceUuid
];
}, $reports));
}
/**
* @Route("/loadReportAnswers/{projectId}/{date}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function loadReportAnswersAction(Request $request, $projectId, $date) {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$company = $user->getCompany();
$companyId = $company->getId() ?? 0;
$d = $this->getDoctrine();
$project = $d->getRepository("App\Entity\Project")->findOneBy(["uuid" => $projectId]);
$reports = $d->getRepository("App\Entity\Answer")->getAnswers($project, $date);
$images = $d->getRepository("App\Entity\JobMessage")->getMessages($project, $date);
$version = $request->query->get("v", "last");
return new JsonResponse([
"answers" => $this->export($reports, "browser", $version),
"images" => $this->export($images, "browser", $version),
"company_id" => $companyId,
]);
}
/**
* @Route("/load/{type}/{since}/{month}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function loadAction(Request $request, $type = "default", $since = 0, $month = "2021-0") {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$version = $request->query->get("v", "last");
return new JsonResponse($this->loadData($user, $type, $since, $version, $month));
}
/**
* @Route("/encode/{code}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function encodeAction($code) {
$out = CalCommons::encodeRes($code);
return new JsonResponse($out);
}
public function decodeRes($code) {
$out = CalCommons::decodeRes($code);
if ($out === FALSE) {
return [false, false];
}
if ($out < 0) {
$entity = $this->getDoctrine()->getRepository("App\Entity\User")->findOneBy(["bpo_id" => $out * -1]);
$type = "USER";
} else {
$type = "RESOURCE";
$entity = $this->getDoctrine()->getRepository("App\Entity\Resource")->findOneBy(["bpo_id" => $out]);
}
return [$type, $entity];
}
/**
* @Route("/appAuth/{code}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function appAuthAction($code) {
list($type, $entity) = $this->decodeRes(preg_replace("/[^0-9]/", "", $code));
if ($type === FALSE) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
if ($entity->isDeleted()) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
return new JsonResponse(["name" => $entity->getName(), "image" => $type === "RESOURCE" ? $entity->getImage() : "", "id" => $entity->getUuid(), "type" => $type, "code" => trim($code)]);
}
/**
* @Route("/appBaseData/{code}/{group}/{since}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function appBaseDataAction(Request $request, $code, $group, $since = 0) {
$out = CalCommons::decodeRes($code);
if ($out === FALSE) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$entity = $this->getDoctrine()->getRepository("App\Entity\UserGroup")->findOneBy(["uuid" => $group]);
if ($entity->isDeleted())
$entity = null;
if (is_null($entity)) {
$response = new JsonResponse(["message" => "invalid entity"]);
$response->setStatusCode(404);
return $response;
}
$utime = $since / 1000;
if ($utime < strtotime("-1 year"))
$sinceTime = null;
else
$sinceTime = (new \DateTime())->setTimestamp(ceil($utime));
$version = $request->query->get("v", "last");
return new JsonResponse($this->appGetBaseData($entity, $sinceTime, "app", $version));
}
/**
* @Route("/loadStatistics/{resourceId}/{startDate}/{startInt}/{endDate}/{endInt}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function getReportStatistics(Request $request, $resourceId, $startDate, $startInt, $endDate, $endInt) {
$user = $this->getUser();
if (is_null($user)) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
$groups = $user->getGroups();
$start = (new \DateTime())->setTimestamp(ceil($startInt/1000));
$end = (new \DateTime())->setTimestamp(ceil($endInt/1000));
$startDate = new \DateTime($startDate);
$endDate = new \DateTime($endDate);
$checking = [];
$d = $this->getDoctrine();
$resource = $d->getRepository("App\Entity\Resource")->findOneBy(["uuid" => $resourceId]);
if (is_null($resource) || !$groups->contains($resource->getOwner())) {
$response = new JsonResponse(["message" => "invalid resource"]);
$response->setStatusCode(400);
return $response;
}
$betweenDateExpression = Criteria::expr()->andX(
Criteria::expr()->gte('date', $startDate),
Criteria::expr()->lte('date', $endDate)
);
$resExpression = Criteria::expr()->eq('resource', $resource);
$xExpression = Criteria::expr()->eq('deletedAt', NULL);
$groupExpression = Criteria::expr()->in('owner', $groups->map(function ($e) {
return $e->getId();
})->toArray());
$deployments = $d->getRepository("App\Entity\Deployment")->findNotDeletedByResInTimespan([$resource->getId()], $start, $end);
$absences = $d->getRepository("App\Entity\Absence")->matching(Criteria::create()->where($resExpression)->andWhere($xExpression)->andWhere($betweenDateExpression));
$exceptions = $d->getRepository("App\Entity\WorkDay")->matching(Criteria::create()->where($groupExpression)->andWhere($xExpression)->andWhere(Criteria::expr()->eq('holiday', false))->andWhere($betweenDateExpression))->map(function($x) {
return $x->getDateExport();
});
$holidays = $d->getRepository("App\Entity\WorkDay")->matching(Criteria::create()->where($groupExpression)->andWhere($xExpression)->andWhere(Criteria::expr()->eq('holiday', true))->andWhere($betweenDateExpression))->map(function($x) {
return $x->getDateExport();
});
$absenceList = [];
foreach ($absences as $absence) {
$name = $absence->getType()->getName();
$date = $absence->getDate()->format("Y-m-d");
if (!isset($absenceList[$name]))
$absenceList[$name] = [];
if (!isset($absenceList[$name][$date]))
$absenceList[$name][$date] = true;
}
$absenceList = array_map(function ($x) {
return count($x);
}, $absenceList);
$useDays = [];
foreach ($deployments as $deployment) {
$startX = $deployment->getJobStart();
if (!$startX)
continue;
$useDays[(new \DateTime())->setTimestamp(ceil($startX/1000))->format("Y-m-d")] = true;
}
$isWorkingDay = function ($momentObj) use ($holidays, $exceptions) {
$workDays = [true, true, true, true, true, false, false];
$date = $momentObj->format("Y-m-d");
$isHoliday = $holidays->contains($date);
$isException = $exceptions->contains($date);
$isWorkingDay = $workDays[$momentObj->format("N") - 1] ?? true;
$key = ($isWorkingDay ? 1 : 0) +
($isHoliday ? 2 : 0) +
($isException ? 4 : 0);
switch ($key) {
case 4:
case 6:
case 7:
case 5:
case 1:
return true;
default:
return false;
}
};
$calDays = 0;
$workDays = 0;
for (
$currentDay = clone $startDate; $currentDay <= $endDate; $currentDay->modify("+1 day")
) {
$key = $currentDay->format("Y-m-d");
$calDays++;
if (
isset($useDays[$key]) ||
$isWorkingDay($currentDay)
){
$workDays++;
}
}
return new JsonResponse([
"calDays" => $calDays,
"checking" => $checking,
"workDays" => $workDays,
"useDays" => count($useDays),
"absences" => $absenceList
]);
}
/**
* @Route("/app/{code}/{start}/{end}/{since}")
*
* @param Request $request
*
* @return JsonResponse
*
* @throws \Exception
*/
public function appAction(Request $request, $code, $start, $end, $since = 0) {
$out = CalCommons::decodeRes($code);
$data = json_decode($request->getContent(), true);
if ($out === FALSE) {
$response = new JsonResponse(["message" => "invalid token"]);
$response->setStatusCode(401);
return $response;
}
if ($out < 0) {
$type = "appUser";
$entity = $this->getDoctrine()->getRepository("App\Entity\User")->findOneBy(["bpo_id" => $out * -1]);
} else {
$type = "appResource";
$entity = $this->getDoctrine()->getRepository("App\Entity\Resource")->findOneBy(["bpo_id" => $out]);
}
if ($entity->isDeleted())
$entity = null;
if (is_null($entity)) {
$response = new JsonResponse(["message" => "invalid entity"]);
$response->setStatusCode(404);
return $response;
}
$version = $request->query->get("v", "last");
if (!empty($data["save"]))
$this->saveAll($data["save"], null, "app", $version);
$utime = $since / 1000;
if ($utime < strtotime("-1 year"))
$sinceTime = null;
else
$sinceTime = (new \DateTime())->setTimestamp(ceil($utime));
try {
$startTime = (new \DateTime())->setTimestamp(ceil($start / 1000));
$endTime = (new \DateTime())->setTimestamp(ceil($end / 1000));
} catch (Exception $e) {
$response = new JsonResponse(["message" => "invalid dates"]);
$response->setStatusCode(400);
return $response;
}
if ($type === "appUser") {
return new JsonResponse($this->getAppUser($entity, $startTime, $endTime, $sinceTime, $version));
} else if ($type === "appResource") {
return new JsonResponse($this->getAppResource($entity, $startTime, $endTime, $sinceTime, $version));
}
}
/**
* @Route("/")
*
* @param mixed $string
*
* @return JsonResponse
*/
public function noAction($string = ''): Response {
return new JsonResponse([]);
}
protected function filterByTime($collection, $since) {
return array_values(array_filter($collection, function ($x) use ($since) {
return $x->getUpdatedAt() >= $since;
}));
}
protected function filterDeleted($collection) {
return array_values(array_filter($collection, function ($x) {
return !$x->isDeleted();
}));
}
protected function export(array $x, $context = "browser", $version = "last") {
return array_values(array_map(function ($e) use ($context, $version) {
return $e->getExport($context, $version);
}, $x));
}
protected function exportColl($x, $context = "browser", $version = "last") {
return array_values($x->map(function ($e) use ($context, $version) {
return $e->getExport($context, $version);
})->toArray());
}
}