enable/disable license
This commit is contained in:
parent
cc2f923ac2
commit
7c8899df47
3
db/migrations/20260219_add_license_fields.sql
Normal file
3
db/migrations/20260219_add_license_fields.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- SQL for the License Manager Database (u128023052_meezan_license)
|
||||
ALTER TABLE licenses ADD COLUMN owner VARCHAR(255) DEFAULT NULL;
|
||||
ALTER TABLE licenses ADD COLUMN address TEXT DEFAULT NULL;
|
||||
150
index.php
150
index.php
@ -1088,6 +1088,37 @@ if (isset($_POST['add_hr_department'])) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['update_license'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
$status = $_POST['status'] ?? null;
|
||||
$owner = $_POST['owner'] ?? null;
|
||||
$address = $_POST['address'] ?? null;
|
||||
|
||||
$updateData = [];
|
||||
if ($status !== null) $updateData['status'] = $status;
|
||||
if ($owner !== null) $updateData['owner'] = $owner;
|
||||
if ($address !== null) $updateData['address'] = $address;
|
||||
|
||||
$res = LicenseService::updateLicense($id, $updateData);
|
||||
if ($res['success']) {
|
||||
$message = "License updated successfully!";
|
||||
} else {
|
||||
$message = "Error: " . ($res['error'] ?? 'Unknown error');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['issue_license'])) {
|
||||
$max = (int)($_POST['max_activations'] ?? 1);
|
||||
$owner = $_POST['owner'] ?? null;
|
||||
$address = $_POST['address'] ?? null;
|
||||
$res = LicenseService::issueLicense($max, 'FLAT', $owner, $address);
|
||||
if ($res['success']) {
|
||||
$message = "New License Issued: " . $res['license_key'];
|
||||
} else {
|
||||
$message = "Error: " . ($res['error'] ?? 'Unknown error');
|
||||
}
|
||||
}
|
||||
if (isset($_POST['pay_payroll'])) {
|
||||
$id = (int)$_POST['id'];
|
||||
if ($id) {
|
||||
@ -7168,6 +7199,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<p class="text-muted small mb-0" data-en="View and search license keys activated on your system" data-ar="عرض والبحث في مفاتيح التراخيص المفعلة في نظامك">View and search license keys activated on your system</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button class="btn btn-primary btn-sm rounded-pill px-3" data-bs-toggle="modal" data-bs-target="#issueLicenseModal">
|
||||
<i class="bi bi-plus-circle"></i> <span data-en="Issue License" data-ar="إصدار ترخيص">Issue License</span>
|
||||
</button>
|
||||
<button onclick="location.reload()" class="btn btn-light btn-sm rounded-pill px-3">
|
||||
<i class="bi bi-arrow-clockwise"></i> <span data-en="Refresh" data-ar="تحديث">Refresh</span>
|
||||
</button>
|
||||
@ -7187,16 +7221,17 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<tr>
|
||||
<th data-en="ID" data-ar="المعرف">ID</th>
|
||||
<th data-en="License Key" data-ar="مفتاح الترخيص">License Key</th>
|
||||
<th data-en="Max Activations" data-ar="أقصى تفعيل">Max</th>
|
||||
<th data-en="Current Activations" data-ar="التفعيلات الحالية">Used</th>
|
||||
<th data-en="Owner" data-ar="المالك">Owner</th>
|
||||
<th data-en="Max/Used" data-ar="الأقصى/المستخدم">Max/Used</th>
|
||||
<th data-en="Status" data-ar="الحالة">Status</th>
|
||||
<th data-en="Created At" data-ar="تاريخ الإنشاء">Created At</th>
|
||||
<th data-en="Actions" data-ar="الإجراءات" class="text-end pe-4">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($data['licenses'])): ?>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center py-5 text-muted">
|
||||
<td colspan="7" class="text-center py-5 text-muted">
|
||||
<i class="bi bi-key fs-1 d-block mb-3 opacity-25"></i>
|
||||
<span data-en="No license data found on the server." data-ar="لم يتم العثور على بيانات ترخيص على السيرفر.">No license data found on the server.</span>
|
||||
</td>
|
||||
@ -7206,8 +7241,15 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<tr>
|
||||
<td><span class="badge bg-light text-dark border">#<?= $l['id'] ?></span></td>
|
||||
<td><code class="fw-bold text-primary"><?= htmlspecialchars($l['license_key']) ?></code></td>
|
||||
<td><span class="badge bg-secondary"><?= (int)$l['max_activations'] ?></span></td>
|
||||
<td><span class="badge bg-<?= $l['activations_count'] >= $l['max_activations'] ? 'danger' : 'info' ?>"><?= (int)$l['activations_count'] ?></span></td>
|
||||
<td>
|
||||
<div class="fw-bold"><?= htmlspecialchars($l['owner'] ?? 'N/A') ?></div>
|
||||
<div class="small text-muted"><?= htmlspecialchars($l['address'] ?? '') ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-secondary"><?= (int)$l['max_activations'] ?></span>
|
||||
/
|
||||
<span class="badge bg-<?= $l['activations_count'] >= $l['max_activations'] ? 'danger' : 'info' ?>"><?= (int)$l['activations_count'] ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($l['is_active']): ?>
|
||||
<span class="badge bg-success-subtle text-success border border-success-subtle rounded-pill">Active</span>
|
||||
@ -7216,6 +7258,21 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="small text-muted"><?= htmlspecialchars($l['created_at']) ?></td>
|
||||
<td class="text-end pe-4">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-outline-primary"
|
||||
onclick='editLicense(<?= json_encode($l) ?>)'
|
||||
title="Edit"><i class="bi bi-pencil"></i></button>
|
||||
<form method="POST" class="d-inline ms-1">
|
||||
<input type="hidden" name="id" value="<?= $l['id'] ?>">
|
||||
<input type="hidden" name="status" value="<?= $l['is_active'] ? 'suspended' : 'active' ?>">
|
||||
<button type="submit" name="update_license" class="btn btn-sm btn-outline-<?= $l['is_active'] ? 'warning' : 'success' ?>"
|
||||
title="<?= $l['is_active'] ? 'Disable' : 'Enable' ?>">
|
||||
<i class="bi bi-power"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
@ -7225,6 +7282,89 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Issue License Modal -->
|
||||
<div class="modal fade" id="issueLicenseModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Issue New License</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Owner Name</label>
|
||||
<input type="text" name="owner" class="form-control" placeholder="e.g. Acme Corp" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Address / Contact</label>
|
||||
<textarea name="address" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Max Activations</label>
|
||||
<input type="number" name="max_activations" class="form-control" value="1" min="1" max="100">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" name="issue_license" class="btn btn-primary">Generate Key</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit License Modal -->
|
||||
<div class="modal fade" id="editLicenseModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Edit License</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="id" id="edit_license_id">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Owner Name</label>
|
||||
<input type="text" name="owner" id="edit_license_owner" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Address / Contact</label>
|
||||
<textarea name="address" id="edit_license_address" class="form-control" rows="2"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Status</label>
|
||||
<select name="status" id="edit_license_status" class="form-select">
|
||||
<option value="active">Active</option>
|
||||
<option value="suspended">Suspended</option>
|
||||
<option value="expired">Expired</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" name="update_license" class="btn btn-primary">Save Changes</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function editLicense(license) {
|
||||
document.getElementById('edit_license_id').value = license.id;
|
||||
document.getElementById('edit_license_owner').value = license.owner || '';
|
||||
document.getElementById('edit_license_address').value = license.address || '';
|
||||
document.getElementById('edit_license_status').value = license.status;
|
||||
var editModal = new bootstrap.Modal(document.getElementById('editLicenseModal'));
|
||||
editModal.show();
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
#licensesTable td { padding: 1rem 0.75rem; }
|
||||
</style>
|
||||
|
||||
<?php elseif ($page === 'users'): ?>
|
||||
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
|
||||
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center border-0">
|
||||
|
||||
@ -144,6 +144,27 @@ class LicenseService {
|
||||
return self::callRemoteApi('/list', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing license.
|
||||
*/
|
||||
public static function updateLicense($id, $data) {
|
||||
$params = array_merge(['id' => $id, 'secret' => '1485-5215-2578'], $data);
|
||||
return self::callRemoteApi('/update', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a new license.
|
||||
*/
|
||||
public static function issueLicense($max_activations, $prefix = 'FLAT', $owner = null, $address = null) {
|
||||
return self::callRemoteApi('/issue', [
|
||||
'secret' => '1485-5215-2578',
|
||||
'max_activations' => $max_activations,
|
||||
'prefix' => $prefix,
|
||||
'owner' => $owner,
|
||||
'address' => $address
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote API Caller
|
||||
*/
|
||||
|
||||
@ -18,6 +18,7 @@ if (strpos($request_uri, '/verify') !== false) $endpoint = 'verify';
|
||||
if (strpos($request_uri, '/deactivate') !== false) $endpoint = 'deactivate';
|
||||
if (strpos($request_uri, '/issue') !== false) $endpoint = 'issue';
|
||||
if (strpos($request_uri, '/list') !== false) $endpoint = 'list';
|
||||
if (strpos($request_uri, '/update') !== false) $endpoint = 'update';
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
@ -154,19 +155,23 @@ if ($endpoint === 'issue') {
|
||||
|
||||
$max_activations = (int)($input['max_activations'] ?? 1);
|
||||
$prefix = strtoupper(trim($input['prefix'] ?? 'FLAT'));
|
||||
$owner = $input['owner'] ?? null;
|
||||
$address = $input['address'] ?? null;
|
||||
|
||||
// Generate a formatted key: PREFIX-XXXX-XXXX
|
||||
$key = $prefix . '-' . bin2hex(random_bytes(2)) . '-' . bin2hex(random_bytes(2));
|
||||
$key = strtoupper($key);
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("INSERT INTO licenses (license_key, max_activations) VALUES (?, ?)");
|
||||
$stmt->execute([$key, $max_activations]);
|
||||
$stmt = $pdo->prepare("INSERT INTO licenses (license_key, max_activations, owner, address) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$key, $max_activations, $owner, $address]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'license_key' => $key,
|
||||
'max_activations' => $max_activations
|
||||
'max_activations' => $max_activations,
|
||||
'owner' => $owner,
|
||||
'address' => $address
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => 'Failed to generate license.']);
|
||||
@ -198,4 +203,45 @@ if ($endpoint === 'list') {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($endpoint === 'update') {
|
||||
$secret = $input['secret'] ?? '';
|
||||
if ($secret !== SERVER_SECRET) {
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = (int)($input['id'] ?? 0);
|
||||
$status = $input['status'] ?? null;
|
||||
$owner = $input['owner'] ?? null;
|
||||
$address = $input['address'] ?? null;
|
||||
|
||||
if (!$id) {
|
||||
echo json_encode(['success' => false, 'error' => 'ID is required.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$fields = [];
|
||||
$params = [];
|
||||
if ($status !== null) { $fields[] = "status = ?"; $params[] = $status; }
|
||||
if ($owner !== null) { $fields[] = "owner = ?"; $params[] = $owner; }
|
||||
if ($address !== null) { $fields[] = "address = ?"; $params[] = $address; }
|
||||
|
||||
if (empty($fields)) {
|
||||
echo json_encode(['success' => false, 'error' => 'No fields to update.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$params[] = $id;
|
||||
$sql = "UPDATE licenses SET " . implode(', ', $fields) . " WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => 'Update failed: ' . $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['success' => false, 'error' => 'Invalid endpoint.']);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user