initial commit

This commit is contained in:
2026-06-25 13:03:45 +06:00
commit 4589f4a8d0
3229 changed files with 941958 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
<?php
/**
* AppShell file
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 2.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
App::uses('Shell', 'Console');
/**
* Application Shell
*
* Add your application-wide methods in the class below, your shells
* will inherit them.
*
* @package app.Console.Command
*/
class AppShell extends Shell {
public function getSystemCurrentTimeStamp(){
date_default_timezone_set("UTC");
return date("Y-m-d H:i:s");
}
}

View File

@@ -0,0 +1,279 @@
<?php
/**
* @property NotificationComponent $Notification
*/
class BackupShell extends AppShell
{
public $unique_url;
public $uses = array('AccessInfo','ExpiredRecord');
public function main() {
}
/*
* command: Console/cake Backup generateAccessInfo
* Run it only once to generate accessinfo for records before 25 february 2018
*/
public function generateAccessInfo(){
$backup_mode = Configure::read('expensecount.backup.mode');
$db = ConnectionManager::getDataSource('default');
$limit = 100;
if($backup_mode){
//retrieve all expense which is not exist in Access Info and update date before 4 months
// create access info records for those expenses; id=>expense_id, unique_url=>unique_url, access_time=>created_date
$range = date('Y-m-d', strtotime("25 February, 2018"));
$expense_counts = $db->query("SELECT id, unique_url, create_date FROM `expenses` WHERE id not in(select id from access_infos) and `create_date` < '$range'");
foreach ($expense_counts as $key=>$value) {
$expense_id = $value['expenses']['id'];
$unique_url = $value['expenses']['unique_url'];
// $access_time = $value['expenses']['create_date'];
$access_time = date('Y-m-d H:i:s', $value['expenses']['update_date']);
$db->query("insert into access_infos(id, unique_url, access_time) values(".$expense_id.",'".$unique_url."','".$access_time."')");
}
}
exit;
//insert multiple record into the table Expired_Records
//check the case whether the record insertion successful or not for multi insertion when pk already exist
}
/*
* command: Console/cake Backup shiftExpiredRecords
* Run it in every hours once
* This method generates records into the table expired_records and delete all records fron access info
*/
public function shiftExpiredRecords(){
$backup_mode = Configure::read('expensecount.backup.mode');
$month = isset($this->args[0]) ? (int)$this->args[0] : 4; // default 4 months
$type = isset($this->args[1]) ? (int)$this->args[1] : 1; // default 1. 1 = Months, 2 = Days; Type will always be 1 because no value is passed for this parameter.
if ($month <= 0) {
echo('Month must be a positive number');
exit;
}
if($backup_mode){
//retrieve all expried records
$result = $this->AccessInfo->getExpiredExpenses($month,$type);
if(!empty($result)){
$currentDate = $this->getSystemCurrentTimeStamp();
foreach($result as $key=>$value){
$deleteList[] = $value["AccessInfo"]["id"];
$data["ExpiredRecord"][$key]["id"] = $value["AccessInfo"]["id"];
$data["ExpiredRecord"][$key]["unique_url"] = $value["AccessInfo"]["unique_url"];
$data["ExpiredRecord"][$key]["inserted_on"] = $currentDate;
}
$error = $this->ExpiredRecord->saveAllExpiredRecords($data);
if(empty($error)){
//delete all records from AccessInfo table
$this->AccessInfo->deleteAllExpiredExpenses($deleteList);
}
}
}
exit;
//insert multiple record into the table Expired_Records
//check the case whether the record insertion successful or not for multi insertion when pk already exist
}
/*
* command: Console/cake Backup initiateBackup 100
* Run it in every six hours once
* This method scan expire_records table and shift records to backup tables;
* After taking backup, it delete records from expire_records table.
*/
public function initiateBackup($limit = BACKUP_LIMIT){
$limit = isset($this->args[0]) ? (int)$this->args[0] : BACKUP_LIMIT;
$this->backupAndRemoveOriginalRecords($limit);
}
/*
* Command : Console/cake Backup backupSingleExpense 1ILcOUb0fe3JpgB
* This method shifts and backup single expense from live tables to backup tables in the production database.
*/
public function backupSingleExpense($unique_url=null)
{
$unique_url = isset($this->args[0]) ? $this->args[0] : null;
$db = ConnectionManager::getDataSource('default');
try {
$backup_expense = $db->query("select * from backup_expenses where unique_url='".$unique_url."'");
} catch (Exception $ex) {
}
if (empty($backup_expense)) {
$expense = $db->query("select * from expenses where unique_url= '".$unique_url."'");
if(!empty($expense)) {
$this->loadModel('Backup');
$this->Backup->processBackupAndRemove($expense);
} else {
echo "Expense is not found in production database. Could not perform backup!";
exit;
}
} else {
echo "Expense is already in backup database. Could not perform backup!";
exit;
}
}
/*
* command: Console/cake Backup archieveSingleItem 1ILcOUb0fe3JpgB
* Run it to archieve a sinle expense
*
* This method shifts one single expense from backup tables(live db) to archieve database
*
*/
public function archieveSingleItem($unique_url=null)
{
$unique_url = isset($this->args[0]) ? $this->args[0] : null;
$this->loadModel('Backup');
$this->Backup->archieveSingleExpense($unique_url);
}
/*
* command: Console/cake Backup initiateArchive 10 100
* Run it to archive records older than custom month, with a row limit.
* e.g. 10 months before from the current date and 100 records
*/
public function initiateArchive($month = 50, $limit = BACKUP_LIMIT){
$month = isset($this->args[0]) ? (int)$this->args[0] : 50;
$limit = isset($this->args[1]) ? (int)$this->args[1] : BACKUP_LIMIT;
$this->archiveAndRemoveOriginalRecords($limit,$month);
}
/*
* command: Console/cake Backup initiateRemoveArchive 10 100
* Run it to remove archived records older than custom month, with a row limit.
* e.g. 10 months before from the current date and 100 records
*/
public function initiateRemoveArchive($month = 50, $limit = BACKUP_LIMIT){
$month = isset($this->args[0]) ? (int)$this->args[0] : 50;
$limit = isset($this->args[1]) ? (int)$this->args[1] : BACKUP_LIMIT;
$this->removeArchiveRecords($limit,$month);
}
private function backupAndRemoveOriginalRecords($limit = BACKUP_LIMIT){
$backup_mode = Configure::read('expensecount.backup.mode');
if($backup_mode){
//retrieve 100 records from the table expired_records
$query = "select id,unique_url from expired_records limit 0,".$limit;
$db = ConnectionManager::getDataSource('default');
$expiredRecordList = $db->query($query);
$db->begin();
try {
if (!empty($expiredRecordList)) {
$this->loadModel('Backup');
$this->Backup->processBackupAndRemove($expiredRecordList, true);
$db->commit();
}
}catch (Exception $ex) {
$db->rollback();
$message = "Backup process failed. Rolled back. Error: " . $ex->getMessage();
$this->emailSend($message,"Backup process failed");
echo $message;
}
}
exit;
}
private function archiveAndRemoveOriginalRecords($limit = BACKUP_LIMIT, $month = 36){
$month = (int)$month;
if ($month <= 0) {
echo('Month must be a positive number');
exit;
}
$backup_mode = Configure::read('expensecount.backup.mode');
$db = ConnectionManager::getDataSource('default');
$before_date = (new DateTime())
->modify("-{$month} months")
->format('Y-m-d');
$range = strtotime($before_date);
if($backup_mode){
//retrieve records from the table back_expenses
$query = "SELECT id, unique_url
FROM backup_expenses WHERE update_date <= $range
LIMIT $limit";
$backupRecordList = $db->query($query);
if(!empty($backupRecordList)){
$this->loadModel('Backup');
$this->Backup->processArchiveAndRemove($backupRecordList,true);
}
}
exit;
}
private function removeArchiveRecords($limit = BACKUP_LIMIT, $month = 36){
$month = (int)$month;
if ($month <= 0) {
echo('Month must be a positive number');
exit;
}
$backup_mode = Configure::read('expensecount.backup.mode');
$before_date = (new DateTime())
->modify("-{$month} months")
->format('Y-m-d');
$range = strtotime($before_date);
$db = ConnectionManager::getDataSource('archieve');
if ($backup_mode) {
//retrieve records from the table expenses
$query = "SELECT id, unique_url
FROM expenses WHERE update_date <= $range
LIMIT $limit";
$archiveRecordList = $db->query($query);
if (!empty($archiveRecordList)) {
$this->loadModel('Backup');
$this->Backup->processRemoveArchive($archiveRecordList, true);
}
}
}
private function emailSend($message = null, $subject = null)
{
App::uses('ComponentCollection', 'Controller');
App::uses('NotificationComponent', 'Controller/Component');
$this->Notification = new NotificationComponent(new ComponentCollection());
$this->Notification->sendEmail(array(
"email_from" => SUPPORT_EMAIL,
"email_to" => REPORTING_EMAIL,
"title" => $message,
"template" => "backup_archive_process_error",
"subject" => $subject,
));
}
}
?>

