Add dashboard MCU user controller and activity log table
This commit is contained in:
447
application/controllers/dashboard_mcu/User.php
Normal file
447
application/controllers/dashboard_mcu/User.php
Normal file
@@ -0,0 +1,447 @@
|
||||
<?php
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
class User extends MY_Controller
|
||||
{
|
||||
private $db_dashboard;
|
||||
private $db_log;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->db_dashboard = $this->load->database("cpone_dashboard", true);
|
||||
$this->db_log = $this->load->database("log", true);
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
if (!$this->isLogin) {
|
||||
$this->sys_error("Invalid Token");
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $this->sanitize_username($this->get_input('username'));
|
||||
$password = (string) $this->get_input('password');
|
||||
$displayName = $this->sanitize_text($this->get_input('display_name'), 100);
|
||||
|
||||
if ($username === '') {
|
||||
$this->sys_error("username wajib diisi");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->is_valid_password_policy($password)) {
|
||||
$this->sys_error("password harus minimal 8 karakter dan mengandung huruf besar, huruf kecil, angka, serta simbol");
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db_dashboard->query(
|
||||
"CALL sp_insert_dashboard_user(?, ?, ?)",
|
||||
array($username, $password, $displayName)
|
||||
);
|
||||
$this->clean_mysqli_connection($this->db_dashboard->conn_id);
|
||||
|
||||
if (!$query) {
|
||||
$error = $this->db_dashboard->error();
|
||||
$this->log_activity("SAVE_USER", $username, $this->sys_input, "N", $error['message']);
|
||||
$this->sys_error_db("gagal insert dashboard user", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log_activity("SAVE_USER", $username, $this->sys_input, "Y", "success");
|
||||
$this->sys_ok(array(
|
||||
"message" => "user berhasil disimpan",
|
||||
"username" => $username
|
||||
));
|
||||
}
|
||||
|
||||
public function reset_password()
|
||||
{
|
||||
if (!$this->isLogin) {
|
||||
$this->sys_error("Invalid Token");
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $this->sanitize_username($this->get_input('username'));
|
||||
$newPassword = (string) $this->get_input('password');
|
||||
|
||||
if ($username === '') {
|
||||
$this->sys_error("username wajib diisi");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->is_valid_password_policy($newPassword)) {
|
||||
$this->sys_error("password harus minimal 8 karakter dan mengandung huruf besar, huruf kecil, angka, serta simbol");
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db_dashboard->query(
|
||||
"CALL sp_reset_dashboard_user_password(?, ?)",
|
||||
array($username, $newPassword)
|
||||
);
|
||||
$this->clean_mysqli_connection($this->db_dashboard->conn_id);
|
||||
|
||||
if (!$query) {
|
||||
$error = $this->db_dashboard->error();
|
||||
$this->log_activity("RESET_PASSWORD", $username, $this->sys_input, "N", $error['message']);
|
||||
$this->sys_error_db("gagal reset password", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log_activity("RESET_PASSWORD", $username, $this->sys_input, "Y", "success");
|
||||
$this->sys_ok(array(
|
||||
"message" => "password berhasil direset",
|
||||
"username" => $username
|
||||
));
|
||||
}
|
||||
|
||||
public function assign_project()
|
||||
{
|
||||
if (!$this->isLogin) {
|
||||
$this->sys_error("Invalid Token");
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $this->sanitize_username($this->get_input('username'));
|
||||
$mcuID = intval($this->get_input('mcu_id'));
|
||||
|
||||
if ($username === '') {
|
||||
$this->sys_error("username wajib diisi");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($mcuID <= 0) {
|
||||
$this->sys_error("mcu_id tidak valid");
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db_dashboard->query(
|
||||
"CALL sp_assign_user_project(?, ?)",
|
||||
array($username, $mcuID)
|
||||
);
|
||||
$this->clean_mysqli_connection($this->db_dashboard->conn_id);
|
||||
|
||||
if (!$query) {
|
||||
$error = $this->db_dashboard->error();
|
||||
$this->log_activity("ASSIGN_PROJECT", $username, $this->sys_input, "N", $error['message']);
|
||||
$this->sys_error_db("gagal assign project", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log_activity("ASSIGN_PROJECT", $username, $this->sys_input, "Y", "success");
|
||||
$this->sys_ok(array(
|
||||
"message" => "project berhasil di-assign",
|
||||
"username" => $username,
|
||||
"mcu_id" => $mcuID
|
||||
));
|
||||
}
|
||||
|
||||
public function remove_project()
|
||||
{
|
||||
if (!$this->isLogin) {
|
||||
$this->sys_error("Invalid Token");
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $this->sanitize_username($this->get_input('username'));
|
||||
$mcuID = intval($this->get_input('mcu_id'));
|
||||
|
||||
if ($username === '') {
|
||||
$this->sys_error("username wajib diisi");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($mcuID <= 0) {
|
||||
$this->sys_error("mcu_id tidak valid");
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->db_dashboard->query(
|
||||
"CALL sp_remove_user_project(?, ?)",
|
||||
array($username, $mcuID)
|
||||
);
|
||||
$this->clean_mysqli_connection($this->db_dashboard->conn_id);
|
||||
|
||||
if (!$query) {
|
||||
$error = $this->db_dashboard->error();
|
||||
$this->log_activity("REMOVE_PROJECT", $username, $this->sys_input, "N", $error['message']);
|
||||
$this->sys_error_db("gagal remove project", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log_activity("REMOVE_PROJECT", $username, $this->sys_input, "Y", "success");
|
||||
$this->sys_ok(array(
|
||||
"message" => "project berhasil dihapus dari user",
|
||||
"username" => $username,
|
||||
"mcu_id" => $mcuID
|
||||
));
|
||||
}
|
||||
|
||||
public function search_project()
|
||||
{
|
||||
if (!$this->isLogin) {
|
||||
$this->sys_error("Invalid Token");
|
||||
return;
|
||||
}
|
||||
|
||||
$keyword = $this->sanitize_text($this->get_input('search'), 100);
|
||||
$keywordLike = "%" . $keyword . "%";
|
||||
|
||||
$sql = "SELECT
|
||||
Mgm_McuID AS mcu_id,
|
||||
Mgm_McuNumber AS project_number,
|
||||
Mgm_McuLabel AS project_name
|
||||
FROM cpone.mgm_mcu
|
||||
WHERE Mgm_McuIsActive = 'Y'
|
||||
AND (
|
||||
Mgm_McuNumber LIKE ?
|
||||
OR Mgm_McuLabel LIKE ?
|
||||
)
|
||||
ORDER BY Mgm_McuID DESC
|
||||
LIMIT 20";
|
||||
|
||||
$query = $this->db_dashboard->query($sql, array($keywordLike, $keywordLike));
|
||||
if (!$query) {
|
||||
$this->sys_error_db("gagal search project", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sys_ok(array(
|
||||
"records" => $query->result_array()
|
||||
));
|
||||
}
|
||||
|
||||
public function search()
|
||||
{
|
||||
if (!$this->isLogin) {
|
||||
$this->sys_error("Invalid Token");
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $this->sanitize_text($this->get_input('username'), 50);
|
||||
$project = $this->sanitize_text($this->get_input('project'), 20);
|
||||
$page = intval($this->get_input('page'));
|
||||
$limit = intval($this->get_input('limit'));
|
||||
|
||||
if ($page <= 0) {
|
||||
$page = 1;
|
||||
}
|
||||
if ($limit <= 0) {
|
||||
$limit = 20;
|
||||
}
|
||||
if ($limit > 100) {
|
||||
$limit = 100;
|
||||
}
|
||||
|
||||
$offset = ($page - 1) * $limit;
|
||||
$usernameLike = "%" . $username . "%";
|
||||
$projectID = 0;
|
||||
if ($project !== '' && strtolower($project) !== 'all') {
|
||||
$projectID = intval($project);
|
||||
}
|
||||
|
||||
$whereProject = "";
|
||||
$paramsCount = array($usernameLike);
|
||||
$paramsData = array($usernameLike);
|
||||
if ($projectID > 0) {
|
||||
$whereProject = " AND up.UserProj_McuID = ? ";
|
||||
$paramsCount[] = $projectID;
|
||||
$paramsData[] = $projectID;
|
||||
}
|
||||
|
||||
$sqlCount = "SELECT COUNT(DISTINCT u.User_ID) AS total_rows
|
||||
FROM cpone_dashboard.dashboard_user u
|
||||
LEFT JOIN cpone_dashboard.dashboard_user_project up
|
||||
ON up.UserProj_UserID = u.User_ID
|
||||
AND up.UserProj_IsActive = 'Y'
|
||||
WHERE u.User_IsActive = 'Y'
|
||||
AND u.User_Username LIKE ? " . $whereProject;
|
||||
|
||||
$countQuery = $this->db_dashboard->query($sqlCount, $paramsCount);
|
||||
if (!$countQuery) {
|
||||
$this->sys_error_db("gagal hitung data user", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
$totalRows = intval($countQuery->row()->total_rows);
|
||||
$totalPages = $totalRows > 0 ? intval(ceil($totalRows / $limit)) : 0;
|
||||
|
||||
$sqlData = "SELECT
|
||||
u.User_ID,
|
||||
u.User_Username,
|
||||
u.User_DisplayName,
|
||||
u.User_IsActive,
|
||||
u.User_CreatedAt,
|
||||
u.User_UpdatedAt,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CONCAT(
|
||||
up.UserProj_McuID, '|',
|
||||
IFNULL(m.Mgm_McuNumber, ''), '|',
|
||||
IFNULL(m.Mgm_McuLabel, '')
|
||||
)
|
||||
ORDER BY up.UserProj_McuID DESC
|
||||
SEPARATOR '||'
|
||||
) AS project_list
|
||||
FROM cpone_dashboard.dashboard_user u
|
||||
LEFT JOIN cpone_dashboard.dashboard_user_project up
|
||||
ON up.UserProj_UserID = u.User_ID
|
||||
AND up.UserProj_IsActive = 'Y'
|
||||
LEFT JOIN cpone.mgm_mcu m
|
||||
ON m.Mgm_McuID = up.UserProj_McuID
|
||||
WHERE u.User_IsActive = 'Y'
|
||||
AND u.User_Username LIKE ? " . $whereProject . "
|
||||
GROUP BY
|
||||
u.User_ID,
|
||||
u.User_Username,
|
||||
u.User_DisplayName,
|
||||
u.User_IsActive,
|
||||
u.User_CreatedAt,
|
||||
u.User_UpdatedAt
|
||||
ORDER BY u.User_ID DESC
|
||||
LIMIT ? OFFSET ?";
|
||||
|
||||
$paramsData[] = $limit;
|
||||
$paramsData[] = $offset;
|
||||
|
||||
$dataQuery = $this->db_dashboard->query($sqlData, $paramsData);
|
||||
if (!$dataQuery) {
|
||||
$this->sys_error_db("gagal ambil data user", $this->db_dashboard);
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = $dataQuery->result_array();
|
||||
foreach ($rows as &$row) {
|
||||
$row['projects'] = array();
|
||||
if (!empty($row['project_list'])) {
|
||||
$items = explode("||", $row['project_list']);
|
||||
foreach ($items as $item) {
|
||||
$parts = explode("|", $item);
|
||||
$row['projects'][] = array(
|
||||
"mcu_id" => isset($parts[0]) ? intval($parts[0]) : 0,
|
||||
"project_number" => isset($parts[1]) ? $parts[1] : "",
|
||||
"project_name" => isset($parts[2]) ? $parts[2] : ""
|
||||
);
|
||||
}
|
||||
}
|
||||
unset($row['project_list']);
|
||||
}
|
||||
unset($row);
|
||||
|
||||
$this->sys_ok(array(
|
||||
"pagination" => array(
|
||||
"page" => $page,
|
||||
"limit" => $limit,
|
||||
"total_rows" => $totalRows,
|
||||
"total_pages" => $totalPages
|
||||
),
|
||||
"filters" => array(
|
||||
"username" => $username,
|
||||
"project" => $project === '' ? 'all' : $project
|
||||
),
|
||||
"records" => $rows
|
||||
));
|
||||
}
|
||||
|
||||
private function log_activity($action, $target, $payload, $isSuccess, $message)
|
||||
{
|
||||
$actorUserID = isset($this->sys_user["M_UserID"]) ? intval($this->sys_user["M_UserID"]) : 0;
|
||||
$actorUsername = isset($this->sys_user["M_UserUsername"]) ? $this->sys_user["M_UserUsername"] : "";
|
||||
$actorEmail = isset($this->sys_user["M_UserEmail"]) ? $this->sys_user["M_UserEmail"] : "";
|
||||
|
||||
$sql = "INSERT INTO cpone_log.dashboard_user_activity_log (
|
||||
DashboardUserActivityLogAction,
|
||||
DashboardUserActivityLogTarget,
|
||||
DashboardUserActivityLogPayloadJson,
|
||||
DashboardUserActivityLogIsSuccess,
|
||||
DashboardUserActivityLogMessage,
|
||||
DashboardUserActivityLogActorUserID,
|
||||
DashboardUserActivityLogActorUsername,
|
||||
DashboardUserActivityLogActorEmail,
|
||||
DashboardUserActivityLogCreatedAt
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())";
|
||||
|
||||
$safePayload = $this->mask_sensitive_payload($payload);
|
||||
$payloadJson = json_encode($safePayload);
|
||||
if ($payloadJson === false) {
|
||||
$payloadJson = "{}";
|
||||
}
|
||||
|
||||
$this->db_log->query($sql, array(
|
||||
$this->sanitize_text($action, 50),
|
||||
$this->sanitize_text($target, 100),
|
||||
$payloadJson,
|
||||
$isSuccess === "Y" ? "Y" : "N",
|
||||
$this->sanitize_text($message, 255),
|
||||
$actorUserID,
|
||||
$this->sanitize_text($actorUsername, 100),
|
||||
$this->sanitize_text($actorEmail, 150)
|
||||
));
|
||||
}
|
||||
|
||||
private function mask_sensitive_payload($payload)
|
||||
{
|
||||
if (!is_array($payload)) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
$sensitiveKeys = array(
|
||||
'password',
|
||||
'new_password',
|
||||
'old_password',
|
||||
'pass',
|
||||
'passwd'
|
||||
);
|
||||
|
||||
foreach ($payload as $key => $value) {
|
||||
$lowerKey = strtolower((string) $key);
|
||||
if (in_array($lowerKey, $sensitiveKeys, true)) {
|
||||
$payload[$key] = hash('sha256', (string) $value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$payload[$key] = $this->mask_sensitive_payload($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function get_input($key)
|
||||
{
|
||||
return isset($this->sys_input[$key]) ? $this->sys_input[$key] : "";
|
||||
}
|
||||
|
||||
private function sanitize_username($value)
|
||||
{
|
||||
$value = trim((string) $value);
|
||||
$value = preg_replace('/[^a-zA-Z0-9._-]/', '', $value);
|
||||
return substr($value, 0, 50);
|
||||
}
|
||||
|
||||
private function sanitize_text($value, $maxLen = 255)
|
||||
{
|
||||
$value = trim((string) $value);
|
||||
$value = strip_tags($value);
|
||||
if (strlen($value) > $maxLen) {
|
||||
$value = substr($value, 0, $maxLen);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function is_valid_password_policy($password)
|
||||
{
|
||||
if (!is_string($password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($password) < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasUpper = preg_match('/[A-Z]/', $password) === 1;
|
||||
$hasLower = preg_match('/[a-z]/', $password) === 1;
|
||||
$hasNumber = preg_match('/[0-9]/', $password) === 1;
|
||||
$hasSymbol = preg_match('/[^a-zA-Z0-9]/', $password) === 1;
|
||||
|
||||
return $hasUpper && $hasLower && $hasNumber && $hasSymbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE IF NOT EXISTS `cpone_log`.`dashboard_user_activity_log` (
|
||||
`DashboardUserActivityLogID` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`DashboardUserActivityLogAction` VARCHAR(50) NOT NULL,
|
||||
`DashboardUserActivityLogTarget` VARCHAR(100) DEFAULT NULL,
|
||||
`DashboardUserActivityLogPayloadJson` LONGTEXT,
|
||||
`DashboardUserActivityLogIsSuccess` CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
`DashboardUserActivityLogMessage` VARCHAR(255) DEFAULT NULL,
|
||||
`DashboardUserActivityLogActorUserID` INT NOT NULL DEFAULT 0,
|
||||
`DashboardUserActivityLogActorUsername` VARCHAR(100) DEFAULT NULL,
|
||||
`DashboardUserActivityLogActorEmail` VARCHAR(150) DEFAULT NULL,
|
||||
`DashboardUserActivityLogCreatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`DashboardUserActivityLogID`),
|
||||
KEY `idx_dashboard_user_activity_log_created` (`DashboardUserActivityLogCreatedAt`),
|
||||
KEY `idx_dashboard_user_activity_log_action` (`DashboardUserActivityLogAction`),
|
||||
KEY `idx_dashboard_user_activity_log_actor` (`DashboardUserActivityLogActorUserID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
Reference in New Issue
Block a user