- Add POST route for /setting/admin/system-ops/updateDirect
- Add GET route for /setting/admin/system-ops/diagnose
- Both endpoints were implemented but routes were missing
This fixes 'Request failed' error on Deploy from GitHub button
- New 'Deploy from GitHub' button downloads latest code directly
- No git configuration required - more reliable for git-unfriendly servers
- Automatically syncs changed files (skips .git, vendor, writable)
- Both methods available: git pull (if configured) or direct GitHub download
- Each has a clear confirmation dialog explaining the method
- Handles temporary extraction and cleanup automatically
This solves HMS deployment when git is not accessible to PHP process
Enhanced error reporting:
- Show detailed diagnostic information: git version, user config, email, remote, branch
- Check .git directory and config file existence
- Detect if repository has uncommitted changes
- Error categorization: PERMISSION, CONFIG, REPO, NETWORK, SSL, GIT errors
- Actionable error messages with command suggestions
- Report raw error output to log file for debugging
Added setup_git_config.sh script:
- Automated configuration for www-data user
- Creates .ssh directory with proper permissions
- Sets git user.name and user.email globally
- Disables SSL verification (for HTTPS repos)
- Configures git to use HTTPS remote URL
- Fixes directory ownership and permissions
- Tests git status to verify configuration
Usage on live server:
sudo bash setup_git_config.sh
This script handles the common git configuration issues
that prevent 'Update HMS' button from working.
- Added findGitCommand() method to check for git in common locations:
* /usr/bin/git (standard Linux)
* /bin/git (alternative location)
* /usr/local/bin/git (compiled from source)
* Falls back to 'which git' and 'command -v git'
- Uses absolute git path in all shell commands
- Fixes 'Git command not found' error on systems where git is not in PATH
- No dependencies added, uses PHP file_exists() + is_executable() checks
Pre-checks before git pull:
- Verify .git directory exists
- Check if git command is available
- Run git status to detect permission/connectivity issues
Better error messages for common failures:
- Permission denied → 'Git directory may not be writable'
- Authentication failed → 'SSH keys may not be configured for www-data'
- Connection refused → 'GitHub server unreachable'
- fatal errors → Parse and return specific error details
Returns actual error message instead of generic 'Check logs for details'
- Method 1: ping to Google DNS (8.8.8.8)
- Method 2: DNS resolution via nslookup
- Method 3: DNS query using dig
- Method 4: curl HTTP HEAD to google.com
- Method 5: wget --spider
- Method 6: fsockopen to Google DNS (8.8.8.8:53)
- Method 7: curl to Cloudflare DNS (1.1.1.1)
- Method 8: PHP gethostbyname() for DNS resolution
Tries multiple DNS providers (Google, Cloudflare, Quad9)
Falls back to 'Offline' only if all methods fail
Handles firewalls, ICMP blocks, and missing commands
- Method 1: \['SERVER_ADDR'] from Apache/Nginx (most reliable)
- Method 2: /sbin/ip (absolute path, works if ip not in PATH)
- Method 3: Parse /proc/net/route for default gateway interface + IP
- Method 4: hostname -I (space-separated IPs)
- Method 5: ifconfig (fallback for older systems)
- Method 6: Socket connection to 8.8.8.8 (pure PHP, no shell commands)
Each method validates IP and skips loopback (127.x, ::1, ::ffff:127.x)
Fixes 'Unavailable' when shell commands fail or aren't available
- Changed primary method to: ip -4 addr show scope global (gets public/private IPs only)
- Added isLoopbackIp() helper to filter out loopback addresses (127.* and ::1)
- Fallback: hostname -I with loopback filtering
- Last resort: gethostbyname() with loopback check
- On remote server with eth0: 159.89.175.190, will now show public IP instead of 127.0.0.1
Three-level fallback chain:
1. gethostbyname(gethostname()) - PHP built-in, works on Linux and Windows
2. ip -4 addr show scope global | grep inet - Linux shell fallback
3. hostname -I - Linux shell secondary fallback
All results validated with FILTER_VALIDATE_IP before display.
- Added "View HMS Features & Capabilities" link below the login card
- Copied HMS_FEATURES_PRESENTATION.html to public/ so it is accessible
via base_url without auth (same pattern as software-use-license.html)
- Link opens in a new tab
- HMS_FEATURES_PRESENTATION.html: full styled presentation with cover,
professional introduction, 11 feature sections, tech stack, compliance,
print/PDF button, and proper @media print A4 layout
- HMS_FEATURES_PRESENTATION.md: plain Markdown version of the same content
- system_ops.php: fix confirm dialog text for Update HMS button
- Added "Details" column to Update History table
- Shows info icon button when error details are available
- Clicking button opens a modal with full error message
- Details displayed in pre-formatted text for easy reading
- Helps diagnose why HMS updates failed or timed out
When an update fails, users can now click the info icon to see the exact
git error output, making troubleshooting much easier.
Update improvements:
- Renamed button from "Update System" to "Update HMS"
- Changed update to run only 'git pull' (removed database migrations)
- Added 60-second timeout to prevent system hangup
- Better error messages for timeouts and failures
- Logs update status (running/success/failed/timeout) to history
- Confirmation dialog now says "Pull latest HMS code from repository?"
This ensures quick updates without long-running migrations that could hang
the admin interface. Database migrations can be run separately as needed.
Resource Usage improvements:
- Added visual progress bars for CPU, RAM, and Disk usage
- Progress bars use Bootstrap styling (success/info/warning colors)
- Display percentage and detailed metrics (e.g., RAM 4 / 128 MB (3%))
- Bars animate smoothly with CSS transitions
CPU detection enhancements:
- Added fallback to /proc/stat parsing when shell commands unavailable
- Added fallback to PHP getrusage() for CPU time estimation
- CPU now displays even when shell_exec is disabled
- Graceful fallback chain ensures data is always available
Progress bar styling:
- Success (green) for CPU
- Info (blue) for RAM
- Warning (orange/yellow) for Disk
- All bars styled with height, rounded corners, and smooth transitions
When shell_exec() is disabled on the server (common in production), the system
operations panel now gracefully falls back to PHP built-in functions:
- gethostname() for hostname instead of shell 'hostname' command
- php_uname() for OS info instead of shell 'uname -a' command
- /proc/uptime parsing or unavailable status for uptime
- disk_free_space() and disk_total_space() for disk usage
- memory_get_usage() and PHP memory limit for memory usage
- Improved parsePhpMemoryLimit() to handle memory limit parsing
This ensures the admin panel shows meaningful information even in restricted
production environments where shell_exec is disabled for security reasons.
- Added System Operations link to Admin dashboard (app/Views/Setting/Admin/index.php)
- Uses load_form_div to load the system operations page inline
- Added SystemOperations library for server status collection and actions
- Tile uses server icon (bi-server) and appears in the admin panel grid
- Link: javascript:load_form_div(base_url('setting/admin/system-ops'), 'maindiv', 'System Operations')
- Added SystemOps controller with index and panel endpoints for dynamic content refresh
- Created system_ops_panel.php fragment for AJAX-based UI updates (no full page reload)
- Implemented 30-second auto-refresh using AJAX instead of location.reload()
- Fixed health badge contrast by adding explicit dark text color (#1f2937)
- Added jQuery availability checks to prevent script errors on page load
- Included server overview, resource usage, services, events, and update history
- Integrated delegated event handlers for action buttons (Update, Restart, Reboot, Shutdown)
- All buttons are protected with confirmation dialogs
- Layout maintains NiceAdmin card styling and responsive design
Routes added:
- GET /admin/system-ops/panel - returns panel fragment for refresh
- Diagnosis.php: resolve doctor mapping via ABDM Report Doctor Mapping,
compile pathology/diagnosis reports into separate Letter Head and
Plain Paper PDFs, add compiled-pdf-links endpoint
- Routes.php: add diagnosis/compiled-pdf-links route
- pathology_detail.php: render/persist dual compiled PDF buttons
- Setting/Template.php: per-modality Letter Head / Plain Paper template
mapping via hospital_setting keys
- Setting/Template/index.php: fix tile links using load_form (which only
replaces #main) instead of load_form_div, which broke every internal
AJAX reload (template type switch, modality switch, reset) on the
diagnosis/discharge/document print template settings pages
- diagnosis_print_settings.php: fix corrupted watermark_alpha number
input (missing step attribute) that silently blocked form submission
for templates with non-integer-step legacy values
- Patient.php: broaden non-fatal-pending detection in abdm_content_auto_flow() to recognize more bridge error wordings (No HIU sessions found / matching the criteria) and HTTP 400, stopping spurious 'Auto flow failed' toasts.
- Opd_prescription.php: remove dead opd.fhir.generated bridge_sync_queue enqueue in storePrescriptionFhirBundle(). This unprefixed event type routed to the CSNOtk terminology bridge which has no consumer for it, always 404ing. Real ABDM sharing already works via DreamsoftConnector::sharePrescriptionBundle() (abdm.fhir.share.requested).
- Fix groupWorkflowRowsIntoSessions() to correlate workflow rows by stable
request_id/abdm_consent_request_id instead of chronological proximity to
the newest CONSENT_REQUEST row. Background polling reconciles all
historical sessions in one batch, so older sessions' rows previously got
silently merged into the newest session, causing 'Show Data' to display
an unrelated older session's single facility instead of all consented
facilities.
- Skip synthetic orphan sessions (stray rows with no owning CONSENT_REQUEST)
in getAbdmConsentRequestsList()/getAbdmConsentArtifactDetail() so they
don't show as phantom history rows or get picked as 'most recent'.
- Fix abdm_documents() consent_request_id filter to match all known sibling
artifact IDs for a session (via abdm_hiu_consent_artifacts), not just an
exact single artifact id, so all facilities under one consent request
appear together.
- Fix CreateAbdmHiuConsentArtifacts migration: reduce VARCHAR(180) to
VARCHAR(100) on consent_request_id/artifact_id to satisfy MySQL's
1000-byte composite key length limit (was silently failing to migrate).
- Add fetchAllArtifactsAfterGrant() cascade in M3HiuWorkflowService to fetch
every known artifact under a granted consent, used by both the cron poll
and a new abdm_check_live_status() endpoint/button.
- getLatestAbdmSyncSnapshot() session-scoping fix to avoid an older granted
session masking a newer in-progress one.
- Relabel Dr. Joshi Clinic documents (previously mislabeled 'Test Hospital'
from the HIP's own FHIR bundle Organization name).
Abha::verifyOtp() and Abha::verifyCommOtp() were overwriting the
user-typed, OTP-verified mobile number with whatever the ABDM bridge's
verify-otp response echoed back for 'mobile'. Many bridge responses
(especially plain mobile-OTP verification, as opposed to Aadhaar eKYC)
do not echo the mobile at all, so it silently became empty and was
never saved to patient_master.mphone1 during ABHA Register (By ABHA
Number / QR / Facility QR / Mobile OTP) or ABHA Create/Verify.
Fix: fall back to the originally submitted/verified mobile when the
gateway response omits it. Also updated Patient_V.php JS (Verify ABHA
tab, ABHA Register Method 1 and Method 4) to resend the mobile number
along with the verify_comm_otp call so the server has it available.
Address/email are unaffected by this bug: those fields are already
mapped via applyAbhaMetaColumns() when present, but the ABDM mobile-OTP
verification API generally doesn't return KYC demographic data (that
only comes from the Aadhaar-eKYC flow) - so they may legitimately
stay blank for phone-based registration methods.
HMS instances behind NAT with no live public IP can hit an expired/unreachable
TLS cert on their own base_url() when doing the internal handoff self-call to
AbdmGateway::share_prescription_bundle, causing 'Gateway handoff failed:
curl error 60: Peer's Certificate has expired'. This call never leaves the
local server, so skip peer verification by default via new
fhirGatewayHandoffSslVerify() helper. Set FHIR_HANDOFF_SSL_VERIFY=true in .env
to re-enable strict verification on deployments with a valid public cert.
Does not affect the actual outbound ABDM bridge submission (EAtriaBridgeConnector),
which keeps its own independent SSL verification/toggle.