- Add login wallpaper upload, preview, and deletion in Hospital Profile settings - Redesign login page with right-docked form and left hospital branding hero - Implement clean blank neutral fallback when no wallpaper is configured - Add automated unit tests for wallpaper rendering and fallback behavior
445 lines
16 KiB
PHP
445 lines
16 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers\Setting;
|
|
|
|
use App\Controllers\BaseController;
|
|
use CodeIgniter\HTTP\Files\UploadedFile;
|
|
|
|
class HospitalProfile extends BaseController
|
|
{
|
|
public function index()
|
|
{
|
|
if (! $this->canManageHospitalProfile()) {
|
|
return $this->response->setStatusCode(403)->setBody('Access denied');
|
|
}
|
|
|
|
$logo = $this->readSettingValue('H_logo');
|
|
$pharmacyLogo = $this->readSettingValue('H_Med_logo');
|
|
$wallpaper = $this->readSettingValue('H_login_wallpaper');
|
|
helper('common');
|
|
|
|
return view('Setting/Admin/hospital_profile', [
|
|
'hospital_name' => $this->readSettingValue('H_Name'),
|
|
'hospital_address_1' => $this->readSettingValue('H_address_1'),
|
|
'hospital_address_2' => $this->readSettingValue('H_address_2'),
|
|
'hospital_phone' => $this->readSettingValue('H_phone_No'),
|
|
'hospital_email' => $this->readSettingValue('H_Email'),
|
|
'hospital_hfr_id' => $this->readSettingValue('H_HFR_ID'),
|
|
'footer_version' => $this->readSettingValue('HMS_UPDATE_ID') !== ''
|
|
? $this->readSettingValue('HMS_UPDATE_ID')
|
|
: hms_default_version_id(),
|
|
'hospital_logo' => $logo,
|
|
'hospital_logo_url' => $logo !== '' ? base_url('assets/images/' . rawurlencode($logo)) : '',
|
|
'hospital_wallpaper' => $wallpaper,
|
|
'hospital_wallpaper_url' => $wallpaper !== '' ? base_url('assets/images/' . rawurlencode($wallpaper)) : '',
|
|
'pharmacy_name' => $this->readSettingValue('H_Med_Name'),
|
|
'pharmacy_address' => $this->readSettingValue('H_Med_address_1'),
|
|
'pharmacy_phone' => $this->readSettingValue('H_Med_phone_No'),
|
|
'pharmacy_gst' => $this->readSettingValue('H_Med_GST'),
|
|
'pharmacy_logo' => $pharmacyLogo,
|
|
'pharmacy_logo_url' => $pharmacyLogo !== '' ? base_url('assets/images/' . rawurlencode($pharmacyLogo)) : '',
|
|
'sidebar_auto_hide_seconds' => $this->readSettingValue('SIDEBAR_AUTO_HIDE_SECONDS') !== ''
|
|
? $this->readSettingValue('SIDEBAR_AUTO_HIDE_SECONDS')
|
|
: '7',
|
|
'allow_image_preupload_edit' => $this->readSettingValue('ALLOW_IMAGE_PREUPLOAD_EDIT') === '1' ? '1' : '0',
|
|
]);
|
|
}
|
|
|
|
public function save()
|
|
{
|
|
if (! $this->request->isAJAX()) {
|
|
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
|
}
|
|
|
|
if (! $this->canManageHospitalProfile()) {
|
|
return $this->response->setStatusCode(403)->setJSON(['update' => 0, 'error_text' => 'Access denied']);
|
|
}
|
|
|
|
if (! $this->db->tableExists('hospital_setting')) {
|
|
return $this->response->setJSON(['update' => 0, 'error_text' => 'hospital_setting table not found']);
|
|
}
|
|
|
|
$name = trim((string) $this->request->getPost('hospital_name'));
|
|
$address = trim((string) $this->request->getPost('hospital_address_1'));
|
|
$address2 = trim((string) $this->request->getPost('hospital_address_2'));
|
|
$phone = trim((string) $this->request->getPost('hospital_phone'));
|
|
$email = trim((string) $this->request->getPost('hospital_email'));
|
|
$hfrId = strtoupper(trim((string) $this->request->getPost('hospital_hfr_id')));
|
|
$footerVersion = trim((string) $this->request->getPost('footer_version'));
|
|
|
|
$pharmacyName = trim((string) $this->request->getPost('pharmacy_name'));
|
|
$pharmacyAddress = trim((string) $this->request->getPost('pharmacy_address'));
|
|
$pharmacyPhone = trim((string) $this->request->getPost('pharmacy_phone'));
|
|
$pharmacyGst = trim((string) $this->request->getPost('pharmacy_gst'));
|
|
$sidebarAutoHideSecondsRaw = trim((string) $this->request->getPost('sidebar_auto_hide_seconds'));
|
|
$sidebarAutoHideSeconds = $sidebarAutoHideSecondsRaw === '' ? 7 : (int) $sidebarAutoHideSecondsRaw;
|
|
$allowImagePreuploadEdit = $this->request->getPost('allow_image_preupload_edit') === '1' ? '1' : '0';
|
|
|
|
if ($name === '' || $address === '') {
|
|
return $this->response->setJSON([
|
|
'update' => 0,
|
|
'error_text' => 'Hospital name and address are required.',
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
|
|
if ($hfrId !== '' && preg_match('/^[A-Z0-9\/-]{6,40}$/', $hfrId) !== 1) {
|
|
return $this->response->setJSON([
|
|
'update' => 0,
|
|
'error_text' => 'HFR ID format is invalid. Use alphanumeric characters with / or -',
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
|
|
if ($sidebarAutoHideSeconds < 0 || $sidebarAutoHideSeconds > 60) {
|
|
return $this->response->setJSON([
|
|
'update' => 0,
|
|
'error_text' => 'Sidebar auto hide seconds must be between 0 and 60.',
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
|
|
$savedCount = 0;
|
|
if ($this->upsertSettingValue('H_Name', $name)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_address_1', $address)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_address_2', $address2)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_phone_No', $phone)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_Email', $email)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_HFR_ID', $hfrId)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('HMS_UPDATE_ID', $footerVersion)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_Med_Name', $pharmacyName)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_Med_address_1', $pharmacyAddress)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_Med_phone_No', $pharmacyPhone)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('H_Med_GST', $pharmacyGst)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('SIDEBAR_AUTO_HIDE_SECONDS', (string) $sidebarAutoHideSeconds)) {
|
|
$savedCount++;
|
|
}
|
|
if ($this->upsertSettingValue('ALLOW_IMAGE_PREUPLOAD_EDIT', $allowImagePreuploadEdit)) {
|
|
$savedCount++;
|
|
}
|
|
|
|
$logoResult = $this->processLogoUpload(
|
|
$this->request->getFile('hospital_logo'),
|
|
'hospital_logo',
|
|
'H_logo',
|
|
'Logo'
|
|
);
|
|
if (! $logoResult['ok']) {
|
|
return $this->response->setJSON([
|
|
'update' => 0,
|
|
'error_text' => $logoResult['error'],
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
if ($logoResult['changed']) {
|
|
$savedCount++;
|
|
}
|
|
|
|
$wallpaperResult = $this->processLogoUpload(
|
|
$this->request->getFile('hospital_wallpaper'),
|
|
'hospital_wallpaper',
|
|
'H_login_wallpaper',
|
|
'Login wallpaper'
|
|
);
|
|
if (! $wallpaperResult['ok']) {
|
|
return $this->response->setJSON([
|
|
'update' => 0,
|
|
'error_text' => $wallpaperResult['error'],
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
if ($wallpaperResult['changed']) {
|
|
$savedCount++;
|
|
}
|
|
|
|
$pharmacyLogoResult = $this->processLogoUpload(
|
|
$this->request->getFile('pharmacy_logo'),
|
|
'pharmacy_logo',
|
|
'H_Med_logo',
|
|
'Pharmacy logo'
|
|
);
|
|
if (! $pharmacyLogoResult['ok']) {
|
|
return $this->response->setJSON([
|
|
'update' => 0,
|
|
'error_text' => $pharmacyLogoResult['error'],
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
if ($pharmacyLogoResult['changed']) {
|
|
$savedCount++;
|
|
}
|
|
|
|
return $this->response->setJSON([
|
|
'update' => 1,
|
|
'error_text' => $savedCount > 0 ? 'Hospital profile saved successfully.' : 'No changes detected.',
|
|
'logo_url' => ($logo = $this->readSettingValue('H_logo')) !== '' ? base_url('assets/images/' . rawurlencode($logo)) : '',
|
|
'logo_name' => $this->readSettingValue('H_logo'),
|
|
'wallpaper_url' => ($wp = $this->readSettingValue('H_login_wallpaper')) !== '' ? base_url('assets/images/' . rawurlencode($wp)) : '',
|
|
'wallpaper_name' => $this->readSettingValue('H_login_wallpaper'),
|
|
'pharmacy_logo_url' => ($logo = $this->readSettingValue('H_Med_logo')) !== '' ? base_url('assets/images/' . rawurlencode($logo)) : '',
|
|
'pharmacy_logo_name' => $this->readSettingValue('H_Med_logo'),
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
|
|
public function deleteLogo()
|
|
{
|
|
if (! $this->request->isAJAX()) {
|
|
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
|
}
|
|
|
|
if (! $this->canManageHospitalProfile()) {
|
|
return $this->response->setStatusCode(403)->setJSON(['update' => 0, 'error_text' => 'Access denied']);
|
|
}
|
|
|
|
$type = strtolower(trim((string) $this->request->getPost('type')));
|
|
if ($type === 'pharmacy') {
|
|
$settingKey = 'H_Med_logo';
|
|
} elseif ($type === 'wallpaper') {
|
|
$settingKey = 'H_login_wallpaper';
|
|
} else {
|
|
$type = 'hospital';
|
|
$settingKey = 'H_logo';
|
|
}
|
|
|
|
$oldFile = $this->readSettingValue($settingKey);
|
|
$ok = $this->upsertSettingValue($settingKey, '');
|
|
|
|
if ($oldFile !== '') {
|
|
$oldPath = FCPATH . 'assets/images/' . basename($oldFile);
|
|
if (is_file($oldPath)) {
|
|
@unlink($oldPath);
|
|
}
|
|
}
|
|
|
|
$label = $type === 'wallpaper' ? 'Login wallpaper' : ucfirst($type) . ' logo';
|
|
|
|
return $this->response->setJSON([
|
|
'update' => $ok ? 1 : 0,
|
|
'error_text' => $ok ? $label . ' deleted.' : 'Unable to delete ' . strtolower($label) . '.',
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
|
|
public function reset()
|
|
{
|
|
if (! $this->request->isAJAX()) {
|
|
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
|
}
|
|
|
|
if (! $this->canManageHospitalProfile()) {
|
|
return $this->response->setStatusCode(403)->setJSON(['update' => 0, 'error_text' => 'Access denied']);
|
|
}
|
|
|
|
$logo = $this->readSettingValue('H_logo');
|
|
$pharmacyLogo = $this->readSettingValue('H_Med_logo');
|
|
$wallpaper = $this->readSettingValue('H_login_wallpaper');
|
|
$this->db->table('hospital_setting')->whereIn('s_name', [
|
|
'H_Name',
|
|
'H_address_1',
|
|
'H_address_2',
|
|
'H_phone_No',
|
|
'H_Email',
|
|
'H_HFR_ID',
|
|
'HMS_UPDATE_ID',
|
|
'H_logo',
|
|
'H_login_wallpaper',
|
|
'H_Med_Name',
|
|
'H_Med_address_1',
|
|
'H_Med_phone_No',
|
|
'H_Med_GST',
|
|
'H_Med_logo',
|
|
'SIDEBAR_AUTO_HIDE_SECONDS',
|
|
'ALLOW_IMAGE_PREUPLOAD_EDIT',
|
|
])->delete();
|
|
|
|
if ($logo !== '') {
|
|
$logoPath = FCPATH . 'assets/images/' . basename($logo);
|
|
if (is_file($logoPath)) {
|
|
@unlink($logoPath);
|
|
}
|
|
}
|
|
|
|
if ($pharmacyLogo !== '') {
|
|
$logoPath = FCPATH . 'assets/images/' . basename($pharmacyLogo);
|
|
if (is_file($logoPath)) {
|
|
@unlink($logoPath);
|
|
}
|
|
}
|
|
|
|
if ($wallpaper !== '') {
|
|
$wpPath = FCPATH . 'assets/images/' . basename($wallpaper);
|
|
if (is_file($wpPath)) {
|
|
@unlink($wpPath);
|
|
}
|
|
}
|
|
|
|
return $this->response->setJSON([
|
|
'update' => 1,
|
|
'error_text' => 'Hospital profile settings reset.',
|
|
'csrfName' => csrf_token(),
|
|
'csrfHash' => csrf_hash(),
|
|
]);
|
|
}
|
|
|
|
private function canManageHospitalProfile(): bool
|
|
{
|
|
if (! function_exists('auth') || ! auth()->loggedIn()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private function readSettingValue(string $name): string
|
|
{
|
|
if (! $this->db->tableExists('hospital_setting')) {
|
|
return '';
|
|
}
|
|
|
|
$row = $this->db->table('hospital_setting')
|
|
->select('s_value')
|
|
->where('s_name', $name)
|
|
->get(1)
|
|
->getRowArray();
|
|
|
|
return trim((string) ($row['s_value'] ?? ''));
|
|
}
|
|
|
|
private function upsertSettingValue(string $name, string $value): bool
|
|
{
|
|
$existing = $this->db->table('hospital_setting')
|
|
->select('id, s_value')
|
|
->where('s_name', $name)
|
|
->get(1)
|
|
->getRowArray();
|
|
|
|
$oldValue = trim((string) ($existing['s_value'] ?? ''));
|
|
|
|
if ($existing) {
|
|
$ok = $this->db->table('hospital_setting')
|
|
->where('id', (int) ($existing['id'] ?? 0))
|
|
->update(['s_value' => $value]);
|
|
} else {
|
|
$ok = $this->db->table('hospital_setting')->insert([
|
|
's_name' => $name,
|
|
's_value' => $value,
|
|
]);
|
|
}
|
|
|
|
if ($ok) {
|
|
$this->auditClinicalUpdate('hospital_setting', $name, $name, $oldValue, $value);
|
|
}
|
|
|
|
return (bool) $ok;
|
|
}
|
|
|
|
private function processLogoUpload(?UploadedFile $file, string $filePrefix, string $settingKey, string $label): array
|
|
{
|
|
if (! $file || $file->getError() === UPLOAD_ERR_NO_FILE) {
|
|
return ['ok' => true, 'changed' => false, 'error' => ''];
|
|
}
|
|
|
|
if (! $file->isValid()) {
|
|
return [
|
|
'ok' => false,
|
|
'changed' => false,
|
|
'error' => $label . ' upload failed: ' . $file->getErrorString(),
|
|
];
|
|
}
|
|
|
|
if ($file->hasMoved()) {
|
|
return ['ok' => true, 'changed' => false, 'error' => ''];
|
|
}
|
|
|
|
$ext = strtolower((string) $file->getExtension());
|
|
$allowed = ['png', 'jpg', 'jpeg', 'webp'];
|
|
if (! in_array($ext, $allowed, true)) {
|
|
return [
|
|
'ok' => false,
|
|
'changed' => false,
|
|
'error' => $label . ' must be png, jpg, jpeg, or webp.',
|
|
];
|
|
}
|
|
|
|
$targetDir = FCPATH . 'assets/images';
|
|
if (! is_dir($targetDir) && ! @mkdir($targetDir, 0775, true) && ! is_dir($targetDir)) {
|
|
return [
|
|
'ok' => false,
|
|
'changed' => false,
|
|
'error' => 'Cannot create upload directory. Check server write permissions.',
|
|
];
|
|
}
|
|
|
|
if (! is_writable($targetDir)) {
|
|
return [
|
|
'ok' => false,
|
|
'changed' => false,
|
|
'error' => 'Upload directory is not writable. Set write permission on public/assets/images.',
|
|
];
|
|
}
|
|
|
|
$newName = $filePrefix . '_' . date('Ymd_His') . '_' . substr(md5((string) mt_rand()), 0, 8) . '.' . $ext;
|
|
|
|
try {
|
|
$file->move($targetDir, $newName, true);
|
|
} catch (\Throwable $e) {
|
|
log_message('error', '[HospitalProfile] ' . $label . ' move failed: ' . $e->getMessage());
|
|
|
|
return [
|
|
'ok' => false,
|
|
'changed' => false,
|
|
'error' => $label . ' upload failed. Check write permission on public/assets/images and PHP upload temp directory.',
|
|
];
|
|
}
|
|
|
|
$oldLogo = $this->readSettingValue($settingKey);
|
|
if (! $this->upsertSettingValue($settingKey, $newName)) {
|
|
return [
|
|
'ok' => false,
|
|
'changed' => false,
|
|
'error' => 'Unable to save ' . strtolower($label) . ' setting.',
|
|
];
|
|
}
|
|
|
|
if ($oldLogo !== '' && $oldLogo !== $newName) {
|
|
$oldPath = $targetDir . DIRECTORY_SEPARATOR . basename($oldLogo);
|
|
if (is_file($oldPath)) {
|
|
@unlink($oldPath);
|
|
}
|
|
}
|
|
|
|
return ['ok' => true, 'changed' => true, 'error' => ''];
|
|
}
|
|
}
|