Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4df0703
Crreated a new gateway class and created two new tables
ali-ichk Feb 24, 2026
e9aace2
All Gateway methods have been successfully implemented.
ali-ichk Feb 24, 2026
c00d3f5
Simplified to only have one method in FileGateway to insert file and …
ali-ichk Feb 24, 2026
d62a96d
change the method position
ali-ichk Feb 24, 2026
57c9219
Added internal protected insert and update methods in the Gateway cla…
ali-ichk Feb 25, 2026
7873e84
Markbook: 4 locations where files are being uploaded have been refact…
ali-ichk Feb 25, 2026
bf412f0
Modules Refactored where files are uploaded: Staff, Markbook, Formal …
ali-ichk Feb 25, 2026
da6a9ad
Reports and Planner Module Refactored
ali-ichk Feb 25, 2026
a38297c
Refactored the code in Reports folder
ali-ichk Feb 26, 2026
3520968
Activities and Finance module - upload files scripts are refactored
ali-ichk Feb 26, 2026
f11faa8
Data Updater and Student: Upload scripts refactored
ali-ichk Feb 26, 2026
406c49f
System Admin, School Admin, User Admin - File upload scripts have bee…
ali-ichk Feb 26, 2026
2f91515
Refactored classes to use the latest file tracking feature
ali-ichk Feb 26, 2026
30b8ae6
Added a recordCustomFieldFileUploads() method that in CustomeFieldHan…
ali-ichk Feb 26, 2026
de5c783
added comments why tracking is not necessary here.
ali-ichk Feb 26, 2026
e54c37c
Covered the files which uses AJAX-uploaded approach
ali-ichk Mar 2, 2026
b3f18e2
Added comments to why tracking is skipped in some locations
ali-ichk Mar 2, 2026
1483f34
updated the gateway methods for better error checking
ali-ichk Mar 2, 2026
17e98c2
added error check in gateway methods
ali-ichk Mar 2, 2026
8cd5c01
Created a new fileHandler class and interface. Made changes in all re…
ali-ichk Mar 2, 2026
98c6f56
typo fix
ali-ichk Mar 2, 2026
b93e8bf
Implemented fileDeletion method in fileHandler class
ali-ichk Mar 2, 2026
bbb1a28
added the interface to return the class to container
ali-ichk Mar 3, 2026
b6bb441
added delete file methods
ali-ichk Mar 4, 2026
d43a0cd
Integrated File Handler class in Markbook module
ali-ichk Mar 4, 2026
a5aaeb0
Integrated fileHandler class in module - Formal Assessment
ali-ichk Mar 4, 2026
6d7bd7a
integrated file handler class in module Planner and Reports
ali-ichk Mar 4, 2026
1f1b9a4
integrated fileHandler class into module Activities
ali-ichk Mar 4, 2026
9ddc8cb
integrated file handler in module Students and Data Updater
ali-ichk Mar 6, 2026
44904ba
filehandler class integrated in School Admin, User Admin, System Admi…
ali-ichk Mar 6, 2026
f98a9e0
integrated fileHandler class in src-> Forms-> PersonalDocumentHandler…
ali-ichk Mar 9, 2026
5a624e8
integrated fileHandler class in src -> forms -> RequiredDocuments.php
ali-ichk Mar 9, 2026
d7d92ea
implemented the manageCustomFieldFileUploads in CustomFieldHandler cl…
ali-ichk Mar 9, 2026
6eee31c
Integrated CustomFileHandler for all the modules where a custom field…
ali-ichk Mar 9, 2026
ccbb515
minor fixes and integrated to Library
ali-ichk Mar 10, 2026
adc159f
integrated fileHandler class into planner module
ali-ichk Mar 10, 2026
aed864b
System: added a new fileHandler class to track and monitor file uploads
ali-ichk Mar 13, 2026
8754502
Merge branch 'v31.0.00' into System-Create-a-new-file-upload-system-w…
ali-ichk Mar 13, 2026
c11ec87
Merge branch 'v31.0.00' into System-Create-a-new-file-upload-system-w…
SKuipers Mar 20, 2026
8f9a97a
Apply suggestions from code review
ali-ichk Mar 20, 2026
59a73c5
Applied suggestions from code review
ali-ichk Mar 20, 2026
2228be1
Merge branch 'System-Create-a-new-file-upload-system-where-all-files-…
ali-ichk Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGEDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -429,4 +429,6 @@
INSERT INTO `gibbonSetting` (`scope`, `name`, `nameDisplay`, `description`, `value`) VALUES ('System', 'timeFormatPHP', 'Time Format', 'How should the time of day be displayed?', 'H:i');end
INSERT INTO `gibbonSetting` (`scope`, `name`, `nameDisplay`, `description`, `value`) VALUES ('Attendance', 'showIncompleteAttendance', 'Show Incomplete Attendance', 'Show class periods where attendance has not been taken (Not Available).', 'N');end
INSERT INTO `gibbonSetting` (`scope`, `name`, `nameDisplay`, `description`, `value`) VALUES ('Library', 'libraryAPIKey', 'Library API Key', 'Google Books API Key from Google Cloud Console.', '');end
";
CREATE TABLE `gibbonFile` (`gibbonFileID` int(12) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT, `filePath` varchar(255) NOT NULL, `fileName` varchar(255) NOT NULL, `fileExtension` varchar(10) NOT NULL, `fileSize` int(12) UNSIGNED NOT NULL, `mimeType` varchar(100) NOT NULL, `gibbonPersonIDOwner` int(10) UNSIGNED ZEROFILL DEFAULT NULL, `uploadedAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `checksum` varchar(64) NOT NULL, PRIMARY KEY (`gibbonFileID`), KEY `gibbonPersonIDOwner` (`gibbonPersonIDOwner`), KEY `filePath` (`filePath`), KEY `checksum` (`checksum`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;end
CREATE TABLE `gibbonFilePointer` (`gibbonFilePointerID` int(12) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT, `gibbonFileID` int(12) UNSIGNED ZEROFILL NOT NULL, `foreignTable` varchar(60) DEFAULT NULL, `foreignTableID` int(14) UNSIGNED ZEROFILL DEFAULT NULL, `foreignColumn` varchar(60) DEFAULT NULL, `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`gibbonFilePointerID`), KEY `gibbonFileID` (`gibbonFileID`), KEY `foreignTable` (`foreignTable`, `foreignTableID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;end
";
2 changes: 2 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ v31.0.00
Smart blocks have been updated with a streamlined appearance and more tools
Improved text editor with drag-drop image uploads and more formatting options
Added support for 12-hour and 24-hour time formats
Added comprehensive file upload tracking feature to monitor and manage all file uploads across the system

Security

Expand All @@ -38,6 +39,7 @@ v31.0.00
System: enabled configuring the time format as 12-hour clock or 24-hour clock in System Settings
System: added Peruvian Sol as a currency option
System: ensured Twig cache is turned off for Development installs
System: added a new fileHandler class to track and monitor file uploads
Admissions: added a progress bar for admissions milestones to Manage Applications
Admissions: added a warning to Accept Application when milestones have not been completed
Attendance: student attendance history now ordered by timetable period
Expand Down
22 changes: 19 additions & 3 deletions index_parentPhotoUploadProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

use Gibbon\Http\Url;
use Gibbon\Domain\User\PersonPhotoGateway;
use Gibbon\Contracts\Filesystem\FileHandler;

include './gibbon.php';

Expand Down Expand Up @@ -50,6 +51,7 @@
exit();
} else {
$attachment1 = null;
$fileMetaData = null;
if (!empty($_FILES['file1']['tmp_name'])) {
$fileUploader = new Gibbon\FileUploader($pdo, $session);
$fileUploader->setFileSuffixType(Gibbon\FileUploader::FILE_SUFFIX_INCREMENTAL);
Expand All @@ -63,6 +65,9 @@
header("Location: {$URL->withReturn('warning1')}");
exit();
}

// Capture file metadata for tracking
$fileMetaData = $fileUploader->getFileMetaData($attachment1);
}

$path = $session->get('absolutePath');
Expand Down Expand Up @@ -92,18 +97,29 @@
exit();
}


if (!empty($attachment1)) {
$personPhotoGateway = $container->get(PersonPhotoGateway::class);
// Update/insert the photo into the backup table
$photoUpdated = $personPhotoGateway->insertAndUpdate([
'gibbonPersonID' => $userData['gibbonPersonID'],
'gibbonPersonID' => $gibbonPersonID,
'gibbonSchoolYearID' => $session->get('gibbonSchoolYearID'),
'personImage' => $file['relativePath'],
'personImage' => $attachment1,
'gibbonPersonIDCreated' => $session->get('gibbonPersonID'),
], [
'personImage' => $file['relativePath'],
'personImage' => $attachment1,
'gibbonPersonIDCreated' => $session->get('gibbonPersonID'),
]);

// Record file tracking
if (!empty($fileMetaData) && !empty($gibbonPersonID)) {
$gibbonFileID = $container->get(FileHandler::class)->recordFileUpload($fileMetaData, 'gibbonPerson', $gibbonPersonID, 'image_240');

if (empty($gibbonFileID)) {
header("Location: {$URL->withReturn('warning1')}");
exit();
}
}
}

//Update session variables
Expand Down
16 changes: 14 additions & 2 deletions modules/Activities/activities_categories_addProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use Gibbon\Data\Validator;
use Gibbon\Services\Format;
use Gibbon\Domain\Activities\ActivityCategoryGateway;
use Gibbon\Domain\Activities\EventDateGateway;
use Gibbon\Contracts\Filesystem\FileHandler;

require_once '../../gibbon.php';

Expand Down Expand Up @@ -75,6 +75,7 @@
}

// Move attached file, if there is one
$fileMetaData = null;
if (!empty($_FILES['backgroundImageFile']['tmp_name'])) {
$fileUploader = new Gibbon\FileUploader($pdo, $session);
$fileUploader->getFileExtensions('Graphics/Design');
Expand All @@ -83,15 +84,26 @@

// Upload the file, return the /uploads relative path
$data['backgroundImage'] = $fileUploader->uploadFromPost($file, $data['name']);

if (empty($data['backgroundImage'])) {
$partialFail = true;
} else {
$fileMetaData = $fileUploader->getFileMetaData($data['backgroundImage']);
}
}

// Create the record
$gibbonActivityCategoryID = $categoryGateway->insert($data);

// Record file tracking
if (!empty($fileMetaData) && !empty($gibbonActivityCategoryID)) {
$gibbonFileID = $container->get(FileHandler::class)->recordFileUpload($fileMetaData, 'gibbonActivityCategory', $gibbonActivityCategoryID, 'backgroundImage');

if (empty($gibbonFileID)) {
$partialFail = true;
}
}

$URL .= !$gibbonActivityCategoryID
? "&return=error2"
: "&return=success0&editID=$gibbonActivityCategoryID";
Expand Down
23 changes: 22 additions & 1 deletion modules/Activities/activities_categories_editProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Gibbon\Data\Validator;
use Gibbon\Services\Format;
use Gibbon\Domain\Activities\ActivityCategoryGateway;
use Gibbon\Contracts\Filesystem\FileHandler;

require_once '../../gibbon.php';

Expand Down Expand Up @@ -85,6 +86,7 @@
}

// Move attached file, if there is one
$fileMetaData = null;
if (!empty($_FILES['backgroundImageFile']['tmp_name'])) {
$fileUploader = new Gibbon\FileUploader($pdo, $session);
$fileUploader->getFileExtensions('Graphics/Design');
Expand All @@ -93,18 +95,37 @@

// Upload the file, return the /uploads relative path
$data['backgroundImage'] = $fileUploader->uploadFromPost($file, $data['name']);

if (empty($data['backgroundImage'])) {
$partialFail = true;
} else {
$fileMetaData = $fileUploader->getFileMetaData($data['backgroundImage']);
}

} else {
// $data['backgroundImage'] = $_POST['backgroundImage'] ?? '';
}

// Get the old record to check for file deletion
$oldRecord = $categoryGateway->getByID($gibbonActivityCategoryID);

// Update the record
$updated = $categoryGateway->update($gibbonActivityCategoryID, $data);

// Record file tracking
if (!empty($fileMetaData)) {
$gibbonFileID = $container->get(FileHandler::class)->recordFileUpload($fileMetaData, 'gibbonActivityCategory', $gibbonActivityCategoryID, 'backgroundImage');

if (empty($gibbonFileID)) {
$partialFail = true;
}
}

// Handle file deletion when user removes attachment
if (empty($data['backgroundImage']) && !empty($oldRecord['backgroundImage'])) {
$deleted = $container->get(FileHandler::class)->deleteFile('gibbonActivityCategory', $gibbonActivityCategoryID, 'backgroundImage');
}

if (!$updated) {
$URL .= "&return=error2";
} else if ($partialFail) {
Expand Down
19 changes: 16 additions & 3 deletions modules/Activities/activities_manage_editProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Gibbon\Domain\Activities\ActivitySlotGateway;
use Gibbon\Domain\Activities\ActivityStaffGateway;
use Gibbon\Domain\Activities\ActivityPhotoGateway;
use Gibbon\Contracts\Filesystem\FileHandler;
use Gibbon\FileUploader;

require_once '../../gibbon.php';
Expand Down Expand Up @@ -178,6 +179,7 @@
'sequenceNumber' => array_search($index, $photoOrder) ?? false,
];

$fileMetaData = null;
if (!empty($_FILES['photos']['tmp_name'][$index]['fileUpload'])) {
$file = [
'name' => $_FILES['photos']['name'][$index]['fileUpload'] ?? '',
Expand All @@ -195,6 +197,8 @@
if (empty($photoData['filePath'])) {
$partialFail = true;
continue;
} else {
$fileMetaData = $fileUploader->getFileMetaData($photoData['filePath']);
}

if ($photoData['sequenceNumber'] === false) {
Expand All @@ -212,17 +216,26 @@
}

$photoIDs[] = str_pad($gibbonActivityPhotoID, 12, '0', STR_PAD_LEFT);

// Record file tracking
if (!empty($fileMetaData) && !empty($gibbonActivityPhotoID)) {
$gibbonFileID = $container->get(FileHandler::class)->recordFileUpload($fileMetaData, 'gibbonActivityPhoto', $gibbonActivityPhotoID, 'filePath');

if (empty($gibbonFileID)) {
$partialFail = true;
}
}
}

// Remove photos that have been deleted from the filesystem
$cleanupPhotos = $activityPhotoGateway->selectPhotosNotInList($gibbonActivityID, $photoIDs)->fetchAll();
foreach ($cleanupPhotos as $photo) {
$activityPhotoGateway->delete($photo['gibbonActivityPhotoID']);

$photoPath = $session->get('absolutePath').'/'.$photo['filePath'];
if (!empty($photo['filePath']) && file_exists($photoPath)) {
unlink($photoPath);
$deleted = $container->get(FileHandler::class)->deleteFile('gibbonActivityPhoto', $photo['gibbonActivityPhotoID'], 'filePath');
}

$activityPhotoGateway->delete($photo['gibbonActivityPhotoID']);
}

//Write to database
Expand Down
5 changes: 5 additions & 0 deletions modules/Admissions/studentEnrolment_manage_addProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@
//Last insert ID
$AI = str_pad($connection2->lastInsertID(), 8, '0', STR_PAD_LEFT);

// Manage custom field file uploads
if (!empty($fields) && !empty($AI)) {
$container->get(CustomFieldHandler::class)->manageCustomFieldFileUploads('Student Enrolment', [], $fields, 'gibbonStudentEnrolment', $AI);
}

// Handle automatic course enrolment if enabled
$autoEnrolStudent = $_POST['autoEnrolStudent'] ?? 'N';
if ($autoEnrolStudent == 'Y') {
Expand Down
16 changes: 16 additions & 0 deletions modules/Admissions/studentEnrolment_manage_editProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@
} else {
$row = $result->fetch();

// Fetch old record for file comparison
try {
$dataOld = ['gibbonStudentEnrolmentID' => $gibbonStudentEnrolmentID];
$sqlOld = 'SELECT fields FROM gibbonStudentEnrolment WHERE gibbonStudentEnrolmentID=:gibbonStudentEnrolmentID';
$resultOld = $connection2->prepare($sqlOld);
$resultOld->execute($dataOld);
$oldEnrolmentRecord = $resultOld->fetch();
} catch (PDOException $e) {
$oldEnrolmentRecord = null;
}

$gibbonYearGroupID = $_POST['gibbonYearGroupID'] ?? '';
$gibbonFormGroupID = $_POST['gibbonFormGroupID'] ?? '';
$gibbonFormGroupIDOriginal = $_POST['gibbonFormGroupIDOriginal'] ?? 'N';
Expand Down Expand Up @@ -122,6 +133,11 @@
exit;
}

// Manage custom field file uploads
if (!empty($fields)) {
$container->get(CustomFieldHandler::class)->manageCustomFieldFileUploads('Student Enrolment', [], $fields, 'gibbonStudentEnrolment', $gibbonStudentEnrolmentID, $oldEnrolmentRecord['fields'] ?? null);
}

$partialFail = false;

// Handle automatic course enrolment if enabled
Expand Down
5 changes: 5 additions & 0 deletions modules/Behaviour/behaviour_manage_addMultiProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@

if (empty($gibbonBehaviourID)) {
$partialFail = true;
} else {
// Record custom field file uploads
if (!empty($fields) ) {
$filesRecorded = $container->get(CustomFieldHandler::class)->manageCustomFieldFileUploads('Behaviour', [], $fields, 'gibbonBehaviour', $gibbonBehaviourID);
}
}

// ALERTS: possible change to Behaviour alert status, recalculate alerts
Expand Down
5 changes: 5 additions & 0 deletions modules/Behaviour/behaviour_manage_addProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
exit();
}

// Record custom field file uploads
if (!empty($fields)) {
$filesRecorded = $container->get(CustomFieldHandler::class)->manageCustomFieldFileUploads('Behaviour', [], $fields, 'gibbonBehaviour', $gibbonBehaviourID);
}

$copyToNotes = $_POST['copyToNotes'] ?? null;
$followUp = $_POST['followUp'] ?? '';

Expand Down
5 changes: 5 additions & 0 deletions modules/Behaviour/behaviour_manage_editProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@
header("Location: {$URL}");
exit();
}

// Manage custom field file uploads and deletions
if (!empty($fields)) {
$filesRecorded = $container->get(CustomFieldHandler::class)->manageCustomFieldFileUploads('Behaviour', [], $fields, 'gibbonBehaviour', $gibbonBehaviourID, $behaviourRecord['fields']);
}
}

// ALERTS: possible change to Behaviour alert status, recalculate alerts
Expand Down
Loading
Loading