Files
accounting_dev_v2/application/controllers/Profile.php
T
2026-09-14 11:14:25 +07:00

90 lines
6.9 KiB
PHP

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Profile extends MY_Controller
{
public function __construct()
{
parent::__construct();
}
public function index($tab='settings')
{
$tab=$this->input->get('tab',true)?:$tab;if(!in_array($tab,array('settings','devices'),true))$tab='settings';
$user=$this->db->get_where('users',array('id'=>$this->uid()))->row();if(!$user)show_404();
$data=array('active_menu'=>'profile','profile_tab'=>$tab,'user'=>$user,'sessions'=>$this->usersessionservice->activeSessions($user->id),'attempts'=>$this->usersessionservice->attempts($user->id),'active_count'=>$this->usersessionservice->activeCount($user->id));
$this->load->view('partials/header',$data);$this->load->view('profile/index',$data);$this->load->view('partials/footer');
}
public function update_profile()
{
$this->postOnly();$user=$this->user();$newPhoto=null;
try{
$name=trim((string)$this->input->post('nama',true));$email=strtolower(trim((string)$this->input->post('email',true)));
if($name===''||mb_strlen($name)>255)throw new RuntimeException('Nama wajib diisi dan maksimal 255 karakter.');
if($email!==''&&!filter_var($email,FILTER_VALIDATE_EMAIL))throw new RuntimeException('Format email tidak valid.');
if($email!==''&&$this->db->where('email',$email)->where('id !=',$user->id)->get('users')->row())throw new RuntimeException('Email sudah digunakan pengguna lain.');
$newPhoto=$this->uploadPhoto();$update=array('nama'=>$name,'email'=>$email?:null,'profile_updated_at'=>date('Y-m-d H:i:s'));if($newPhoto)$update['profile_photo']=$newPhoto;
$this->db->where('id',$user->id)->update('users',$update);if(!$this->db->trans_status())throw new RuntimeException('Profil gagal disimpan.');
if($newPhoto&&!empty($user->profile_photo))$this->removeOldPhoto($user->profile_photo);
$this->session->set_userdata(array('nama'=>$name,'email'=>$email?:null,'profile_photo'=>$newPhoto?:$user->profile_photo));
log_activity('Profile','update','Memperbarui profil pengguna sendiri','success');$this->session->set_flashdata('success','Profil berhasil diperbarui.');
}catch(Throwable$e){if($newPhoto&&is_file(FCPATH.$newPhoto))@unlink(FCPATH.$newPhoto);$this->session->set_flashdata('error',$e->getMessage());}
redirect('profile');
}
public function update_security()
{
$this->postOnly();$hours=(int)$this->input->post('session_duration_hours');$limit=(int)$this->input->post('max_active_devices');
try{
if(!in_array($hours,array(24,72,168),true))throw new RuntimeException('Durasi session tidak valid.');
if($limit<1||$limit>10)throw new RuntimeException('Batas perangkat harus antara 1 sampai 10.');
$this->db->where('id',$this->uid())->update('users',array('session_duration_hours'=>$hours,'max_active_devices'=>$limit,'profile_updated_at'=>date('Y-m-d H:i:s')));
log_activity('Profile','security_setting','Mengubah durasi session menjadi '.$hours.' jam dan batas perangkat menjadi '.$limit,'success');
$this->session->set_flashdata('success','Pengaturan login berhasil disimpan dan berlaku mulai login berikutnya. Session yang sedang aktif tetap memakai batas waktu awalnya.');
}catch(Throwable$e){$this->session->set_flashdata('error',$e->getMessage());}
redirect('profile');
}
public function update_password()
{
$this->postOnly();$user=$this->user();
try{
$current=(string)$this->input->post('current_password');$new=(string)$this->input->post('new_password');$confirm=(string)$this->input->post('confirm_password');
if(!password_verify($current,$user->password))throw new RuntimeException('Password saat ini tidak sesuai.');
if(strlen($new)<8||!preg_match('/[A-Za-z]/',$new)||!preg_match('/\d/',$new))throw new RuntimeException('Password baru minimal 8 karakter dan harus mengandung huruf serta angka.');
if($new!==$confirm)throw new RuntimeException('Konfirmasi password baru tidak sama.');
if(password_verify($new,$user->password))throw new RuntimeException('Password baru harus berbeda dari password saat ini.');
$this->db->where('id',$user->id)->update('users',array('password'=>password_hash($new,PASSWORD_DEFAULT),'profile_updated_at'=>date('Y-m-d H:i:s')));
$this->usersessionservice->revokeOthers($user->id);log_activity('Profile','password','Mengubah password dan mengakhiri session perangkat lain','success');
$this->session->set_flashdata('success','Password berhasil diubah. Session pada perangkat lain telah diakhiri.');
}catch(Throwable$e){$this->session->set_flashdata('error',$e->getMessage());}
redirect('profile');
}
public function revoke_session($id)
{
$this->postOnly();
try{
$result=$this->usersessionservice->revoke((int)$id,$this->uid());log_activity('Profile','revoke_session','Mengakhiri session perangkat ID '.(int)$id,'success');
if($result['current']){$this->session->sess_destroy();redirect('auth?notice=revoked');return;}
$this->session->set_flashdata('success','Session perangkat berhasil diakhiri.');
}catch(Throwable$e){$this->session->set_flashdata('error',$e->getMessage());}
redirect('profile?tab=devices');
}
private function uploadPhoto()
{
if(empty($_FILES['profile_photo'])||$_FILES['profile_photo']['error']===UPLOAD_ERR_NO_FILE)return null;
$file=$_FILES['profile_photo'];if($file['error']!==UPLOAD_ERR_OK)throw new RuntimeException('Foto profil gagal diunggah.');if((int)$file['size']>2*1024*1024)throw new RuntimeException('Ukuran foto profil maksimal 2 MB.');
$mime=(new finfo(FILEINFO_MIME_TYPE))->file($file['tmp_name']);$allowed=array('image/jpeg'=>'jpg','image/png'=>'png','image/webp'=>'webp');if(!isset($allowed[$mime]))throw new RuntimeException('Foto profil hanya menerima JPG, PNG, atau WEBP.');
$dir=FCPATH.'uploads/accounting/profiles/';if(!is_dir($dir)&&!mkdir($dir,0755,true))throw new RuntimeException('Folder foto profil tidak dapat dibuat.');
$relative='uploads/accounting/profiles/'.bin2hex(random_bytes(20)).'.'.$allowed[$mime];if(!move_uploaded_file($file['tmp_name'],FCPATH.$relative))throw new RuntimeException('Foto profil tidak dapat disimpan.');return$relative;
}
private function removeOldPhoto($path){$prefix='uploads/accounting/profiles/';if(strpos((string)$path,$prefix)===0&&is_file(FCPATH.$path))@unlink(FCPATH.$path);}
private function user(){$row=$this->db->get_where('users',array('id'=>$this->uid()))->row();if(!$row)throw new RuntimeException('Pengguna tidak ditemukan.');return$row;}
private function uid(){return(int)$this->session->userdata('user_id');}
private function postOnly(){if(strtoupper($this->input->method())!=='POST')show_404();}
}