Viewing File: /home/assersoft/public_html/doctor-assistant/app/Controllers/UsersController.php
<?php
namespace App\Controllers;
require_once __DIR__ . "/../Helpers/jwt_helper.php";
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\RESTful\ResourceController;
use App\Models\ClinicsModel;
helper('cookie');
class UsersController extends ResourceController
{
protected $modelName = "App\Models\UsersModel";
protected $format = "json";
/**
* Return an array of resource objects, themselves in array format.
*
* @return ResponseInterface
*/
public function index()
{
$rules = [
'clinic_id' => 'required|numeric',
];
if(!$this->validate($rules)) {
return $this->fail($this->validator->getErrors());
}
$data = $this->model->where('clinic_id', $this->request->getVar('clinic_id'))->findAll();
foreach($data as &$user) {
unset($user['password']);
unset($user['refresh_token']);
unset($user['activation_token']);
unset($user['reset_token']);
}
return $this->respond($data);
}
/**
* Return the properties of a resource object.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function show($id = null)
{
$data = $this->model->find($id);
if($data == null){
return $this->failNotFound("User not found");
}
unset($data['password']);
unset($data['refresh_token']);
unset($data['activation_token']);
unset($data['reset_token']);
return $this->respond($data);
}
/**
* Create a new resource object, from "posted" parameters.
*
* @return ResponseInterface
*/
public function create()
{
$rules = [
'first_name' => 'required|min_length[3]|max_length[50]',
'last_name' => 'permit_empty|min_length[3]|max_length[50]',
'email' => 'required|valid_email',
'phone' => 'required',
'password' => 'required|min_length[8]',
'user_type' => 'required|in_list[provider, head_doctor, doctor,receptionist]',
'consultation_hours' => 'permit_empty|json',
'clinic_id' => 'permit_empty|numberic',
'clinic_name' => 'permit_empty|min_length[3]|max_length[50]',
'refresh_token' => 'permit_empty',
];
if(!$this->validate($rules)) {
return $this->fail($this->validator->getErrors());
}
$data = $this->request->getVar();
$data->subscription_status = false;
$data->subscription_end_date = null;
$data->is_verified = false;
$user = $this->request->user ?? null;
if ($data->user_type == 'provider' && $user->user_type && $user->user_type !== 'provider') {
return $this->fail('Only providers can create more providers');
}
if($data->user_type !== 'head_doctor' && $data->user_type !== 'provider' && !property_exists($data, 'clinic_id')) {
return $this->fail('Clinic ID is required for non-head doctors');
}
if($data->user_type != 'head_doctor' && $user->user_type && ($user->user_type != 'head_doctor' && $user->user_type != 'provider')) {
return $this->fail('Only head doctors can create doctors and receptionists');
}
if($data->user_type == 'head_doctor') {
$clinicsModel = new ClinicsModel();
$data->subscription_status = true;
$data->subscription_end_date = date('Y-m-d', strtotime('+7 days'));
if (!$clinicsModel->insert($data)) {
return $this->fail($clinicsModel->errors());
}
$data->clinic_id = $clinicsModel->getInsertID();
}
$data->password = password_hash($data->password, PASSWORD_DEFAULT);
if(!$this->model->insert($data)) {
// if(!$this->model->save($data)) {
return $this->fail($this->model->errors());
}
$activationToken = generateToken(['user_id' => $this->model->insertID()], getenv('jwt.activation_token_expiration'));
$this->model->update($this->model->insertID(), ['activation_token' => $activationToken]);
// sending email
$message = "Please activate your account: " . anchor(base_url("user/activate/" . $activationToken), "Activate Now");
$email = \Config\Services::email();
$email->setTo($data->email);
$email->setSubject('Activate your account');
$email->setMessage($message);
// $email->send();
if(!$email->send()) {
// return $this->fail($email->printDebugger());
return $this->fail(['error' => 'Failed to send activation email', 'debug' => $email->printDebugger()]);
}
return $this->respondCreated([ 'user_id' => $this->model->getInsertID() ]);
}
public function activate($token = null) {
$decodedToken = decodeJWT($token);
if(is_object($decodedToken) && property_exists($decodedToken, 'error')) {
return view('activation_error', ['error' => 'Invalid token']);
}
$user = $this->model->find($decodedToken->user_id);
if ($user == null) {
return view('activation_error');
}
if($token != $user['activation_token']) {
return view('activation_error', ['error' => 'Invalid or expired token']);
}
if ($user['is_verified']) {
return view('activation_error', ['message' => 'Your account is already verified']);
}
$this->model->update($decodedToken->user_id, ['is_verified' => true, 'activation_token' => null]);
return view('activation_success');
}
/**
* Add or update a model resource, from "posted" properties.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function update($id = null)
{
$rules = [
'first_name' => 'permit_empty|min_length[3]|max_length[50]',
'last_name' => 'permit_empty|min_length[3]|max_length[50]',
'email' => 'permit_empty|valid_email',
'phone' => 'permit_empty',
'password' => 'permit_empty|min_length[8]',
'user_type' => 'permit_empty|in_list[head_doctor, doctor,receptionist]',
'consultation_hours' => 'permit_empty|json',
'clinic_id' => 'permit_empty|numeric',
'clinic_name' => 'permit_empty|min_length[3]|max_length[50]',
'refresh_token' => 'permit_empty',
];
if(!$this->validate($rules)) {
return $this->fail($this->validator->getErrors());
}
$user = $this->model->find($id);
if($user == null) {
return $this->failNotFound("User not found");
}
$data = $this->request->getVar();
if(property_exists($data, 'email') && $data->email !== $user->email) {
$data->is_verified = false;
$activationToken = generateToken(['user_id' => $id], getenv('jwt.activation_token_expiration'));
$data->verification_token = $activationToken;
// sending email
$message = "Please activate your account: " . anchor(base_url("user/activate/" . $activationToken), "Activate Now");
$email = \Config\Services::email();
$email->setTo($user['email']);
$email->setSubject('Activate your account');
$email->setMessage($message);
// $email->send();
if(!$email->send()) {
// return $this->fail($email->printDebugger());
return $this->fail(['error' => 'Failed to send activation email', 'debug' => $email->printDebugger()]);
}
}
if(property_exists($data, 'password')) {
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
}
$this->model->update($id, $data);
if ($this->model->affectedRows() == 0) {
return $this->fail($this->model->errors());
}
return $this->respondUpdated(['user_id' => $id]);
}
/**
* Delete the designated resource object from the model.
*
* @param int|string|null $id
*
* @return ResponseInterface
*/
public function delete($id = null)
{
$user = $this->model->find($id);
if($user == null) {
return $this->failNotFound("User not found");
}
$this->model->delete($id);
if($this->model->affectedRows() == 0) {
return $this->fail($this->model->errors());
}
return $this->respondDeleted(['user_id' => $id]);
}
public function login() {
$rules = [
'user_id' => 'required|numeric',
'password' => 'required',
];
if(!$this->validate($rules)) {
return $this->fail($this->validator->getErrors());
}
$data = $this->request->getVar();
$user = $this->model->where('user_id', $data->user_id)->first();
if($user == null) {
return $this->failNotFound("User not found");
}
if(!password_verify($data->password, $user['password'])) {
return $this->fail("Incorrect password");
}
if(!$user['is_verified']) {
return $this->fail("Email not verified");
}
$clinicsModel = new ClinicsModel();
$clinic = $clinicsModel->find((int)$user['clinic_id']);
if($clinic == null) {
return $this->failNotFound("Clinic not found");
}
$user['clinic'] = $clinic;
$accessToken = generateToken(
['user_id' => $user['user_id'], 'user_type' => $user['user_type'], 'clinic_id' => $user['clinic_id']],
getenv('jwt.access_token_expiration')
);
$refreshToken = generateToken(
['user_id' => $user['user_id']],
getenv('jwt.refresh_token_expiration')
);
$this->model->update($user['user_id'], [
'refresh_token' => $refreshToken
]);
set_cookie('access_token', $accessToken, getenv('jwt.access_token_expiration'));
set_cookie('refresh_token', $refreshToken, getenv('jwt.refresh_token_expiration'));
unset($user['password']);
unset($user['refresh_token']);
unset($user['activation_token']);
unset($user['reset_token']);
return $this->respond([
'access_token' => $accessToken,
'refresh_token' => $refreshToken,
'user' => $user
]);
}
public function refresh() {
$refreshToken = get_cookie('refresh_token');
if(empty($refreshToken)) {
return $this->fail("Refresh token not found");
}
$payload = decodeJWT($refreshToken);
if(is_object($payload) && property_exists($payload, 'refresh_token')) {
return $this->fail("Invalid refresh token");
}
$user = $this->model->find($payload->user_id);
if($user == null) {
return $this->failNotFound("User not found");
}
if ($user['refresh_token'] !== $refreshToken) {
return $this->failUnauthorized('Refresh token mismatch.');
}
$accessToken = generateToken(
['user_id' => $user['user_id'], 'user_type' => $user['user_type']],
getenv('jwt.access_token_expiration')
);
set_cookie('access_token', $accessToken, getenv('jwt.access_token_expiration'));
unset($user['password']);
unset($user['refresh_token']);
unset($user['activation_token']);
unset($user['reset_token']);
return $this->respond([
'access_token' => $accessToken,
'user' => $user
]);
}
public function logout() {
$refreshToken = get_cookie('refresh_token');
if(empty($refreshToken)) {
return $this->fail("Refresh token not found");
}
$payload = decodeJWT($refreshToken);
if(is_object($payload) && property_exists($payload, 'error')) {
return $this->fail("Invalid refresh token");
}
$user = $this->model->find($payload->user_id);
if (!$user) {
return $this->failNotFound('User not found.');
}
if ($user['refresh_token'] !== $refreshToken) {
return $this->failUnauthorized('Refresh token mismatch.');
}
$this->model->update($user['user_id'], [
'refresh_token' => null
]);
set_cookie('access_token', '', -1);
set_cookie('refresh_token', '', -1);
return $this->respond(['message' => "Logged out successfully"]);
}
public function resetPassword() {
$rules = [
'user_id' => 'required|numeric',
];
if(!$this->validate($rules)) {
return $this->fail($this->validator->getErrors());
}
$user = $this->model->where('user_id', $this->request->getVar('user_id'))->first();
if($user == null) {
return $this->failNotFound("User not found");
}
$resetToken = generateToken([
'user_id' => $user['user_id'],
'clinic_id' => $user['clinic_id']
], getenv('jwt.reset_password_token_expiration'));
$this->model->update($user['user_id'], [
'reset_token' => $resetToken
]);
if (!isset($user['email']) || empty($user['email'])) {
return $this->fail(['error' => 'Invalid email address']);
}
$message = "Please reset your password: " . anchor(base_url("user/reset-password/" . $resetToken), "Reset Password");
$email = \Config\Services::email();
$email->setTo($user['email']);
$email->setSubject('Reset Password');
$email->setMessage($message);
if(!$email->send()) {
// return $this->fail($email->printDebugger());
return $this->fail(['error' => 'Failed to send reset password email', 'debug' => $email->printDebugger()]);
}
return $this->respond(['Reset link has been sent to your email.']);
}
public function reset($token = null) {
if (empty($token)) {
return $this->failNotFound('Token is missing');
}
$decodedToken = decodeJWT($token);
if (is_object($decodedToken) && property_exists($decodedToken, 'error')) {
return $this->fail($decodedToken['error']);
}
$user = $this->model->find($decodedToken->user_id);
if ($user == null) {
return $this->failNotFound('User not found');
}
if ($user['reset_token'] !== $token) {
return $this->failUnauthorized('Reset token mismatch.');
}
if ($this->request->getMethod() === 'GET') {
return view('reset_password_form', ['token' => $token]);
}
$password = $this->request->getPost('password');
$confirmPassword = $this->request->getPost('confirm_password');
if ($password !== $confirmPassword) {
return $this->failValidationErrors('Passwords do not match.');
}
if (strlen($password) < 8) {
return $this->failValidationErrors('Password must be at least 8 characters.');
}
$this->model->update($user['user_id'], [
'password' => password_hash($this->request->getPost('password'), PASSWORD_DEFAULT),
'reset_token' => null
]);
return view('reset_successful');
}
}
Back to Directory
File Manager