View File

@@ -0,0 +1,33 @@
<?php
class RestoreShell extends AppShell
{
public $uses = array('AccessInfo', 'ExpiredRecord', 'Expense', 'ExpenseEmail', 'GroupExpense',
'Participant', 'Meal', 'FamilyExpense', 'Log', 'GroupSetting', 'PermissionTable');
public function main()
{
//
}
/*
* Command: Console/cake Restore restoreSingleExpense
* For restoring a single item
*
* This methods first tries to restore single expense from backup tables to live tables. If there
* is no such expense in backup table, it tries to restore from archieve database to live database.
* If the expense is already exist in live tables, it does not do anything.
*
*
*/
public function restoreSingleExpense()
{
$unique_url = "2ruQCFbb";
$this->loadModel("Backup");
$this->Backup->restore($unique_url);
}
}

View File

View File

@@ -0,0 +1,29 @@
Backup Commands
========================
1. command: console\cakce Backup generateAccessInfo
Run it only once to generate accessinfo for records before 25 february 2018
2. command: console\cake Backup shiftExpiredRecords
Run it in every hours once
This method generates records into the table expired_records and delete all records fron access info
3. command: console\cake Backup initiateBackup
Run it in every six hours once
This method scan expire_records table and shift records to backup tables;
After taking backup, it delete records from expire_records table.
4. Command : console\cake Backup backupSingleExpense
This method shifts and backup single expense from live tables to backup tables in the production database.
5. command: console\cake Backup archieveSingleItem
Run it to archieve a sinle expense
This method shifts one single expense from backup tables(live db) to archieve database
Restore Commands
==========================
1. Command: console\cake Restore restoreSingleExpense
For restoring a single item
This methods first tries to restore single expense from backup tables to live tables. If there
is no such expense in backup table, it tries to restore from archieve database to live database.
If the expense is already exist in live tables, it does not do anything.

