<?php
declare(strict_types=1);
namespace WPXToolsBundle\Controller;
use PDO;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Validator\Validator;
use WPXToolsBundle\Entity\Role;
use WPXToolsBundle\Entity\User;
use WPXToolsBundle\Entity\UserDepartment;
use WPXToolsBundle\Entity\UserPosition;
use WPXToolsBundle\Form\LoginType;
class UserController extends Controller
{
/**
* @param Request $request
* @Route("/login", name="login")
* @return \Symfony\Component\HttpFoundation\Response
*/
public function loginForm(Request $request)
{
if($request->server->get('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest'){
$response = new Response();
$response->headers->set('x-is-ajax-call', true);
return $response;
}
$login = new User();
$loginForm = $this->createForm(LoginType::class, $login);
$loginForm->handleRequest($request);
$authenticationUtils = $this->get('security.authentication_utils');
$error = $authenticationUtils->getLastAuthenticationError();
if(($loginForm->isSubmitted() && $loginForm->isValid()) || $this->getUser()){
return $this->redirectToRoute('dashboard');
}else{
return $this->render('default/login_form.html.twig', [
'title' => 'User Login',
'loginForm' => $loginForm->createView(),
'error' => $error
]);
}
}
/**
* @Route ("/logout", name="logout")
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* @internal param Request $request
*/
public function logoutProcess()
{
$session = new Session();
$session->clear();
return $this->redirectToRoute('dashboard');
}
/**
* @Route("/notifications", name="user_notifications")
* @Route("/notifications/view/{id}", name="user_notifications_view_message")
* @param Request $request
* @return string
*/
public function userNotifications(Request $request){
$validator = new Validator([
'id' => $request->attributes->get('id')
], false);
$validator->validateAll([
'id' => [
'type' => 'int',
'required' => false,
'msg' => 'The notification ID provided isn\'t valid.'
]
]);
if($validator->hasErrors()){
foreach ($validator->errors as $string){
$this->addFlash('warning', $string);
}
return false;
}
$notificationService = $this->get('user_notification');
if(!empty($validator->valid['id']))
{
$notification = $notificationService->viewNotification((int)$validator->valid['id']);
if(!$notification) return $this->redirectToRoute('user_notifications');
return $this->render('default/user/notifications_view.html.twig', [
'title' => $notification['notificationSubject'],
'notification' => $notification
]);
}else{
return $this->render('default/user/notifications.html.twig',[
'notifications' => $notificationService->notifications,
'title' => 'User notifications'
]);
}
}
/**
* @Route("/notifications/markRead", name="notifications_mark_read")
* @param Request $request
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function notificationMarkRead(Request $request){
if($this->get('user_notification')->setSeenNotification($request->request->get('alertId'))){
return $this->json([
'message' => 'Successfully marked as read.',
'status' => 0
]);
}else{
return $this->json([
'message' => 'Failed to mark the notification as read!',
'status' => 1
]);
}
}
/**
* @Route("/profile", name="user_profile")
* @Route("/profile/{id}", name="user_profile_admin")
* @param Request $request
* @return bool|\Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\Response
*/
public function userProfile(Request $request){
$validator = new Validator($_REQUEST);
$validator->validateAll([
'id' => [
'type' => 'int',
'required' => 0,
'value' => $request->attributes->get('id'),
'default' => $this->getUser()->getId()
],
'action' => [
'required' => false
]
]);
$adminCheck = $this->isGranted('ROLE_ADMIN');
if($validator->hasErrors()){
foreach ($validator->errors as $string){
$this->addFlash('warning', $string);
}
return false;
}
if( $validator->valid['action'] ){
if( !$this->updateProfile($validator->valid['id'], $adminCheck) ){
$this->addFlash('warning', 'Could not update profile.');
}
}
$em = $this->getDoctrine();
$user = $em->getRepository(User::class)->findOneBy(['id' => $validator->valid['id']]);
if(!is_object($user)){
$this->addFlash('warning', 'User with this ID doesn\'t exist.');
return $this->redirectToRoute('user_staff_list');
}
if($this->getUser()->getId() != $validator->valid['id'] && !$adminCheck){
return $this->render('default/user/view_profile.html.twig',[
'title' => 'View Profile',
'userData' => $user
]);
}
$roles = $em->getRepository(Role::class)->findAll();
$departments = $em->getRepository(UserDepartment::class)->findAll();
$positions = $em->getRepository(UserPosition::class)->findAll();
$hb = $this->get('hb_initialize');
$hostBillUsers = $hb->makeAction('getAllUsers');
return $this->render('default/user/profile.html.twig',[
'title' => 'Edit Profile',
'userData' => $user,
'roles' => $roles,
'departments' => $departments,
'positions' => $positions,
'hbUsers' => $hostBillUsers['result'],
]);
}
/**
* @param $userId
* @param $adminCheck
* @return bool|\Symfony\Component\HttpFoundation\JsonResponse
*/
public function updateProfile($userId, $adminCheck){
if($this->getUser()->getId() != $userId && !$adminCheck){
return false;
}
$validator = new Validator($_REQUEST, false);
$validator->validateAll([
'username' => [
'filter' => 'trim',
'msg' => 'The username is invalid.',
'msg_miss' => 'You haven\'t provided username.'
],
'realname' => [
'filter' => 'trim',
'msg' => 'The name is invalid.',
'msg_miss' => 'You haven\'t provided any name for the account'
],
'fullName' => [
'filter' => 'trim',
'msg' => 'The name is invalid.',
'msg_miss' => 'You haven\'t provided any name for the account'
],
'realPosition' => [
'filter' => 'trim',
'msg' => 'The real position is invalid.',
'msg_miss' => 'You haven\'t provided any real position for the account'
],
'currentPassword' => [
'required' => false,
'requires' => ['newPassword', 'newPasswordAgain'],
'msg' => 'The entered password is invalid',
'msg_miss' => 'The current password wasn\'t provided'
],
'newPassword' => [
'required' => false,
'requires' => ['currentPassword', 'newPasswordAgain'],
'match' => '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$/',
'msg' => 'Password should be containing at least 1 lower case letter, at least 1 upper case letter, at least 1 digit and at least 1 special symbol.',
'msg_miss' => 'No new password provided.'
],
'newPasswordAgain' => [
'required' => false,
'requires' => ['currentPassword', 'newPassword'],
'match' => '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$/',
'msg' => 'Password should be the same as the previous field.',
'msg_miss' => 'You should repeat the new password.'
],
'email' => [
'type' => 'email',
'msg' => 'The email address isn\'t valid.',
'msg_miss' => 'You haven\'t provided any email address.'
],
'skype' => [
'filter' => 'trim',
'required' => false,
'msg' => 'The provided Skype name isn\'t valid'
],
'mobileNumber' => [
'match' => '/^\+?\d{6,12}$/',
'required' => false,
'msg' => 'Invalid mobile number provided. Should be containing digits only and starting with +359 or 0 only.',
'msg_miss' => 'No mobile number provided'
],
'birthdate' => [
'type' => 'date',
'filter' => 'trim',
'required' => false,
'msg' => 'The birth date is invalid.',
'msg_miss' => 'No birth date provided.'
],
'canUsePLAfter' => [
'type' => 'date',
'filter' => 'trim',
'required' => false,
'msg' => 'The paid leave date is invalid.',
'msg_miss' => 'No paid leave date provided.'
],
'paidLeaveDays' => [
'type' => 'int',
'required' => false,
'msg' => 'The paid leave value is invalid.',
'msg_miss' => 'No paid leave value provided.'
],
'isActive' => [
'match' => ['on', 'off'],
'required' => false,
'msg' => 'Invalid active status provided.'
],
'popupNotifications' => [
'match' => ['on', 'off'],
'required' => false,
'msg' => 'Invalid popup notification status provided.'
],
'userRole' => [
'type' => 'int',
'required' => false,
'msg' => 'Invalid user Role provided.'
],
'positions' => [
'type' => 'int',
'msg' => 'Invalid user Position provided.'
],
'hostBillUser' => [
'type' => 'int',
'required' => false,
'msg' => 'Invalid hostBillUser ID provided.'
]
]);
if($validator->hasErrors()){
foreach ($validator->errors as $string){
$this->addFlash('warning', $string);
}
return false;
}
$valid = $validator->valid;
$em = $this->getDoctrine();
$user = $em->getRepository(User::class)->findOneBy(['id'=>$userId]);
if($valid['hostBillUser'] !== $user->getHostBillId() && $adminCheck) {
$checkHBUser = $em->getRepository(User::class)->findOneBy(['hostBillId' => $valid['hostBillUser']]);
if (is_object($checkHBUser) && $valid['hostBillUser'] !== 0 && $checkHBUser->getId() !== $user->getId()) {
$this->addFlash('warning', $checkHBUser->getRealName() . ' is already related with this HostBill account. Two users can\'t have the same HostBill account relation.');
return false;
}else{
$user->setHostBillId($valid['hostBillUser']);
}
}
$currentPassword = (!$adminCheck) ? password_verify($valid['currentPassword'], $user->getPassword()) : true;
if(!empty($valid['newPassword']) && $currentPassword){
if($valid['newPassword'] == $valid['newPasswordAgain']){
$password = $this->get('security.password_encoder')->encodePassword($user, $valid['newPassword']);
$user->setPassword($password);
}else{
$this->addFlash('warning', 'The new passwords do not match.');
}
}else{
if(!empty($valid['currentPassword'])){
$this->addFlash('warning', 'The current password doesn\'t match. New password was NOT updated.');
}elseif(!empty($valid['newPassword'])){
$this->addFlash('warning', 'New password was entered but either wrong or no password was provided as current.');
}
}
if($adminCheck){
$position = $em->getRepository(UserPosition::class)->findOneBy(['id'=>$valid['positions']]);
$user->setRealName($valid['realname']);
$user->setUsername($valid['username']);
$user->setEmail($valid['email']);
if ($valid['realPosition']) {
$user->setDepartmentNameInCyrillic($valid['realPosition']);
}
if($valid['canUsePLAfter']){
$user->setPaidLeaveDaysDate(new \DateTime($valid['canUsePLAfter']));
}else{
$user->setPaidLeaveDaysDate(NULL);
}
$user->setPaidLeaveDays($valid['paidLeaveDays']);
$user->setPosition($position);
if($valid['userRole'] === 6 && !$this->isGranted('ROLE_SUPER_ADMIN')) {
$roleId = 1;
}else{
$roleId = $valid['userRole'];
}
$sql = "UPDATE users_roles SET role_id = :roleId WHERE user_id = :userId";
$query = $em->getConnection()->prepare($sql);
$query->execute([
'roleId' => $roleId,
'userId' => $userId
]);
$active = ($valid['isActive'] == 'on') ? 1 : 0;
$popupNotifications = ($valid['popupNotifications'] == 'on') ? 1 : 0;
$user->setIsActive($active);
$user->setPopupNotifications($popupNotifications);
}
if ($valid['fullName']) {
$user->setNameInCyrillic($valid['fullName']);
}
$user->setSkype($valid['skype']);
$user->setPhoneNumber($valid['mobileNumber']);
if($valid['birthdate']){
$user->setBirthDate(new \DateTime($valid['birthdate']));
}else{
$user->setBirthDate(NULL);
}
$em->getManager()->flush();
$this->addFlash('success', 'Profile has been updated successfully.');
return true;
}
/**
* @Route("/getPositions", name="get_positions")
*/
public function getPositions(){
$validator = new Validator($_REQUEST, false);
$validator->validateAll([
'departmentId' => [
'type' => 'int'
]
]);
if($validator->hasErrors()){
foreach ($validator->errors as $string){
$this->addFlash('warning', $string);
}
return false;
}
$em = $this->getDoctrine();
$sql = "SELECT positionName, id FROM users_positions WHERE department_id = :departmentId";
$query = $em->getConnection()->prepare($sql);
$query->execute([
'departmentId' => $validator->valid['departmentId']
]);
$positions = $query->fetchAll();
return $this->json([
'message' => 'Shifts have been successfully retrieved.',
'status' => 0,
'data' => $positions
]);
}
/**
* @Route("/staff", name="user_staff_list")
*/
public function staffList(){
$em = $this->getDoctrine()->getConnection();
$sqlStaffList = "SELECT d.DepartmentName, u.id, u.realName, u.email, u.skype, u.phoneNumber, u.isActive, p.positionName
FROM users as u
INNER JOIN users_positions as p ON u.position_id = p.id
INNER JOIN users_departments as d ON p.department_id = d.id
WHERE u.isActive = '1'
ORDER BY d.sortOrder ASC, p.positionPriority ASC";
$queryStaffList = $em->prepare($sqlStaffList);
$queryStaffList->execute();
$staffList = $queryStaffList->fetchAll(PDO::FETCH_GROUP);
return $this->render('default/user/staff_list.html.twig',[
'title' => 'Staff list',
'staffList' => $staffList
]);
}
/**
* @Route("/pull/data", name="pull_data")
* @param Request $request
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function pullData(Request $request){
/**
* List all the data that will be pulled and returned in the JSON.
*/
$notifications = $this->get('user_notification');
$activity = $this->get('user_activity')->refreshActivity($request->headers->get('referer'));
return $this->json([
'message' => 'OK',
'status' => 0,
'data' => [
'notifications' => $notifications->notificationsUnseen,
'activity' => ($activity['status'] === 0) ? $activity['data'] : 'Failed to update activity.',
'feedbackChats' => $notifications->notificationFeedbackChats,
'feedbackTickets' => $notifications->notificationFeedbackTickets,
'assignedIssues' => $notifications->notificationAssignedIssues
]
]);
}
}