<?php
namespace Aqarmap\Bundle\ListingBundle\Controller\Api;
use App\Exception\BadRequestHttpException;
use App\Exception\LogicHttpException;
use Aqarmap\Bundle\CreditBundle\Constant\CreditStatus;
use Aqarmap\Bundle\CreditBundle\Contract\CreditManagerInterface;
use Aqarmap\Bundle\CreditBundle\Entity\Credit;
use Aqarmap\Bundle\FeatureToggleBundle\Service\FeatureToggleManager;
use Aqarmap\Bundle\ListingBundle\Constant\CountryCodes;
use Aqarmap\Bundle\ListingBundle\Constant\LeadTypes;
use Aqarmap\Bundle\ListingBundle\Constant\ListingFeaturedTypes;
use Aqarmap\Bundle\ListingBundle\Constant\ListingFeatures;
use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
use Aqarmap\Bundle\ListingBundle\Constant\ListingSyncedFields;
use Aqarmap\Bundle\ListingBundle\Constant\PhotoTypes;
use Aqarmap\Bundle\ListingBundle\Contracts\PhoneManagerInterface;
use Aqarmap\Bundle\ListingBundle\Entity\CallRequest;
use Aqarmap\Bundle\ListingBundle\Entity\Listing;
use Aqarmap\Bundle\ListingBundle\Entity\ListingNote;
use Aqarmap\Bundle\ListingBundle\Entity\ListingPhone;
use Aqarmap\Bundle\ListingBundle\Entity\ListingPhoto;
use Aqarmap\Bundle\ListingBundle\Entity\Photo;
use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;
use Aqarmap\Bundle\ListingBundle\Entity\Section;
use Aqarmap\Bundle\ListingBundle\Event\LeadEvent;
use Aqarmap\Bundle\ListingBundle\Event\ListingEvent;
use Aqarmap\Bundle\ListingBundle\Event\ListingUpdatedEvent;
use Aqarmap\Bundle\ListingBundle\Form\ContactSellerFormType;
use Aqarmap\Bundle\ListingBundle\Form\ListingApiType;
use Aqarmap\Bundle\ListingBundle\Form\ListingNoteType;
use Aqarmap\Bundle\ListingBundle\Form\PhotoType;
use Aqarmap\Bundle\ListingBundle\Form\QuickContactSellerType;
use Aqarmap\Bundle\ListingBundle\Form\QuickCreateLeadFormType;
use Aqarmap\Bundle\ListingBundle\Form\QuickLeadType;
use Aqarmap\Bundle\ListingBundle\Model\LeadModel;
use Aqarmap\Bundle\ListingBundle\Repository\ListingNoteRepository;
use Aqarmap\Bundle\ListingBundle\Repository\ListingRepository;
use Aqarmap\Bundle\ListingBundle\Service\CallLog\Logger;
use Aqarmap\Bundle\ListingBundle\Service\CallRequestManager;
use Aqarmap\Bundle\ListingBundle\Service\FavouriteService;
use Aqarmap\Bundle\ListingBundle\Service\InteractionService;
use Aqarmap\Bundle\ListingBundle\Service\LeadService;
use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
use Aqarmap\Bundle\ListingBundle\Service\ListingNoteService;
use Aqarmap\Bundle\ListingBundle\Service\ListingRateService;
use Aqarmap\Bundle\ListingBundle\Service\ListingRuleMatcher;
use Aqarmap\Bundle\ListingBundle\Service\LocationManager;
use Aqarmap\Bundle\ListingBundle\Service\Mortgage\MortgageService;
use Aqarmap\Bundle\ListingBundle\Service\NewsFeed\ListingNewsFeed;
use Aqarmap\Bundle\ListingBundle\Twig\ListingExtension;
use Aqarmap\Bundle\MainBundle\Controller\Api\BaseController;
use Aqarmap\Bundle\MainBundle\Service\Setting;
use Aqarmap\Bundle\MessageBundle\Service\Composer;
use Aqarmap\Bundle\TopSellerBundle\Model\TopSeller;
use Aqarmap\Bundle\TopSellerBundle\Service\TopSellerRetrievalService;
use Aqarmap\Bundle\UserBundle\Entity\User;
use Aqarmap\Bundle\UserBundle\Services\UserManager;
use DateTime;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use FOS\UserBundle\Model\UserManagerInterface;
use Gedmo\Translatable\TranslatableListener;
use Knp\Component\Pager\PaginatorInterface;
use Nelmio\ApiDocBundle\Annotation\Operation;
use OpenApi\Annotations as OA;
use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class ListingController.
*/
class ListingController extends BaseController
{
/**
* @var CallRequestManager
*/
private $callRequestManager;
/**
* @var ListingNewsFeed
*/
private $listingNewsFeed;
/**
* @var LoggerInterface
*/
private $errorLogger;
/**
* @var MortgageService
*/
private $mortgageService;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var Composer
*/
private $messageComposer;
/**
* @var FavouriteService
*/
private $favouriteService;
/**
* @var PaginatorInterface
*/
private $paginator;
/** @var ListingManager */
private $listingManager;
/**
* @var InteractionService
*/
private $interactionService;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/** @var FOSUserManager */
private $fosUserManager;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var TranslatableListener
*/
private $translatableListener;
/**
* @var Logger
*/
private $logger;
private UserManager $userManager;
/** @var ListingManager */
private $listingService;
/** @var ListingRateService */
private $listingRateService;
/** @var ListingNoteService */
private $listingNoteService;
/**
* @var ListingRuleMatcher
*/
private $listingRuleMatcher;
/**
* @var LocationManager
*/
private $locationManager;
/**
* @var FeatureToggleManager
*/
private $featureToggle;
/**
* @var PhoneManagerInterface
*/
private $phoneManager;
/** @var LeadService */
private $leadManager;
/** @var CreditManagerInterface */
private $creditManager;
/**
* @var ListingExtension
*/
private $listingExtension;
private EntityManagerInterface $entityManager;
public function __construct(
Composer $messageComposer,
FavouriteService $favouriteService,
PaginatorInterface $paginator,
SessionInterface $session,
InteractionService $interactionService,
ListingManager $listingManager,
EventDispatcherInterface $dispatcher,
UserManagerInterface $fosUserManager,
TranslatorInterface $translator,
TranslatableListener $translatableListener,
Logger $logger,
UserManager $userManager,
ListingManager $listingService,
ListingNoteService $listingNoteService,
ListingRuleMatcher $listingRuleMatcher,
LocationManager $locationManager,
Setting $setting,
PhoneManagerInterface $phoneManager,
FeatureToggleManager $featureToggle,
ListingRateService $listingRateService,
TokenStorageInterface $tokenStorage,
LeadService $leadManager,
CallRequestManager $callRequestManager,
MortgageService $mortgageService,
CreditManagerInterface $creditManager,
ListingExtension $listingExtension,
ListingNewsFeed $listingNewsFeed,
EntityManagerInterface $entityManager
) {
$this->messageComposer = $messageComposer;
$this->favouriteService = $favouriteService;
$this->callRequestManager = $callRequestManager;
$this->featureToggle = $featureToggle;
$this->paginator = $paginator;
$this->interactionService = $interactionService;
$this->listingManager = $listingManager;
$this->dispatcher = $dispatcher;
$this->fosUserManager = $fosUserManager;
$this->translator = $translator;
$this->translatableListener = $translatableListener;
$this->logger = $logger;
$this->userManager = $userManager;
$this->listingService = $listingService;
$this->listingNoteService = $listingNoteService;
$this->listingRuleMatcher = $listingRuleMatcher;
$this->locationManager = $locationManager;
$this->phoneManager = $phoneManager;
$this->listingRateService = $listingRateService;
$this->tokenStorage = $tokenStorage;
$this->leadManager = $leadManager;
$this->mortgageService = $mortgageService;
$this->creditManager = $creditManager;
$this->listingExtension = $listingExtension;
$this->listingNewsFeed = $listingNewsFeed;
$this->entityManager = $entityManager;
}
/**
* Get Listing.
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Listing Object",
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Get("/api/v2/listing/{id}", requirements={"id" = "\d+"}, options={"i18n" = false}, name="aqarmap_api_get_listing_v2")
*
* @Rest\View(serializerGroups={"Default", "Details", "Compound"})
*
* @Cache(
* expires="+2 hours", maxage="+2 hours", smaxage="+2 hours",
* public=false, vary={"Accept-Language", "X-Accept-Version", "Accept"}
* )
*/
public function getListing(Listing $listing): array
{
return ['listing' => $listing];
}
/**
* Listing details.
*
* @Rest\Get("/api/v4/listing/{id}", requirements={"id" = "\d+"}, options={"i18n" = false}, name="aqarmap_api_get_listing_v4")
*
* @Rest\View(serializerGroups={"listingDetails", "listingDetailsWithLocationCompound"})
*
* @Cache(
* expires="+6 hours", maxage="+6 hours", smaxage="+6 hours",
* public=true, vary={"Accept-Language", "X-Accept-Version", "Accept"}
* )
*/
public function getListingDetails(int $id, ListingRepository $listingRepository): array
{
$entityManagerFilters = $this->entityManager->getFilters();
if ($entityManagerFilters->isEnabled('softdeleteable')) {
$entityManagerFilters->disable('softdeleteable');
}
$listing = $listingRepository->find($id);
$entityManagerFilters->enable('softdeleteable');
return ['listing' => $listing];
}
/**
* Get Listing Children (Project Units).
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Listing Children",
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Get("/api/v2/listing/{id}/children", options={"i18n" = false}, name="aqarmap_api_get_listing_children_v2")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return array
*/
public function getListingChildren(Listing $listing)
{
return $this->respond($listing->getLiveChildren());
}
/**
* @Operation(
* tags={"Web API Calls"},
* summary="",
*
* @OA\Parameter(
* name="lead",
* in="query",
* description="",
* required=false,
* ),
*
* )
*
* @Rest\Post("/api/v2/listing/{listing}/phones", options={"i18n" = false}, name="aqarmap_api_get_listing_phones_v2")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return Collection
*
* @throws ORMException
* @throws OptimisticLockException
*/
public function getListingPhone(Listing $listing, Request $request, ?User $user = null)
{
$version = (float) ltrim((string) $request->headers->get('X-Accept-Version'), 'v');
$leadModel = new LeadModel();
$currentUrl = $request->getUri();
if (str_contains($currentUrl, 'v2')) {
if (!$user = $this->getUser() && $version <= 2.13) {
throw new AccessDeniedHttpException();
}
}
$form = $this->createForm(QuickLeadType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
$form->handleRequest($request);
$lead = $form->getData();
$phoneManager = $this->phoneManager;
$originalPhoneNumber = $lead['phone'];
$phoneNumber = $phoneManager->trimZero($lead['phone'], $lead['countryCode']);
$aqarmapUserService = $this->userManager;
$hasEmail = !$lead['isAutoGeneratedEmail'];
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->fosUserManager;
/** @var User $user */
$user = $userManager->findUserByEmail($lead['email']);
$countryCode = $lead['countryCode'];
if (!$user && !$hasEmail) {
$user = $aqarmapUserService->findLatestByPhone($phoneNumber, $countryCode);
}
if (!$user && $hasEmail) {
$user = $aqarmapUserService->findAndReplaceUserAndEmail($phoneNumber, $lead['email'], $countryCode);
}
if (!$user) {
$user = $userManager->createUser();
$user
->setFullName($lead['name'])
->setPhoneNumber($lead['phone'])
->setTempOriginalPhoneNumber($originalPhoneNumber)
->setTempCountryCode($lead['countryCode'])
->setEmail($lead['email'])
->setHasEmail($hasEmail)
->setLanguage('ar');
$user = $aqarmapUserService->quickRegistration($form, $user, $request);
}
$phone = $phoneManager->addNewUserPhone($phoneNumber, $lead['countryCode'], $user, true, false, null, $originalPhoneNumber);
$userManager->updateUser($user);
$userManager->reloadUser($user);
$leadModel->setPhone($phone->getPhone());
$leadModel->setName($request->request->get('name', $lead['name']));
$leadModel->setEmail($request->request->get('email', $lead['email']));
$leadService = $this->leadManager;
$leadModel->setLeadType(LeadTypes::SHOW_PHONE);
$leadModel->setListing($listing);
$leadModel->setSource('api');
$leadModel->setUser($user);
$lead = $leadService->addLead($leadModel);
if ($lead) {
$this->dispatcher->dispatch(
new LeadEvent(
$listing,
$user,
$lead
),
'aqarmap.listing.show_seller_number'
);
}
return $listing->getPhones();
}
/**
* @Operation(
* tags={"Listing"},
* summary="Send message to listing owner & set lead",
*
* @OA\Parameter(
* name="campaign",
* in="query",
* description="Campaign Name",
* required=false,
* ),
* @OA\Parameter(
* name="contact_seller",
* in="query",
* description="",
* required=false,
* ),
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Post("/api/v2/listing/{listing}/contact_seller", options={"i18n" = false}, name="aqarmap_api_listing_contact_seller_v2")
*
* @Rest\QueryParam(name="campaign", description="Campaign Name")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return bool|Form
*
* @throws AccessDeniedHttpException
*/
public function contactSeller(Request $request, Listing $listing, ?User $user = null)
{
$currentUrl = $request->getUri();
if (str_contains($currentUrl, 'v2')) {
if (!$user = $this->getUser()) {
throw new AccessDeniedHttpException();
}
}
$form = $this->createForm(ContactSellerFormType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Get campaign name
$campaign = $request->query->get('campaign');
$message = $form->getData();
// Send contact seller message and send a lead
$composer = $this->messageComposer;
$composer
->setSender($user)
->compose($message['message'], $listing, $campaign);
return true;
}
return $form;
}
/**
* @Operation(
* tags={"Listing"},
* summary="Quick register a user, send message to listing owner & set lead",
*
* @OA\Parameter(
* name="campaign",
* in="query",
* description="Campaign Name",
* required=false,
* ),
* @OA\Parameter(
* name="contact_seller",
* in="query",
* description="",
* required=false,
* ),
*
* @OA\Response(
* response="201",
* description="Returned when user created and message sent successfully"
* ),
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* ),
* @OA\Response(
* response="403",
* description="Returned when parameter is missing"
* )
* )
*
* @Rest\Post("/api/v2/listing/{listing}/contact_seller/quick", options={"i18n" = false}, name="aqarmap_api_listing_quick_contact_seller_v2")
*
* @Rest\QueryParam(name="campaign", description="Campaign Name")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return Response $response
*
* @throws \Exception
*/
public function contactSellerWithQuickRegistration(Request $request, Listing $listing): Response
{
if (!$this->isValidQuickContactSellerParameters($request->get('contact_seller'))) {
return new Response(null, Response::HTTP_FORBIDDEN);
}
$form = $this->createForm(QuickContactSellerType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && !$form->isValid()) {
return new Response(null, Response::HTTP_FORBIDDEN);
}
$userManager = $this->userManager;
$fromData = $form->getData();
$user = $userManager->createQuickUser($request, $form);
$campaign = $request->query->get('campaign');
$composer = $this->messageComposer;
$composer
->setSender($user)
->compose($fromData['message'], $listing, $campaign);
return new Response(null, Response::HTTP_CREATED);
}
private function isValidQuickContactSellerParameters(array $parameters): bool
{
if (
!\array_key_exists('email', $parameters)
|| !\array_key_exists('phone', $parameters)
|| !\array_key_exists('countryCode', $parameters)
) {
return false;
}
return true;
}
/**
* @Operation(
* tags={"Listing"},
* summary="",
*
* )
*
* @Rest\Post("/api/v2/listing/{listing}/call_request", options={"i18n" = false}, name="aqarmap_api_listing_call_request_v2")
*
* @Rest\QueryParam(name="campaign", description="Campaign Name")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return bool|array
*/
public function callRequest(Listing $listing, Request $request, ?User $user = null)
{
$version = (float) ltrim((string) $request->headers->get('X-Accept-Version'), 'v');
$callRequest = new CallRequest();
$currentUrl = $request->getUri();
if (str_contains($currentUrl, 'v2')) {
if (!$user = $this->getUser() && $version <= 2.13) {
throw new AccessDeniedHttpException();
}
}
$form = $this->createForm(QuickLeadType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
$form->handleRequest($request);
$lead = $form->getData();
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->fosUserManager;
$aqarmapUserManager = $this->userManager;
$hasEmail = !$lead['isAutoGeneratedEmail'];
$phoneManager = $this->phoneManager;
$originalPhoneNumber = $lead['phone'];
$countryCode = $lead['countryCode'];
$phoneNumber = $phoneManager->trimZero($lead['phone'], $countryCode);
/** @var User $user */
$user = $userManager->findUserByEmail($lead['email']);
if (!$user && !$hasEmail) {
$user = $aqarmapUserManager->findLatestByPhone($phoneNumber, $countryCode);
}
if (!$user && $hasEmail) {
$user = $aqarmapUserManager->findAndReplaceUserAndEmail($phoneNumber, $lead['email'], $countryCode);
}
if (!$user) {
$user = $userManager->createUser();
$user
->setFullName($lead['name'])
->setPhoneNumber($lead['phone'])
->setTempOriginalPhoneNumber($originalPhoneNumber)
->setTempCountryCode($lead['countryCode'])
->setEmail($lead['email'])
->setHasEmail($hasEmail)
->setLanguage('ar');
$user = $aqarmapUserManager->quickRegistration($form, $user, $request);
}
$phone = $phoneManager->addNewUserPhone($phoneNumber, $lead['countryCode'], $user, true, false, null, $originalPhoneNumber);
$userManager->updateUser($user);
$userManager->reloadUser($user);
$callRequest->setPhone($phone->getPhone());
$callRequest->setLeadFullName($request->request->get('name'));
$callRequest->setLeadEmail($request->request->get('email'));
$campaign = $request->request->get('campaign');
$callRequest->setUser($user);
$callRequest->setListing($listing);
$this->callRequestManager->submitCallRequest($callRequest, $campaign);
return true;
}
/**
* Add New User Listing.
*
* @Operation(
* tags={"Listing"},
* summary="Add New User Listing.",
*
* @OA\Parameter(
* name="listing",
* in="query",
* description="",
* required=false,
* ),
*
* @OA\Response(
* response="201",
* description="Returned when successfully created"
* ),
* @OA\Response(
* response="400",
* description="Returned when validation error"
* )
* )
*
* @Rest\Post("/api/v2/listing", options={"i18n" = false}, name="aqarmap_api_add_listing")
*
* @Security("is_granted('ROLE_USER')")
*
* @return View|Form
*/
public function addListing(Request $request)
{
$form = $this->createForm(ListingApiType::class, $listing = new Listing(), [
'csrf_protection' => false,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($this->getUser()->getPhoneNumber()) {
$listing->addPhone(new ListingPhone($this->getUser()->getPhoneNumber()));
}
$listingManager = $this->listingService;
$listing->setUser($this->getUser());
$listing->setStatus(ListingStatus::DRAFT);
$listingManager->saveListing($listing);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
return View::create()->setData($listing)->setStatusCode(Response::HTTP_CREATED);
}
return View::create()->setData($form)->setStatusCode(Response::HTTP_BAD_REQUEST);
}
/**
* Create Single Listing Note.
*
* @Rest\Post("/api/v2/listing/{id}/note", options={"i18n" = false})
*
* @Rest\RequestParam(name="body", description="Note Body")
* @Rest\RequestParam(name="source", description="Supported sources: 1 = Website, 2 = Consumer App, 3 = Live App")
* @Rest\RequestParam(name="last_modified_at", description="dateTime")
* @Rest\RequestParam(name="created_at", description="dateTime")
*
* @ParamConverter("Listing", options={"mapping": {"listing": "id"}}, converter="querystring")
*
* @Security("is_granted('ROLE_USER')")
*/
public function postListingSingleNote(Request $request, Listing $listing, ListingNoteRepository $listingNoteRepository, EntityManagerInterface $em)
{
$currentUser = $this->getUser();
$listingNote = $listingNoteRepository->findOneBy([
'user' => $currentUser,
'listing' => $listing,
]);
if (empty($listingNote)) {
$listingNote = new ListingNote();
$listingNote->setUser($currentUser);
$listingNote->setListing($listing);
$listingNote->setCreatedAt(new \DateTime());
}
$form = $this->createForm(ListingNoteType::class, $listingNote);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($listingNote);
$em->flush();
return $this->json([
'message' => 'Successfully submitted',
], Response::HTTP_CREATED);
}
return $this->json([
'message' => 'Error occurred',
], Response::HTTP_BAD_REQUEST);
}
/**
* Create Bulk Listing Note.
*
* @Rest\Post("/api/v2/listing/note", options={"i18n" = false})
*
* @Security("is_granted('ROLE_USER')")
*
* @return array
*/
public function postListingBulkNote(Request $request)
{
$listingNoteService = $this->listingNoteService;
$listingNoteService->addBulk($request);
return $this->respond('Note Added Successfully!');
}
/**
* Update Listing.
*
* @Operation(
* tags={"Listing"},
* summary="Update Listing.",
*
* @OA\Parameter(
* name="listing",
* in="query",
* description="",
* required=false,
* ),
*
* @OA\Response(
* response="200",
* description="Returned when successfully Updated"
* ),
* @OA\Response(
* response="400",
* description="Returned when validation error"
* )
* )
*
* @Rest\Post("/api/v2/listing/{id}", options={"i18n" = false}, name="aqarmap_api_update_listing")
*
* @Rest\View
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @return View|Form
*/
public function updateListing(Listing $listing, Request $request)
{
$listing->clearAttributes();
$form = $this->createForm(ListingApiType::class, $listing, [
'csrf_protection' => false,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($this->getUser()->getPhoneNumber()) {
$listing->addPhone(new ListingPhone($this->getUser()->getPhoneNumber()));
}
$listingManager = $this->listingService;
$listingManager->saveListing($listing);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
return View::create()->setData($listing)->setStatusCode(Response::HTTP_OK);
}
return View::create()->setData($form)->setStatusCode(Response::HTTP_BAD_REQUEST);
}
/**
* Upload listing photos.
*
* @Operation(
* tags={"Listing"},
* summary="Upload listing photos.",
*
* @OA\Parameter(
* name="photos",
* in="query",
* description="",
* required=false,
* ),
*
* @OA\Response(
* response="201",
* description="Returned when successfully created"
* ),
* @OA\Response(
* response="400",
* description="Returned when validation error"
* )
* )
*
* @Rest\Post("/api/v2/listing/{id}/photos", options={"i18n" = false}, name="aqarmap_api_upload_listing_photos")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @return View|array
*/
public function upload(Request $request, Listing $listing)
{
$form = $this->createForm(PhotoType::class, null, [
'csrf_protection' => false,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$outputFiles = [];
$listingManager = $this->listingService;
$maxOrder = $listingManager->getMaxListingPhotoOrder($listing);
foreach ($form->get('file')->getData() as $index => $file) {
$photo = new Photo();
$photo->setFile($file);
$listingPhoto = new ListingPhoto();
$listingPhoto->setFile($photo);
$listingPhoto->setCaption($photo->getFile()->getClientOriginalName());
$listingPhoto->setOrder($maxOrder + $index + 1);
$outputFiles[] = $listingPhoto;
$listing->addPhoto($listingPhoto);
}
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
$listingManager->saveListing($listing);
return View::create()->setData($outputFiles)->setStatusCode(Response::HTTP_CREATED);
}
return [
'listing' => $listing,
'form' => $form->createView(),
];
}
/**
* Delete Listing entity.
*
* @Operation(
* tags={"Listing"},
* summary="Delete Listing entity.",
*
* @OA\Response(
* response="204",
* description="Returned when successfully Deleted"
* ),
* @OA\Response(
* response="404",
* description="Returned when Listing is not found"
* ),
* @OA\Response(
* response="403",
* description="Returned when you are trying to remove listing that not yours."
* )
* )
*
* @Rest\Delete("/api/v2/listing/{listing}", options={"i18n" = false}, name="aqarmap_api_delete_listing")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*/
public function delete(Listing $listing)
{
if (\in_array('ROLE_PREVENT_DELETE_LISTING', $this->getUser()->getRoles())) {
throw new AccessDeniedHttpException("Forbidden, user don't have this permession.");
}
$listingManager = $this->listingService;
$listingManager->remove($listing, ListingStatus::USER_DELETED);
return new Response(null, Response::HTTP_NO_CONTENT);
}
/**
* Undelete Listing entity.
*
* @Operation(
* tags={"Listing"},
* summary="Undelete Listing entity.",
*
* @OA\Response(
* response="200",
* description="Returned when successfully undeleted"
* ),
* @OA\Response(
* response="404",
* description="Returned when Listing is not found or is not on user deleted state"
* ),
* @OA\Response(
* response="403",
* description="Returned when you are trying to remove listing that not yours."
* )
* )
*
* @Rest\get("/api/v2/listing/{listing}/undelete", options={"i18n" = false}, name="aqarmap_api_undelete_listing")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @Rest\View()
*
* @return array
*/
public function undelete(Listing $listing)
{
if (ListingStatus::USER_DELETED != $listing->getStatus()) {
throw $this->createNotFoundException('Unable to find this listing.');
}
$listingManager = $this->listingService;
$listingManager->changeStatus($listing, ListingStatus::PENDING);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.resubmitted');
return ['listing' => $listing];
}
/**
* Republish Listing entity.
*
* @Operation(
* tags={"Listing"},
* summary="Republish Listing entity.",
*
* @OA\Response(
* response="200",
* description="Returned when successfully Republished"
* ),
* @OA\Response(
* response="404",
* description="Returned when Listing is not found or is not on Expired state"
* ),
* @OA\Response(
* response="403",
* description="Returned when you are trying to Republish listing that not yours."
* )
* )
*
* @Rest\get("/api/v2/listing/{listing}/relist", options={"i18n" = false}, name="aqarmap_api_republish_listing")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @Rest\View()
*
* @return array
*/
public function relist(Listing $listing)
{
if (ListingStatus::EXPIRED != $listing->getStatus()) {
throw $this->createNotFoundException('Unable to find this listing.');
}
$em = $this->getDoctrine()->getManager();
$listingRepo = $em->getRepository(Listing::class);
$relistChild = $listingRepo->getRelistChild($listing);
// If the expired listing already republished before .. return the republished version.
if ($relistChild) {
return ['listing' => $relistChild];
}
$listingManager = $this->listingService;
$listing = $listingManager->relist($listing);
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.resubmitted');
return ['listing' => $listing];
}
/**
* Feature A Listing.
*
* @Operation(
* tags={"Listing"},
* summary="Remove listing from favourite",
*
* )
*
* @Rest\Post("/api/v2/listing/{listing}/feature", options={"i18n" = false}, name="aqarmap_api_feature_listing")
*
* @Rest\RequestParam(name="type", description="Feature Type, 1 for payment, 2 for making it featured")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @return View
*/
public function feature(Listing $listing, Request $request)
{
$type = $request->get('type');
if (!$type) {
throw new BadRequestHttpException('Please Specify the feature type');
}
$matcher = $this->listingRuleMatcher;
$listingRule = $matcher->match($listing);
$translator = $this->translator;
$featuredDuration = $listingRule['featured_duration'];
$featuredFees = $listingRule['featured_fees'];
if (ListingFeatures::FEATURED == $type) {
// Check if there is a value for featured_duration & featured_fees
if (empty($featuredDuration) || empty($featuredFees)) {
throw new LogicHttpException($translator->trans('Making a listing Featured is not available for this listing.', [], 'exceptions'));
}
try {
$this->listingService->makeItFeatured(
$listing,
[
'featuredFees' => $featuredFees,
'featuredDuration' => $featuredDuration,
'listingFeaturedType' => ListingFeaturedTypes::FEATURED,
'listingFeature' => $type,
]
);
} catch (\Exception $e) {
throw new LogicHttpException($translator->trans($e->getMessage(), [], 'exceptions'));
}
} elseif (ListingFeatures::PAID == $type) {
/** @var \Aqarmap\Bundle\CreditBundle\Services\CreditManager $creditManager */
$creditManager = $this->creditManager;
if ($listing->getPublicationCredit()) {
throw new LogicHttpException($translator->trans('credit.already_paid'));
} elseif ($listingRule['publication_fees'] > $creditManager->getBalance($listing->getUser())) {
throw new LogicHttpException($translator->trans('credit.not_enough_credits'));
}
// Subtract publication fees
$credits = $creditManager->deduction($listing->getUser(), $listingRule['publication_fees'], 'Listing Fees', CreditStatus::PENDING);
foreach ($credits as $credit) {
if ($credit instanceof Credit) {
$this->listingService->addFeature($listing, ListingFeatures::PAID, null, $credit);
}
}
$listingEvent = new ListingEvent($listing);
$this->dispatcher->dispatch($listingEvent, 'aqarmap.listing.submitted');
}
return View::create()->setData(['listing' => $listing]);
}
// -------------------------------------------------------------------------//
// ++++++++++++++ Quick contact seller & call request Actions +++++++++++++++//
// -------------------------------------------------------------------------//
/**
* @Operation(
* tags={"Listing"},
* summary="Returns Rules for a specific listing",
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Post("/api/v2/listing/{listing}/quick_create_lead", options={"i18n" = false}, name="aqarmap_api_listing_quick_create_lead")
*
* @Rest\QueryParam(name="campaign", description="Campaign Name")
* @Rest\QueryParam(name="country_code", default=null, description="Country Code")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return bool|Form|array
*
* @throws AccessDeniedHttpException
*
* ===============================================================
* |
* | DEPRECATED: USE QuickCreateLeadAction::LeadController instead
* |
* ===============================================================
*/
public function quickCreateLead(Request $request, Listing $listing)
{
$form = $this->createForm(QuickCreateLeadFormType::class, null, [
'method' => 'POST',
'csrf_protection' => false,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$lead = $form->getData();
/** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->fosUserManager;
$leadModel = new LeadModel();
try {
/** @var User $user */
if ($user = $userManager->findUserByEmail($form->get('email')->getData())) {
$phone = $this->phoneManager->addNewUserPhone(
$lead['phoneNumber'],
'+'.str_replace(' ', '', $request->get('country_code')),
$user,
true,
true,
CountryCodes::getCountryFromCodeNumber('+'.str_replace(' ', '', $request->get('country_code'))),
$lead['phoneNumber']
);
$userManager->updateUser($user);
$leadModel->setUser($user);
} else {
$user = $userManager->createUser();
$user
->setFullName($lead['fullName'])
->setEmail($lead['email'])
->setLanguage($request->getLocale());
$user = $this->userManager->quickRegistration($form, $user, $request);
$phone = $this->phoneManager->addNewUserPhone(
$lead['phoneNumber'],
'+'.str_replace(' ', '', $request->get('country_code')),
$user,
true,
true,
CountryCodes::getCountryFromCodeNumber('+'.str_replace(' ', '', $request->get('country_code'))),
$lead['phoneNumber']
);
$userManager->reloadUser($user);
$leadModel->setUser($user);
}
} catch (\Exception $e) {
return [
'status' => 'error',
'message' => 'Cannot create a user.',
];
}
if ($user) {
try {
$leadModel->setEmail($lead['email']);
$leadModel->setName($lead['fullName']);
$leadModel->setPhone($phone->getPhone());
$leadModel->setCampaign($request->request->get('campaign'));
$leadModel->setMessage($form->get('message')->getData());
$leadModel->setListing($listing);
$this->listingService->quickCreateLead($leadModel);
return [
'status' => 'ok',
];
} catch (\Exception $e) {
return [
'status' => 'error',
'message' => 'Cannot create the lead.',
];
}
}
}
return $form;
}
/**
* Get Listing Rules.
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Note for a specific listing",
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Get("/api/v2/listing/{id}/rules", options={"i18n" = false}, name="aqarmap_api_get_listing_rules")
*
* @Security("is_granted('ROLE_OWNER', listing)")
*
* @Rest\View()
*
* @return array
*/
public function getListingRules(Listing $listing)
{
$listingMatcher = $this->listingRuleMatcher;
$rules = $listingMatcher->match($listing);
return ['rules' => $rules];
}
/**
* Get Listing Note.
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Listing",
*
* @OA\Parameter(
* name="propertyType",
* in="query",
* description="propertyType of the unites",
* required=false,
* ),
* @OA\Parameter(
* name="section",
* in="query",
* description="Section of the unites",
* required=false,
* ),
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Get("/api/v2/listing/{id}/note", options={"i18n" = false}, name="aqarmap_api_get_listing_note")
*
* @Security("is_granted('ROLE_USER')")
*
* @Rest\View()
*
* @return array
*/
public function getListingNote(Listing $listing)
{
/** @var EntityManager $em */
$em = $this->getDoctrine()->getManager();
$listingNoteRepo = $em->getRepository(ListingNote::class);
return $listingNoteRepo->findOneBy([
'user' => $this->getUser(),
'listing' => $listing,
]);
}
/**
* Get account statistics (Listings Statistics).
*
* @Operation(
* tags={"User"},
* summary="Get account statistics (Listings Statistics).",
*
* )
*
* @Rest\Get("/api/user/listings/statistics", requirements={"id":"\d+"}, options={"expose" = true, "i18n" = false}, name="aqarmap_api_get_user_listings_rates_counts")
*
* @Rest\Post("/api/v2/user/listings/statistics", options={"i18n" = false}, name="aqarmap_api_get_user_listings_rates_counts_v2")
*
* @ParamConverter("user", options={"mapping": {"user": "id"}}, isOptional="true", converter="querystring")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @Security("is_granted('ROLE_USER')")
*
* @throws \Exception
*/
public function getUserListingsRatesCounts(Request $request, ?User $user = null): View
{
$isSubAccount = null != $user && $this->getUser() === $user->getParent();
$startDate = null;
$period = $request->query->get('period', null);
if (!$this->getUser() && !$isSubAccount) {
throw new AccessDeniedHttpException();
}
$user = $user ?: $this->getUser();
if ('7Days' == $period) {
$startDate = date('Y-m-d', strtotime('-7 days'));
} elseif ('30Days' == $period) {
$startDate = date('Y-m-d', strtotime('-30 days'));
}
return $this->respond([
'rates' => $this->listingService->getUserListingsRatesCounts($user, $startDate, $period),
]);
}
/**
* Generates XML file for Listings News feed for marketing purpose.
*
* @Operation(
* tags={"Listing"},
* summary="Generates XML file for Listings News feed for marketing purpose.",
*
* )
*
* @Rest\Get(
* "/api/listings/feed/{platform}",
* options={"expose" = true, "i18n" = false},
* name="aqarmap_api_get_listings_news_feed",
* defaults={"page"=1}
* )
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @return Response
*/
public function getNewsFeed($platform, Request $request)
{
$criteria = [];
$page = min($request->query->get('page') ?: 1, ListingNewsFeed::MAX_PAGES);
$limit = min($request->query->get('limit', 100), 100);
if ((int) $request->query->get('page', 1) > $page) {
throw new NotFoundHttpException('Exceeded maximum number of pages');
}
if ($request->query->get('ugc')) {
$data = explode(',', $request->query->get('ugc'));
$data = array_map('intval', $data);
$criteria['groupCategory'] = array_filter($data);
}
if ($request->query->get('ug')) {
$data = explode(',', $request->query->get('ug'));
$data = array_map('intval', $data);
$criteria['userGroup'] = array_filter($data);
}
if ($request->query->get('hl')) {
$criteria['locale'] = $request->query->get('hl');
}
if ($request->query->get('maxlead')) {
$criteria['maxlead'] = $request->query->get('maxlead');
}
if ($request->query->get('feat')) {
$criteria['feat'] = $request->query->get('feat');
}
if ($request->query->get('location')) {
$locations = $this->locationManager
->buildLocationsArrayByParentId($request->query->get('location'));
if (!empty($locations)) {
$criteria['locations'] = $locations;
}
}
if ($request->query->get('section')) {
$data = explode(',', $request->query->get('section'));
$data = array_map('intval', $data);
$criteria['sections'] = array_filter($data);
}
$news = $this->listingNewsFeed;
$offset = ($page - 1) * $limit;
$excludedKeys = ['sections', 'maxlead'];
if (!array_diff(array_keys($criteria), $excludedKeys)) {
throw new BadRequestHttpException(sprintf('The request must contain parameters others than the following: %s', implode(', ', $excludedKeys)));
}
if ('json' == $request->query->get('format')) {
return $this->responseJson($news->asJson($offset, $limit, $criteria));
}
return $this->responseXml($news->asXml($offset, $limit, $platform, $criteria));
}
/**
* Get call log.
*
* @deprecated
*
* @Operation(
* tags={"Listing"},
* summary="Get call log.",
*
* )
*
* @Rest\Get(
* "/api/listings/calllog",
* options={"expose" = true, "i18n" = false},
* name="aqarmap_api_get_listings_calllog"
* )
*
* @Rest\View(serializerGroups={"CallLog"})
*
* @return Response
*/
public function getCallLog(Request $request)
{
$this->translatableListener->setTranslatableLocale($request->get('lang'));
$em = $this->getDoctrine()->getManager();
$listings = $em
->getRepository(Listing::class)
->getByIds($this->logger->get());
return View::create()->setData($listings);
}
/**
* Remove call log.
*
* @Operation(
* tags={"Listing"},
* summary="Remove call log.",
*
* )
*
* @Rest\Post(
* "/api/listings/calllog",
* options={"expose" = true, "i18n" = false},
* name="aqarmap_api_remove_listings_calllog"
* )
*
* @Rest\View
*
* @return Response
*/
public function removeCallLog()
{
$this->logger->remove();
return View::create()->setData([]);
}
/**
* update listing fields.
*
* @Rest\Post("api/listing/{id}/edit", options={"i18n" = false, "expose" = true}, name="update_listing_field")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*
* @Security("is_granted('ROLE_EDIT_REVIEW_LISTINGS')")
*
* @return View
*/
public function update(Listing $listing, Request $request)
{
$listingManager = $this->listingManager;
$isEnabled = $this->featureToggle
->isEnabled('web.mortgage.options');
$mortgage = $request->get('eligibleForMortgage');
$fields = $request->request->all();
if ($isEnabled) {
if (true == $mortgage) {
$this->mortgageService->addEligibleMortgageTypes($listing);
} else {
$listingManager->setEligibleMortgageToNull($listing);
}
unset($fields['eligibleForMortgage']);
}
$this->dispatcher->dispatch(
new ListingUpdatedEvent($listing, $fields),
ListingUpdatedEvent::UPDATED
);
$listing = $listingManager->update($listing, $fields);
if ($listing->getStatus() == ListingStatus::LIVE){
$listingManager->changeStatus($listing, ListingStatus::PENDING);
}
return $this->respond([
'listing' => $listing,
'msg' => 'Listing was updated successfully',
]);
}
/**
* Get Photos Of The Given Listings.
*
* @Operation(
* tags={"Listing"},
* summary="Get Photos Of The Given Listings.",
*
* )
*
* @Rest\Get(
* "/api/listings/{listing}/photos",
* options={"expose" = true, "i18n" = false},
* name="aqarmap_api_get_listing_photos",
* )
*
* @return Response
*/
public function getListingPhotos(Listing $listing)
{
$listingPhotos = $listing->getPhotos();
$listingPhotosData = [];
foreach ($listingPhotos as $listingPhoto) {
$listingPhotosData[] = [
'id' => $listingPhoto->getId(),
'type' => $listingPhoto->getType(),
'caption' => $listingPhoto->getCaption(),
'file' => $listingPhoto->getFile(),
];
}
return $this->respond($listingPhotosData);
}
/**
* Get Photo Types.
*
* @Operation(
* tags={"Listing"},
* summary="Get Photo Types.",
*
* )
*
* @Rest\Get(
* "/api/listings/photoTypes",
* options={"expose" = true, "i18n" = false},
* name="aqarmap_api_get_listing_photo_types",
* )
*
* @return Response
*/
public function getPhotoTypes()
{
return $this->respond(PhotoTypes::getPhotoTypes());
}
/**
* Upload Listing Photo.
*
* @Operation(
* tags={"Listing"},
* summary="Upload Listing Photo.",
*
* )
*
* @Rest\Post(
* "/api/listing/{id}/upload_photo",
* options={"expose" = true, "i18n" = false},
* name="aqarmap_api_admin_upload_listing_photo",
* )
*
* @return array
*
* @throws OptimisticLockException
*/
public function uploadListingPhoto(Listing $listing)
{
$outputFiles = [];
$listingManager = $this->listingManager;
$maxOrder = $listingManager->getMaxListingPhotoOrder($listing);
$photo = new Photo();
$file = $_FILES['file'];
$file = new UploadedFile($file['tmp_name'], $file['name'], $file['type']);
$photo->setFile($file);
$listingPhoto = new ListingPhoto();
$listingPhoto->setFile($photo);
$listingPhoto->setCaption($photo->getFile()->getClientOriginalName());
$listingPhoto->setOrder($maxOrder + 1);
$outputFiles[] = $listingPhoto;
$listing->addPhoto($listingPhoto);
$em = $this->getDoctrine()->getManager();
$em->persist($listing);
$em->flush();
return $this->respond(['status' => 'OK']);
}
/**
* Gets rate details of listing.
*
* @Operation(
* tags={"Listing"},
* summary="Gets rate details of listing.",
*
* )
*
* @Rest\Get("/api/v2/listing/{listing}/rates", options={"i18n" = false})
* @Rest\Get("/api/listing/{listing}/rates", options={"expose" = true, "i18n" = false}, name="aqarmap_api_listing_rates_details")
*
* @Rest\View(serializerGroups={"Rates"})
*
* @Cache(
* expires="+1 week",
* maxage="+1 week",
* smaxage="+1 week",
* public=false,
* vary={"Accept-Language",
* "X-Accept-Version", "Accept"}
* )
*/
public function getRateDetails(Listing $listing)
{
return $this->respond(
current($this->listingRateService->getRatesDetails([$listing]))
);
}
/**
* @Operation(
* tags={"Listing"},
* summary="",
*
* )
*
* @Rest\Get("/api/v2/listing/{listing}/preview", options={"i18n" = false})
* @Rest\Get("/api/listing/{listing}/preview", options={"expose" = true, "i18n" = false}, name="aqarmap_api_listing_preview_data")
*
* @Rest\View(serializerGroups={"Preview"})
*
* @return View
*/
public function getListingPreviewData(Listing $listing)
{
return $this->respond($listing);
}
/**
* @Operation(
* tags={"Lead"},
* summary="Return Lead Distribution Analytics",
*
* )
*
* @Rest\Get("/api/listing/{listing}/lead-analytics",
* options={"i18n"=false, "expose"=true},
* name="aqarmap_api_listing_lead_analytics")
*
* @return JsonResponse
*
* @throws \Exception
*/
public function getLeadAnalytics(Listing $listing)
{
$analytics = $this->listingService->getLeadAnalytics($listing);
return $this->respond($analytics);
}
/**
* @Operation(
* tags={"Listing"},
* summary="Remove listing from favourite",
*
* )
*
* @Rest\Delete("/api/v2/listing/{listing}/favourite", options={"i18n" = false})
* @Rest\Delete("/api/listing/{listing}/favourite", options={"i18n" = false, "expose" = true}, name="aqarmap_api_remove_favourite_listing")
*
* @Security("is_granted('ROLE_USER')")
*
* @return string
*/
public function deleteFavourite(Request $request)
{
$this->favouriteService->deleteByListing($request->attributes->get('listing'));
return $this->respond('Favourite Deleted Successfully!');
}
/**
* @Operation(
* tags={"Listing"},
* summary="Remove listing note",
*
* )
*
* @Rest\Delete("/api/v2/listing/{listing}/note", options={"i18n" = false})
* @Rest\Delete("/api/listing/{listing}/note", options={"i18n" = false, "expose" = true}, name="aqarmap_api_remove_listing_note")
*
* @Security("is_granted('ROLE_USER')")
*
* @return string
*/
public function deleteNote(Request $request)
{
$this->listingNoteService->deleteByListing($request->attributes->get('listing'));
return $this->respond('Note Deleted Successfully!');
}
/**
* @Operation(
* tags={"Listing"},
* summary="Change listing rate review",
*
* )
*
* @Rest\Post("/api/listing/{listing}/rate-review", options={"i18n" = false, "expose" = true}, name="aqarmap_api_change_listing_rate_review_status")
*
* @Security("is_granted('ROLE_ADMIN')")
*
* @return string
*/
public function rateReview(Request $request, Listing $listing)
{
$this->listingService->updateIsRateReviewed($listing, $request->request->get('isReviewed'));
return $this->respond('Listing rate review status changed successfully');
}
/**
* Get Similar Listings Count.
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Listing Count",
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Get("/api/listing/{id}/similar_listings_count", options={"i18n" = false, "expose" = true}, name="aqarmap_api_get_similar_listings_count")
*
* @Rest\View(serializerGroups={"Default", "Details"})
*/
public function getSimilarListingsCount(Listing $listing): int
{
$listingManager = $this->listingService;
try {
$count = $listingManager->countSimilarListings($listing);
} catch (\Exception $exception) {
echo $exception->getMessage();
$this->errorLogger->error(shell_exec("Error retriving similar listings count! {$exception->getMessage()}"));
$count = 0;
}
return $count;
}
/**
* ApiDoc(
* resource = true,
* section = "Listing",
* description="Get Listings Objects with notes",
* statusCodes={
* 200="Returned when successful",
* }
* ).
*
* @Rest\Get("/api/v2/listings/notes", options={"i18n" = false})
* @Rest\Get("/api/listings/notes", options={"i18n" = false, "expose" = true}, name="aqarmap_api_listing_notes_and_favourites")
*
* @Rest\QueryParam(name="from", description="[favourites|notes]")
*
* @Rest\View(serializerGroups={"Default", "List"})
* )
*
* @return array
*/
public function getListingsWithNotes(Request $request)
{
$listingsIdWithNotes = [];
if ($content = $request->getContent()) {
$listingsIdWithNotes = json_decode($content, true);
}
$listings = $this->getDoctrine()->getRepository(Listing::class)
->getByIdsQuery(array_column($listingsIdWithNotes, 'listingId'));
$pagination = $this->paginator->paginate(
$listings,
$request->query->get('page', 1),
$request->query->get('limit', 10)
);
$data = $this->listingService->setStaticNotesFromPaginator($pagination, $listingsIdWithNotes);
if ('favourites' == $request->query->get('from')) {
return ['favourite' => $data];
}
return ['note' => $data];
}
/**
* ApiDoc(
* resource = true,
* section = "Listing",
* description="Get ApprovalRejectionWaitingTime",
* statusCodes={
* 200="Returned when successful",
* }
* ).
*
* @Rest\Get("/api/listing/arwt", options={"i18n" = false, "expose" = true}, name="aqarmap_api_listing_arwt")
*
* @Rest\View()
* )
*
* @return array
*
* @throws \Exception
*/
public function getApprovalRejectionWaitingTime(Request $request)
{
$criteria = array_merge(
$request->query->all(),
['actionTime' => true]
);
$listingManager = $this->listingService;
$listingExtension = $this->listingExtension;
return [
'arwt' => $listingExtension->waited($listingManager->getApprovalRejectionWaitingTime($criteria)),
];
}
/**
* filter Listing Children with property type (Project Units).
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Listing Children",
*
* @OA\Parameter(
* name="propertyType",
* in="query",
* description="propertyType of the unites",
* required=false,
* ),
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Get("/api/listing/{id}/children", options={"i18n" = false}, name="aqarmap_api_get_listing_children")
*
* @Rest\QueryParam(name="propertyType", description="propertyType of the unites")
*
* @ParamConverter("propertyType", options={"mapping": {"propertyType": "id"}}, isOptional="true", converter="querystring")
*
* @Rest\View(serializerGroups={"UnitDetails"})
*
* @return array
*/
public function filterListingChildren(Listing $listing, ?PropertyType $propertyType = null): View
{
if (!$this->getUser()) {
throw new AccessDeniedHttpException();
}
return $this->respond($listing->getLiveChildren($propertyType));
}
/**
* Api for clonning listing.
*
* @Operation(
* tags={"Listing"},
* summary="Returns a Listing",
*
* @OA\Parameter(
* name="propertyType",
* in="query",
* description="propertyType of the unites",
* required=false,
* ),
* @OA\Parameter(
* name="section",
* in="query",
* description="Section of the unites",
* required=false,
* ),
*
* @OA\Response(
* response="404",
* description="Returned when the listing is not found"
* )
* )
*
* @Rest\Post("/api/listing/{id}/clone", options={"i18n" = false}, name="aqarmap_api_clone_listing_children")
* @Rest\Post("/api/v2/listing/{id}/clone", options={"i18n" = false}, name="aqarmap_api_v2_clone_listing_children")
*
* @Rest\RequestParam(name="propertyType", description="propertyType of the unites")
* @Rest\RequestParam(name="section", description="Section of the unites")
*
* @ParamConverter("propertyType", options={"mapping": {"propertyType": "id"}}, converter="querystring")
* @ParamConverter("section", options={"mapping": {"section": "id"}}, converter="querystring")
*
* @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
*
* @Rest\View(serializerGroups={"UnitDetails"})
*/
public function cloneListing(Listing $sourceListing, PropertyType $propertyType, Section $section): View
{
$syncedFields = $sourceListing->getParent() ? ListingSyncedFields::UNIT_FIELDS : ListingSyncedFields::PARENT_FIELDS;
try {
$listing = $this->listingManager->initializeListingForCloning($sourceListing, $propertyType, $section, $this->getUser());
$this->listingManager->syncListingForProject(
[
'targetListingId' => $listing->getId(),
'sourceListingId' => $sourceListing->getId(),
'syncedFields' => $syncedFields,
'targetListingSavedAt' => $listing->getUpdatedAt()->getTimestamp(),
]
);
return $this->respond($listing->getId());
} catch (\Exception $e) {
throw new \Exception('something went wrong');
}
}
/**
* @Rest\Get("/api/v2/listing/{listing}/top-seller", options={"i18n" = false}, name="aqarmap_api_listing_top_seller")
*
* @Rest\View(serializerGroups={"TopCustomers"})
*/
public function getListingTopSeller(Listing $listing, TopSellerRetrievalService $topSellerRetrievalService)
{
$topSeller = new TopSeller();
$topSeller->setLocation($listing->getLocation()->getId());
$topSeller->setSection($listing->getSection()->getId());
$topSeller->setPropertyType($listing->getPropertyType()->getId());
return $topSellerRetrievalService->getTopSellerPersonalData($topSeller);
}
/**
* @Rest\Get("/api/v2/listing/{listing}/related-listings", options={"i18n" = false}, name="aqarmap_api_listing_related_listings")
*
* @Cache(expires="+1 days", maxage="+1 days", smaxage="+1 days", public=true, vary={"Accept-Language", "X-Accept-Version", "Accept"})
*
* @Rest\View(serializerGroups={"RelatedListingsV2"})
*/
public function getRelatedListing(Listing $listing, ListingManager $listingManager, ListingRepository $listingRepository)
{
try {
$relatedListingsElasticResponse = $listingManager->getRelatedListingsElasticResponse($listing);
$listingsQueryBuilder = $listingRepository->getListingsByIds(array_column($relatedListingsElasticResponse['items'], 'id'));
return $listingsQueryBuilder->getQuery()->getResult();
} catch (\Exception $exception) {
throw new \Exception('something went wrong');
}
}
/**
* @Operation(
* tags={"Views"},
* summary="Add listing views",
*
* )
*
* @Rest\Post("/api/v2/listing/{id}/views", options={"i18n" = false, "expose"=true}, requirements={"id"="\d+"}, name="aqarmap_api_add_listing_views")
*
* @Rest\View()
*/
public function increaseListingViews(Listing $listing): array
{
try {
$this->interactionService->increaseViews($listing, $this->getUser());
return [
'status' => 'ok',
'message' => 'Views Created Successfully!',
];
} catch (\Exception $exception) {
throw new \Exception('something went wrong');
}
}
}