View File

@@ -0,0 +1,75 @@
/*
List of Archive Commands
* Command:
* php app\Console\cake.php Backup initiateArchive <months> <limit>
*
* Description:
=======================================================
1. Get data from the "backup_expenses" table in the current database.
2. Save the data to the "expenses" table in the archive database(another database).
Steps
======
1. Go to Project Folder
2. Run the command like
In Widows:
C:\xampp_php7\htdocs\expensecount> C:\xampp_php7\php\php.exe app\Console\cake.php Backup initiateArchive 50 100
(project dir)> "PHP executable" "Entry Point CakePHP shells" "Shell Class" "Function" "Months" "Rows"
( it means
1. 50 month before data from current month
2. 100 record at a time
)
*===========================================================
* Parameters:
* <months> Number of months before the current date. Records older than
* this period will be moved to the archive database.
* <limit> Maximum number of records to archive in a single execution.
*
* Example:
* Console/cake Backup initiateArchive 100 100
*
* This command archives up to 100 records that are older than
* 10 months from the current date.
*
* Usage Notes:
* - Suitable for scheduled execution via cron or manual maintenance tasks.
* - Ensure backup processes are functioning correctly before execution.
*/
/*
Single Archive Commands
* Command:
* php app\Console\cake.php Backup archieveSingleItem <unique_url>
*
* Description:
===================
1. Get data from the "backup_expenses" table by unique_url in the current database.
2. Save the data to the "expenses" table in the archive database(another database).
Steps
======
1. Go to Project Folder
2. Run the command like
In Widows:
C:\xampp_php7\htdocs\expensecount> C:\xampp_php7\php\php.exe app\Console\cake.php Backup archieveSingleItem 1ILcOUb0fe3JpgB
(project dir)> "PHP executable" "Entry Point CakePHP shells" "Shell Class" "Function" "unique_url"
( it means
1. Archive data by unique_url 1ILcOUb0fe3JpgB
)
*
* Parameters:
* <unique_url> The unique identifier of the expense to be archived.
*
* Usage:
* Run this command to archive one specific expense on demand.
* Example:
* php app\Console\cake.php Backup archieveSingleItem 1ILcOUb0fe3JpgB
*
* Purpose:
* - Supports manual or targeted archival of individual expense records.
* - Helps keep backup and live databases lightweight.
*
* Notes:
* - Ensure the expense exists in the backup tables before running the command.
*/

View File

@@ -0,0 +1,36 @@
/*
* Command:
* php app\Console\cake.php Backup initiateRemoveArchive <months> <limit>
*
* Description:
=======================================================
1. Get the data to the "expenses" table in the archive database.
2. Removed from respective tables in archive tables
Steps
======
1. Go to Project Folder
2. Run the command like
In Widows:
C:\xampp_php7\htdocs\expensecount> C:\xampp_php7\php\php.exe app\Console\cake.php Backup initiateRemoveArchive 50 100
(project dir)> "PHP executable" "Entry Point CakePHP shells" "Shell Class" "Function" "Months" "Rows"
( it means
1. 50 month before data from current month
2. 100 record at a time
)
*===========================================================
*
* Parameters:
* <months> Number of months before the current date. Records older than
* this period will be permanently removed.
* <limit> Maximum number of records to remove in a single execution.
*
* Example:
* php app\Console\cake.php Backup initiateRemoveArchive 10 100
*
* This command deletes up to 100 archived records that are older than
* 10 months from the current date.
*
* Usage Notes:
* - Intended to be run via cron or manually as part of archive maintenance.
*/

View File

@@ -0,0 +1,106 @@
/*
Generate Access Info
* Command:
* Console/cake Backup generateAccessInfo
*
* Description:
* Generates access information for expense records created before
* 25 February 2018. This prepares historical records for further
* backup and archival processing.
*
* Execution Frequency:
* Run **only once**.
*
* Purpose:
* - Prepares old expense records for backup and archival.
* - Ensures access information is available for subsequent backup commands.
*
* Usage Notes:
* - Intended for one-time execution during initial setup.
* - Verify database connectivity before running the command.
*/
/*
Shift Expired Records
* Command:
* Console/cake Backup shiftExpiredRecords <month>
*
* Description:
* Identifies expired records and moves them into the `expired_records` table.
* After shifting, all corresponding records are deleted from the `access_info` table.
*
* Execution Frequency:
* Recommended to run once every hour.
*
* Purpose:
* - Prepares expired records for backup processing.
* - Keeps the `access_info` table clean and up-to-date.
*
* Usage:
* Run this command to backup a specific expense on demand.
* Example:
* Console/cake Backup shiftExpiredRecords 4
* Usage Notes:
* - Suitable for scheduled execution via cron.
* - Ensure database connectivity before running this command.
*/
/*
Bulk Expense Backup
* Command:
* Console/cake Backup initiateBackup <limit>
*
* Description:
* Scans the `expired_records` table and moves the records into the backup tables.
* After successfully taking the backup, the records are deleted from the `expired_records` table.
*
* Execution Frequency:
* Recommended to run once every six hours.
*
* Purpose:
* - Transfers expired records from live tables to backup tables.
* - Keeps the `expired_records` table from growing indefinitely.
*
* Usage:
* Run this command to backup a specific expense on demand.
* Example:
* Console/cake Backup initiateBackup 100
*
* Usage Notes:
* - Suitable for scheduled execution via cron.
* - Ensure database backups are functioning correctly before running this command.
* - Recommended to run during low-traffic periods to minimize load.
*/
/*
Single Expense Backup
* Command:
* Console/cake Backup backupSingleExpense <unique_url>
*
* Description:
* Backs up a single expense record from the live tables to the backup tables
* in the production database. This is useful for manually backing up
* individual records without running bulk backup operations.
*
* Parameters:
* <unique_url> The unique identifier of the expense to be backed up.
*
* Usage:
* Run this command to backup a specific expense on demand.
* Example:
* Console/cake Backup backupSingleExpense 1ILcOUb0fe3JpgB
*
* Purpose:
* - Supports targeted backup of individual expense records.
* - Helps ensure important records are safely copied to backup tables.
*
* Notes:
* - Ensure the record exists in the live tables before running the command.
*/

View File

41
app/Console/cake Normal file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
################################################################################
#
# Bake is a shell script for running CakePHP bake script
#
# CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
# Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
#
# Licensed under The MIT License
# For full copyright and license information, please see the LICENSE.txt
# Redistributions of files must retain the above copyright notice.
#
# @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
# @link http://cakephp.org CakePHP(tm) Project
# @package app.Console
# @since CakePHP(tm) v 1.2.0.5012
# @license http://www.opensource.org/licenses/mit-license.php MIT License
#
################################################################################
# Canonicalize by following every symlink of the given name recursively
canonicalize() {
NAME="$1"
if [ -f "$NAME" ]
then
DIR=$(dirname -- "$NAME")
NAME=$(cd -P "$DIR" && pwd -P)/$(basename -- "$NAME")
fi
while [ -h "$NAME" ]; do
DIR=$(dirname -- "$NAME")
SYM=$(readlink "$NAME")
NAME=$(cd "$DIR" && cd $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
echo "$NAME"
}
CONSOLE=$(dirname -- "$(canonicalize "$0")")
APP=$(dirname "$CONSOLE")
exec php -q "$CONSOLE"/cake.php -working "$APP" "$@"
exit

31
app/Console/cake.bat Normal file
View File

@@ -0,0 +1,31 @@
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Bake is a shell script for running CakePHP bake script
::
:: CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
:: Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
::
:: Licensed under The MIT License
:: Redistributions of files must retain the above copyright notice.
::
:: @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
:: @link http://cakephp.org CakePHP(tm) Project
:: @package app.Console
:: @since CakePHP(tm) v 2.0
:: @license http://www.opensource.org/licenses/mit-license.php MIT License
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: In order for this script to work as intended, the cake\console\ folder must be in your PATH
@echo.
@echo off
SET app=%0
SET lib=%~dp0
php -q "%lib%cake.php" -working "%CD% " %*
echo.
exit /B %ERRORLEVEL%

47
app/Console/cake.php Normal file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/php -q
<?php
/**
* Command-line code generation utility to automate programmer chores.
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package app.Console
* @since CakePHP(tm) v 2.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
if (!defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
$dispatcher = 'Cake' . DS . 'Console' . DS . 'ShellDispatcher.php';
if (function_exists('ini_set')) {
$root = dirname(dirname(dirname(__FILE__)));
$appDir = basename(dirname(dirname(__FILE__)));
$install = $root . DS . 'lib';
$composerInstall = $root . DS . $appDir . DS . 'Vendor' . DS . 'cakephp' . DS . 'cakephp' . DS . 'lib';
// the following lines differ from its sibling
// /lib/Cake/Console/Templates/skel/Console/cake.php
if (file_exists($composerInstall . DS . $dispatcher)) {
$install = $composerInstall;
}
ini_set('include_path', $install . PATH_SEPARATOR . ini_get('include_path'));
unset($root, $appDir, $install, $composerInstall);
}
if (!include $dispatcher) {
trigger_error('Could not locate CakePHP core files.', E_USER_ERROR);
}
unset($dispatcher);
return ShellDispatcher::run($argv);